[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",