Repository navigation
Python: [Bug]: DevUI bearer-token authentication returns 500 for non-ASCII tokens #9713
Description
Observed Behavior
DevUI bearer-token authentication can return HTTP 500 when the presented bearer token or the configured DEVUI_AUTH_TOKEN contains non-ASCII characters.
The authentication middleware uses secrets.compare_digest() with string values. When either value contains non-ASCII characters, compare_digest() raises a TypeError instead of returning a comparison result.
As a result:
- A request containing a non-ASCII value in the
Authorization: Bearer ...header results in HTTP 500 instead of HTTP 401 Unauthorized. - If
DEVUI_AUTH_TOKENitself contains non-ASCII characters, a request containing the correct token also results in HTTP 500, making that configured token unusable.
The failure is therefore a correctness/robustness issue in the authentication middleware. I did not observe an authentication bypass; the failure is effectively fail-closed.
Expected Behavior
Invalid or malformed bearer tokens should be rejected with HTTP 401 Unauthorized rather than causing an internal server error.
A valid DEVUI_AUTH_TOKEN containing non-ASCII characters should also be accepted when the client supplies the corresponding token.
Authentication input should not cause the middleware to raise an uncaught TypeError.
Steps to Reproduce
- Start a DevUI server with bearer-token authentication enabled.
- Set
DEVUI_AUTH_TOKENto an ASCII token and make a request with an ASCII bearer token. The request behaves normally. - Make another request with an
Authorizationheader containing a non-ASCII byte in the bearer token. - Observe that the request returns HTTP 500 instead of HTTP 401.
- Alternatively, configure
DEVUI_AUTH_TOKENwith a non-ASCII character, for examplesécret. - Send a request using
Authorization: Bearer sécret. - Observe that authentication raises an internal error and the request returns HTTP 500 instead of authenticating successfully.
Minimal Reproduction
The issue is reproducible against the DevUI implementation in:
python/packages/devui/agent_framework_devui/_server.py
The bearer-token authentication middleware compares the presented token with the configured token using secrets.compare_digest().
A minimal configuration is:
DEVUI_AUTH_TOKEN=sécret
Then send a request with:
Authorization: Bearer sécretThe authentication middleware raises a TypeError from secrets.compare_digest() rather than successfully comparing the values.
The same behavior can be reproduced with a non-ASCII byte in the presented Authorization header while the configured token remains ASCII.
I also reproduced this against the actual DevUI application rather than only testing the comparison function in isolation.
Error Messages and Stack Traces
TypeError: comparing strings with non-ASCII characters is not supported
This originates from the use of `secrets.compare_digest()` with `str` values containing non-ASCII characters.
The resulting exception is not handled by the authentication middleware, causing the request to return HTTP 500.
No credentials or authorization values are included in the reported traceback.
Package Versions
Agent Framework Core version: 1.23.0
Python Version
Python 3.13.15
Operating System
Windows
Regression
Unknown
Additional Context
I reproduced the behavior with the following cases:
Case | Result -- | -- Wrong ASCII token | 401 Correct ASCII token | 200 Non-ASCII value in presented token | 500 Correct non-ASCII configured token | 500The likely cause is that secrets.compare_digest() is being called with str values. Python's secrets.compare_digest() does not support non-ASCII characters when comparing strings and raises TypeError.
I have prepared a small local patch that performs the comparison using byte representations and added regression tests covering both affected cases.
The patch is intentionally limited to the DevUI authentication path.
I also noticed the same general hmac.compare_digest() pattern in two hosting samples:
samples/04-hosting/af-hosting/local_telegram/app.pysamples/04-hosting/foundry-hosted-agents/invocations/telegram/main.py
Those are samples rather than the shipped DevUI package, so I have not included them in this issue's primary scope.
Acknowledgements
- I searched existing issues and did not find a duplicate.
- I personally verified this behavior and the reproduction details are authentic.
- I will wait for explicit maintainer agreement before starting implementation of a non-trivial change.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
lisry-1 commentedon Oct 26, 2026
Reproduced and opened #9714 with a fix.
auth_middlewarecallssecrets.compare_digest(token, expected_token)on twostrvalues.compare_digestonly accepts ASCIIstrand raisesTypeErrorfor anything else, so:DEVUI_AUTH_TOKENnever matches, because the comparison raises before it can succeed.The fix adds
DevServer._token_matches(), which compares bytes instead ofstr. Bytes comparison has no ASCII restriction. The presented value is re-encoded with latin-1 (headers travel as bytes and Starlette hands them back decoded as latin-1, so this recovers the exact wire bytes), and the configured token is encoded as UTF-8 since it is text. ASCII tokens compare bit-for-bit as before.Sending the header as raw bytes against
/v1/entities:Four parametrized test cases cover this. They fail without the fix (
assert 500 == 401,assert 500 == 200).One judgement call worth your input: there is no standard encoding for a non-ASCII bearer token (RFC 6750 restricts
b64tokento ASCII), so I picked wire-bytes/UTF-8, which is what makes the non-ASCIIDEVUI_AUTH_TOKENcase work. If you would rather treat any non-ASCII token as simply invalid, the alternative is atry/except TypeErroraround the existing call — that removes the 500 but leaves such a token unusable.