chore(proxy): fully redact audit values so short secrets cannot leak

The audit reader masked via the default partial-reveal masker, which returns
values of 8 chars or fewer verbatim, so a short secret in an audit snapshot
escaped redaction. Use a no-reveal masker (visible_prefix/suffix=0) on the
audit read path; an audit log is a change record, not a place to read a secret
back from. Add masker- and audit-level regression tests for short values.
This commit is contained in:
user 2026-05-30 21:42:23 +00:00
parent a1900b4ef1
commit 0bdbf8d7bd
No known key found for this signature in database
3 changed files with 28 additions and 1 deletions

View file

@ -23,7 +23,10 @@ from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
router = APIRouter()
_AUDIT_VALUE_MASKER = SensitiveDataMasker()
# Fully redact (no prefix/suffix reveal) so even short secrets in an audit
# snapshot are masked; the audit log is a change record, not a place to read a
# secret back from, so there is no value in revealing any of it.
_AUDIT_VALUE_MASKER = SensitiveDataMasker(visible_prefix=0, visible_suffix=0)
def _redact_audit_log_values(audit_log_dict: Dict[str, Any]) -> Dict[str, Any]:

View file

@ -197,3 +197,15 @@ def test_mask_url_credentials_preserves_ipv6_brackets():
out = mask_url_credentials("redis://:supersecretpw@[::1]:6379")
assert out == "redis://:****@[::1]:6379"
assert "supersecretpw" not in out
def test_fully_redacting_masker_masks_short_secret_values():
"""A masker configured with no visible prefix/suffix (as used on the audit
read path) fully masks even short secrets, which the default partial-reveal
masker would otherwise return verbatim."""
masker = SensitiveDataMasker(visible_prefix=0, visible_suffix=0)
masked = masker.mask_dict({"api_key": "sk12", "password": "x", "port": 6379})
assert masked["api_key"] != "sk12"
assert set(masked["api_key"]) == {"*"}
assert masked["password"] == "*"
assert masked["port"] == 6379

View file

@ -97,6 +97,18 @@ def test_redact_audit_log_values_handles_string_and_non_dict_input():
)
def test_redact_audit_log_values_masks_short_secrets():
"""A short secret in an audit snapshot must still be masked, not returned
verbatim because it falls under the masker's partial-reveal length."""
from litellm_enterprise.proxy.audit_logging_endpoints import (
_redact_audit_log_values,
)
out = _redact_audit_log_values({"updated_values": {"api_key": "sk12"}})
assert out["updated_values"]["api_key"] != "sk12"
assert set(out["updated_values"]["api_key"]) == {"*"}
# --------------------------------------------------------------------------- #
# Pass-through endpoint header masking
# --------------------------------------------------------------------------- #