[Bugfix] Redact api_key in non-default args log (#52523)
Signed-off-by: LuckyStep <67696304+Andy365-365@users.noreply.github.com>
LuckyStep committed
Aug 19, 2026 at 15:52 UTC
9a9aa2b017b468082ca538b6f7a725a60d7f8b47
4 files changed
+61
-1
tests/entrypoints/serve/utils/test_api_utils.py
+37
@@ -1,10 +1,14 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
+from argparse import Namespace
5
+
6
import pytest
7
8
from vllm.entrypoints.openai.engine.protocol import StreamOptions
9
+from vllm.entrypoints.serve.utils import api_utils
10
from vllm.entrypoints.serve.utils.api_utils import (
11
+ _redact_sensitive_args,
12
get_max_tokens,
13
should_include_usage,
14
)
@@ -110,3 +114,36 @@ class TestGetMaxTokens:
114
input_length=150,
115
default_sampling_params={"max_tokens": 2048},
116
)
117
+
118
+
119
+class TestRedactSensitiveArgs:
120
+ API_KEY = "sk-test-secret-12345"
121
+
122
+ def test_redact_replaces_sensitive_values_only(self):
123
+ args = {"api_key": self.API_KEY, "other": "visible"}
124
+ redacted = _redact_sensitive_args(args)
125
+ assert redacted == {"api_key": "***", "other": "visible"}
126
+ # original dict must not be mutated
127
+ assert args == {"api_key": self.API_KEY, "other": "visible"}
128
+
129
+ def test_no_sensitive_fields_returns_original(self):
130
+ args = {"model_tag": "org/model", "other": "visible"}
131
+ assert _redact_sensitive_args(args) is args
132
+
133
+ def test_api_key_not_in_log(self, monkeypatch, caplog):
134
+ non_default = {
135
+ "model_tag": "org/model",
136
+ "default_chat_template_kwargs": {"enable_thinking": False},
137
+ "api_key": self.API_KEY,
138
+ "enable_auto_tool_choice": True,
139
+ "tool_call_parser": "qwen3_coder",
140
+ }
141
+ monkeypatch.setattr(api_utils, "get_non_default_args", lambda args: non_default)
142
+ with caplog.at_level("INFO", logger="vllm.entrypoints.serve.utils.api_utils"):
143
+ api_utils.log_non_default_args(args=Namespace())
144
+ message = caplog.text
145
+ assert self.API_KEY not in message
146
+ assert "'api_key': '***'" in message
147
+ # non-sensitive args are still logged
148
+ assert "org/model" in message
149
+ assert "qwen3_coder" in message
tests/test_envs.py
+6
@@ -37,6 +37,12 @@ def test_nixl_side_channel_host_is_not_compile_factor(
37
assert "VLLM_NIXL_SIDE_CHANNEL_HOST" not in envs.compile_factors()
38
39
40
+def test_api_key_is_not_compile_factor(monkeypatch: pytest.MonkeyPatch):
41
+ monkeypatch.setenv("VLLM_API_KEY", "sk-super-secret")
42
+
43
+ assert "VLLM_API_KEY" not in envs.compile_factors()
44
+
45
+
46
def test_p2p_side_channel_defaults_and_override(monkeypatch: pytest.MonkeyPatch):
47
monkeypatch.delenv("VLLM_P2P_SIDE_CHANNEL_HOST", raising=False)
48
monkeypatch.delenv("VLLM_P2P_SIDE_CHANNEL_PORT", raising=False)
vllm/entrypoints/serve/utils/api_utils.py
+15
-1
@@ -267,9 +267,23 @@ def jsonify_non_default_args(
267
return {key: _jsonify_arg_value(value) for key, value in non_default_args.items()}
268
269
270
+# Fields whose values must never be logged verbatim.
271
+_SENSITIVE_ARG_FIELDS = frozenset({"api_key"})
272
+
273
+
274
+def _redact_sensitive_args(args: dict[str, Any]) -> dict[str, Any]:
275
+ """Return a copy of `args` with sensitive values redacted for logging."""
276
+ if not any(key in _SENSITIVE_ARG_FIELDS for key in args):
277
+ return args
278
+ return {
279
+ key: ("***" if key in _SENSITIVE_ARG_FIELDS else value)
280
+ for key, value in args.items()
281
+ }
282
+
283
+
284
def log_non_default_args(args: Namespace | EngineArgs):
285
non_default_args = get_non_default_args(args)
272
- logger.info("non-default args: %s", non_default_args)
286
+ logger.info("non-default args: %s", _redact_sensitive_args(non_default_args))
287
288
289
def should_include_usage(
vllm/envs.py
+3
@@ -2243,6 +2243,9 @@ def compile_factors() -> dict[str, object]:
2243
"S3_ACCESS_KEY_ID",
2244
"S3_SECRET_ACCESS_KEY",
2245
"S3_ENDPOINT_URL",
2246
+ # Credential; never affects compiled artifacts and must not be
2247
+ # persisted in cache_key_factors.json.
2248
+ "VLLM_API_KEY",
2249
"VLLM_USAGE_STATS_SERVER",
2250
"VLLM_NO_USAGE_STATS",
2251
"VLLM_DO_NOT_TRACK",