Skip to content

fix(core): protect the server auth context from reserved provider-data keys#5589

Open
shaun0927 wants to merge 2 commits intollamastack:mainfrom
shaun0927:fix/provider-data-reserved-auth-key
Open

fix(core): protect the server auth context from reserved provider-data keys#5589
shaun0927 wants to merge 2 commits intollamastack:mainfrom
shaun0927:fix/provider-data-reserved-auth-key

Conversation

@shaun0927
Copy link
Copy Markdown

What does this PR do?

Closes #5588.

This fixes a request-context boundary bug in request_headers.py.

Today, caller-controlled X-LlamaStack-Provider-Data can include the reserved
__authenticated_user key. That key lands in the same dictionary namespace that
the server uses for authenticated user state, so get_authenticated_user() can
return a raw caller-controlled object instead of a validated User. On current
main, that is enough to trigger 500s on storage-backed request paths that
expect current_user.principal / current_user.attributes.

The fix is intentionally narrow:

  1. strip the reserved __authenticated_user key when provider-data enters the
    request context
  2. ignore non-User values in get_authenticated_user() as defense-in-depth
  3. add focused regression tests for both the middleware boundary and a
    storage-backed POST path

I kept the scope small on purpose. A broader policy such as rejecting every
__* key in provider-data may also make sense long-term, but that would need a
separate design discussion because the current test-mode flow uses __test_id.
This PR only fixes the validated auth-context collision.

Test Plan

uv run --python 3.12 pytest \
  tests/unit/server/test_provider_data_reserved_keys.py \
  tests/unit/server/test_test_context_middleware.py \
  tests/unit/core/test_provider_data_context.py \
  tests/unit/utils/test_authorized_sqlstore.py \
  -q

Output:

...................                                                      [100%]
19 passed in 15.99s
uv run --python 3.12 ruff check \
  src/llama_stack/core/request_headers.py \
  tests/unit/server/test_provider_data_reserved_keys.py \
  tests/unit/server/test_test_context_middleware.py \
  tests/unit/core/test_provider_data_context.py

Output:

All checks passed!

…a keys.

Caller-controlled X-LlamaStack-Provider-Data was able to inject
__authenticated_user into the same request-context dictionary used for
server-owned auth state. That let get_authenticated_user() return a raw
dict and could crash storage-backed request paths that expect a real
User.

This change keeps the fix narrow: strip the reserved
__authenticated_user key when provider-data enters the request context,
and ignore non-User values in get_authenticated_user() as
 defense-in-depth. A focused regression test covers both the middleware
boundary and a storage-backed POST path.

Constraint: Keep the fix narrow and compatible with existing __test_id-based test-mode flows
Rejected: Reject every __-prefixed provider-data key globally | risks breaking existing internal test-mode behavior without maintainer sign-off
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: If provider-data and server-owned request context are refactored later, preserve the separation between caller-controlled keys and authenticated user state
Tested: uv run --python 3.12 pytest tests/unit/server/test_provider_data_reserved_keys.py tests/unit/server/test_test_context_middleware.py tests/unit/core/test_provider_data_context.py tests/unit/utils/test_authorized_sqlstore.py -q
Tested: uv run --python 3.12 ruff check src/llama_stack/core/request_headers.py tests/unit/server/test_provider_data_reserved_keys.py tests/unit/server/test_test_context_middleware.py tests/unit/core/test_provider_data_context.py
Not-tested: Full repository mypy run on this branch
Related: llamastack#5588
Signed-off-by: JunghwanNA <70629228+shaun0927@users.noreply.github.com>
@meta-cla
Copy link
Copy Markdown

meta-cla Bot commented Apr 17, 2026

Hi @shaun0927!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Apr 21, 2026
@meta-cla
Copy link
Copy Markdown

meta-cla Bot commented Apr 21, 2026

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@derekhiggins
Copy link
Copy Markdown
Contributor

thanks, fix works for me.

from my understanding, the bug causes 500 responses (when malicious provider-data is sent) but doesn't enable unauthorized access and doesn't crash the server, is that correct?

can the 2 unit tests be merged into an existing file like test_test_context_middleware.py or test_provider_data_context.py? don't think we need a separate file for a single bug.

…st_context_middleware.py

Per review feedback on llamastack#5589, merge the two reserved-key regression tests
into tests/unit/server/test_test_context_middleware.py instead of keeping
them in a separate file. That file already exercises ProviderDataMiddleware
with FastAPI + TestClient, so the new cases fit alongside the existing
__test_id coverage.
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@shaun0927
Copy link
Copy Markdown
Author

Thanks for the review @derekhiggins!

from my understanding, the bug causes 500 responses (when malicious provider-data is sent) but doesn't enable unauthorized access and doesn't crash the server, is that correct?

Yes, that matches what I observed. Concretely:

  • The server doesn't crash — only the individual request fails.
  • The user-visible symptom is a 500 on storage-backed paths, because AuthorizedSqlStore.insert() reaches current_user.principal / current_user.attributes and hits AttributeError: 'dict' object has no attribute 'principal' when get_authenticated_user() returned a caller-controlled dict instead of a validated User.
  • On the authorization side, I didn't find a path where this collision directly grants access. AuthorizedSqlStore only reads principal / attributes off the returned object, and on current main that access raises before any policy check succeeds, so the malicious payload fails closed rather than granting access. The concern was more that downstream code could start trusting those fields if we didn't draw the boundary. The defense-in-depth change in get_authenticated_user() (ignore non-User values) is what keeps that boundary consistent even if future callers are less careful.

can the 2 unit tests be merged into an existing file like test_test_context_middleware.py or test_provider_data_context.py?

Done — consolidated into tests/unit/server/test_test_context_middleware.py in 42f1435. That file already uses ProviderDataMiddleware + FastAPI + TestClient, so the new cases sit alongside the existing __test_id coverage. test_provider_data_reserved_keys.py is deleted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: reserved __authenticated_user key in provider data can corrupt auth context and trigger 500s

2 participants