litellm/tests/test_litellm/proxy/auth
yucheng-berri b4f5b6aa94
fix(logging): redact credential query params from the uvicorn access log (#39293)
* fix(logging): redact credential query params from the uvicorn access log

Raw virtual keys reached container stdout two ways:

- `GET /key/info?key=sk-...`, `/global/spend/report?api_key=sk-...`,
  `/key/spend/report`, `/spend/logs`, `/user/daily/activity` and the Gemini
  passthrough routes all put the credential in the request target, and
  `uvicorn.access` had no redaction filter (only `uvicorn.error` did).
- the key budget error interpolates `LiteLLM_VerificationToken.key_name`,
  a column with no enforced shape, into a message that is both logged and
  returned to the caller.

`SecretRedactionFilter` cannot be reused on an access logger: it collapses the
record into `record.msg` and clears `record.args`, and uvicorn's AccessFormatter
unpacks those args at emit time, so every access line would raise TypeError.
`AccessLogRedactionFilter` scrubs the positional args in place instead.

An access line is the one input to the secret regex an unauthenticated caller
controls end to end, so two bounds go with it. The request target is cut back to
a whole query parameter under 512 characters before it is scanned, since a half
parameter is too short to match its own pattern and would be logged raw, and the
dropped tail is not logged at all. The connection-string pattern is bounded too,
because its user half could previously re-scan the rest of the string from every
`://`: a 16 KB URL of `a://` pairs took 314s and now takes 0.12s, with the caps
set high enough that an RDS IAM auth token used as a DSN password still redacts.

Credential query params are terminated by `&` like the existing `key=` and
`sig=` patterns, so redacting one param no longer swallows the rest of the
request line, and a second credential in the same query string is now redacted
on its own instead of surviving once the first one stops the span. `key_name` is
echoed into the budget error only when it still has the masked `sk-...abcd`
shape `abbreviate_api_key` writes, so a value put there by a direct DB write or
a migration falls back to the key alias.

Also point the `/key/info` and spend-report examples at the sha256 hash both
endpoints already accept, so callers stop putting raw keys in URLs that
third-party access logs record.

Resolves LIT-5909

* test(logging): assert on emitted access lines instead of filter registration

The two registration tests checked that an AccessLogRedactionFilter instance
sits in uvicorn.access.filters, which is the shape of the code rather than its
behavior. Handing the logger a real access record and reading what a handler
wrote covers the same wiring and still fails when the registration is removed.

* fix(logging): redact percent-encoded credentials from access logs

?k%65y=sk%2D... is a working credential once the request parser decodes it,
but the redaction patterns match literal text and never see it. Decode the
request target as a detector and drop the query when decoding reveals a
secret. The decoded text is never logged back, so a %0A cannot forge a
following log line

Also accept any four non-space characters in the masked key_name check, since
abbreviate_api_key copies the last four characters of a custom key verbatim
and those can be punctuation or non-ASCII

* fix(auth): keep control codes out of the masked key label

/key/generate accepts a custom key ending in an escape sequence, and
abbreviate_api_key copies those four characters into key_name verbatim, so
the over-budget message carried them to a terminal and a log viewer. Bar
whitespace and C0/C1 control codes from the four, and keep everything else
2026-09-02 15:10:36 -07:00
..
test_admin_viewer_handler_access.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_auth_checks.py fix(logging): redact credential query params from the uvicorn access log (#39293) 2026-09-02 15:10:36 -07:00
test_auth_exception_handler.py fix(proxy): word database 503s by whether the fault is transient (#39256) 2026-09-02 15:05:55 -07:00
test_auth_hot_path_network_requests.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_auth_utils.py feat(auth): enforce configurable password policy and SSO-only login (#39381) 2026-09-02 14:28:13 -07:00
test_banned_params_extra_body.py fix(proxy): ban caller-supplied aws identity selectors in request bodies 2026-08-10 22:05:49 -07:00
test_cli_auth.py test: assert the poll call shape after the timeout refactor 2026-08-25 11:00:29 -07:00
test_custom_auth_end_user_budget.py fix(proxy): registry caches stop per-request tag and end-user Postgres reads in auth (#36801) 2026-08-17 18:52:13 +00:00
test_fallback_model_access.py feat(proxy): gate fallback model access enforcement behind enforce_fallback_model_access 2026-08-27 15:45:10 -07:00
test_handle_jwt.py test: require a match= on broad pytest.raises, and drop duplicate parametrize cases (#37769) 2026-08-20 20:24:49 -07:00
test_info_routes.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_litellm_license.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_login_utils.py feat(auth): enforce configurable password policy and SSO-only login (#39381) 2026-09-02 14:28:13 -07:00
test_mcp_ip_filtering.py feat(mcp): add mcp_xff_num_trusted_hops to harden X-Forwarded-For client IP resolution (#31257) 2026-06-25 07:31:29 -07:00
test_model_access_group_budgets.py fix(budgets): make the model access group ceiling exclusive 2026-08-29 15:20:10 -07:00
test_model_checks.py test: enforce F811 so a duplicate definition cannot silently replace the first 2026-08-21 12:06:19 -07:00
test_model_checks_fallbacks.py perf: build log messages lazily so filtered-out log records cost nothing (#35703) 2026-08-04 04:34:52 +00:00
test_multi_budget_windows.py fix(proxy): enforce budgets against authoritative DB spend when the cross-pod counter is unreliable (#30684) 2026-06-18 10:35:41 -07:00
test_network.py feat(auth): resolve caller identity once into a Principal at the auth seam (#30887) 2026-06-20 18:49:41 -07:00
test_oauth2_proxy_hook.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_object_permission_loading.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_onboarding.py feat(auth): enforce configurable password policy and SSO-only login (#39381) 2026-09-02 14:28:13 -07:00
test_organization_budget_enforcement.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_password_hashing.py chore: fixes 2026-03-30 18:36:58 -07:00
test_password_policy.py feat(auth): enforce configurable password policy and SSO-only login (#39381) 2026-09-02 14:28:13 -07:00
test_resolvers_exceptions.py feat(auth): resolve caller identity once into a Principal at the auth seam (#30887) 2026-06-20 18:49:41 -07:00
test_resolvers_models.py feat(auth): resolve caller identity once into a Principal at the auth seam (#30887) 2026-06-20 18:49:41 -07:00
test_resolvers_seam.py feat(auth): resolve caller identity once into a Principal at the auth seam (#30887) 2026-06-20 18:49:41 -07:00
test_resolvers_store.py feat(auth): resolve caller identity once into a Principal at the auth seam (#30887) 2026-06-20 18:49:41 -07:00
test_route_checks.py fix(proxy): let llm_api virtual keys read /model_group/info 2026-08-28 14:42:22 +00:00
test_router_override_fallback_auth.py chore(proxy): clean up request parameter validation and provider destination handling (#34189) 2026-07-22 00:57:58 +00:00
test_team_member_budget.py Fix team member budget enforcement without user row (#27273) 2026-05-06 11:42:29 -07:00
test_unmapped_model_budget_enforcement.py fix(router): never price a strategy-router alias (#36691) 2026-08-12 14:26:30 -07:00
test_user_api_key_auth.py fix(auth): skip guaranteed-miss team lookup for the litellm-dashboard sentinel (#38471) 2026-08-27 12:48:11 -07:00