Skip to content

fix(router): separate runtime and backend credentials - #5396

Open
m199369309 wants to merge 2 commits into
xorbitsai:mainfrom
m199369309:fix/router-runtime-backend-credentials
Open

fix(router): separate runtime and backend credentials#5396
m199369309 wants to merge 2 commits into
xorbitsai:mainfrom
m199369309:fix/router-runtime-backend-credentials

Conversation

@m199369309

Copy link
Copy Markdown
Collaborator

Summary

  • keep Supervisor-to-Runtime authentication separate from the external user credential
  • forward the external credential through a dedicated internal header for backend authentication
  • let the Runtime prefer backend_api_key and never forward the internal header upstream
  • add coverage for forged headers and credential precedence

Dependency

Validation

  • pytest -q xinference/router/tests/test_app.py xinference/api/tests/test_token_router_dispatch.py
  • pre-commit run --files xinference/router/constants.py xinference/router/backend.py xinference/router/tests/test_app.py xinference/api/restful_api.py xinference/api/tests/test_token_router_dispatch.py

@XprobeBot XprobeBot added the bug Something isn't working label Aug 20, 2026
@XprobeBot XprobeBot added this to the v3.x milestone Aug 20, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request separates internal and external credentials in the token router by introducing a custom x-xinference-backend-authorization header to forward external credentials when an internal token is configured. It also updates the backend router to promote this header and adds corresponding unit tests. However, a security review identified a potential leak where the secret internal token could be forwarded to the backend if no external authorization or backend API key is provided. A code suggestion has been provided to prevent this leak.

Comment on lines 26 to +38
headers: dict[str, str] = {}
backend_authorization = ""
for key_bytes, value_bytes in incoming:
key = key_bytes.decode("latin-1").lower()
if key in FORWARDED_REQUEST_HEADERS:
headers[key] = value_bytes.decode("latin-1")
value = value_bytes.decode("latin-1")
if key == TOKEN_ROUTER_BACKEND_AUTHORIZATION_HEADER:
backend_authorization = value
elif key in FORWARDED_REQUEST_HEADERS:
headers[key] = value
if backend_api_key:
headers["authorization"] = f"Bearer {backend_api_key}"
elif backend_authorization:
headers["authorization"] = backend_authorization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

If internal_token is configured, the incoming Authorization header to the Runtime is the internal token. If the external user did not provide an authorization header (meaning backend_authorization is empty) and backend_api_key is also empty, the current implementation will forward the internal token to the backend because "authorization" is in FORWARDED_REQUEST_HEADERS. This leaks the secret internal token to the backend.

To prevent this, we should check if the incoming Authorization header matches the configured internal token, and if so, avoid forwarding it.

    import os

    headers: dict[str, str] = {}
    backend_authorization = ""
    internal_token = os.getenv("XINFERENCE_TOKEN_ROUTER_DATA_PLANE_TOKEN") or os.getenv(
        "XINFERENCE_TOKEN_ROUTER_INTERNAL_TOKEN"
    )
    for key_bytes, value_bytes in incoming:
        key = key_bytes.decode("latin-1").lower()
        value = value_bytes.decode("latin-1")
        if key == TOKEN_ROUTER_BACKEND_AUTHORIZATION_HEADER:
            backend_authorization = value
        elif key in FORWARDED_REQUEST_HEADERS:
            if key == "authorization" and internal_token and value == f"Bearer {internal_token}":
                continue
            headers[key] = value
    if backend_api_key:
        headers["authorization"] = f"Bearer {backend_api_key}"
    elif backend_authorization:
        headers["authorization"] = backend_authorization

@m199369309

Copy link
Copy Markdown
Collaborator Author

Fixed in commit 85515151.

  • request_headers() now detects the configured XINFERENCE_TOKEN_ROUTER_DATA_PLANE_TOKEN / XINFERENCE_TOKEN_ROUTER_INTERNAL_TOKEN.
  • A matching Bearer <internal-token> Authorization header is removed before forwarding to the backend.
  • Backend API keys and the dedicated external authorization header retain their existing precedence.
  • Added regression coverage for both internal-token environment variable names.

Validation: 31 passed for xinference/router/tests/test_app.py and xinference/api/tests/test_token_router_dispatch.py; pre-commit passed for the changed files.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants