mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
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:
parent
a1900b4ef1
commit
0bdbf8d7bd
3 changed files with 28 additions and 1 deletions
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue