Skip to content

fix(security): reject non-ASCII auth/signature input with 401 instead of crashing (all compare_digest sites) - #65697

Merged
teknium1 merged 4 commits into
mainfrom
salvage/65305-65307-nonascii-hmac
Jul 16, 2026
Merged

fix(security): reject non-ASCII auth/signature input with 401 instead of crashing (all compare_digest sites)#65697
teknium1 merged 4 commits into
mainfrom
salvage/65305-65307-nonascii-hmac

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

A non-ASCII byte in any attacker-controlled auth/signature input now yields a clean 401/403/False instead of crashing the handler with a 500 — across the API server, the webhook adapter, and every sibling compare_digest call site that feeds it raw request input.

Salvages #65305 and #65307 by @Drexuxux (3 commits cherry-picked, authorship preserved). Root cause: hmac.compare_digest (and secrets.compare_digest) raise TypeError when given a str containing non-ASCII characters. Bearer tokens, signature headers, verify tokens, and clientState values are raw client input — several of these sit on public, unauthenticated endpoints.

Changes

  • gateway/platforms/api_server.py: bearer-token check compares as bytes (@Drexuxux)
  • gateway/platforms/webhook.py: _hmac_str_equal() helper; all 5 signature branches (GitHub, GitLab, generic V1/V2, Svix) routed through it (@Drexuxux)
  • Sibling-site widening (ours, same bug class — never merge incomplete fixes):
    • gateway/platforms/msgraph_webhook.py: clientState from request body
    • gateway/platforms/whatsapp_cloud.py: hub.verify_token query param + X-Hub-Signature-256 (the old comment claimed compare_digest "works on str" — not for non-ASCII)
    • plugins/platforms/{feishu,raft,line,sms}: verification tokens + signature headers
    • tools/code_execution_tool.py: sandbox RPC token (both server loops)
  • Tests: non-ASCII reject + positive-path (non-ASCII secrets still self-match) for api_server, webhook (incl. Svix v1), msgraph, whatsapp_cloud

Validation

Before After
Bearer ské-… to API server TypeError → 500 401
Non-ASCII webhook signature header TypeError out of unauthenticated endpoint False → clean reject
Non-ASCII msgraph clientState / WhatsApp verify token TypeError 403
Legit non-ASCII configured secrets worked still match byte-for-byte
Targeted suites (api_server, webhook, msgraph, whatsapp_cloud, raft, code_execution) 574/574 pass
E2E: all 9 sites called with hostile ské- input via real imports rejected cleanly, no raise

Infographic

timing-safe-bytes

Drexuxux and others added 4 commits July 16, 2026 06:36
…crashing

_check_auth gates every OpenAI-compatible API server endpoint. It compared
the client's raw bearer token against the configured key with
hmac.compare_digest on two str values. compare_digest raises TypeError on
a str containing non-ASCII characters, and the token comes straight from
the Authorization header — so a request with a single non-ASCII byte in
the key (a stray unicode char, a smart quote, a pasted BOM) crashed the
handler with an unhandled TypeError. Every endpoint calls _check_auth
without a try/except, so the framework turned that into a 500 Internal
Server Error instead of the intended 401 Invalid API key.

Compare as bytes, matching web_server.py's dashboard-token check
(hmac.compare_digest(auth.encode(), expected.encode())). Encoding both
sides keeps the timing-safe comparison and its semantics identical for
valid keys while making a non-ASCII token fail closed with a clean 401.

Adds regression tests: a non-ASCII bearer token returns 401 (no raise),
and a non-ASCII configured key still authenticates against its exact
value.
… the endpoint

_validate_signature backs the public webhook receiver. It compared each
attacker-supplied signature/token header (GitHub X-Hub-Signature-256,
GitLab X-Gitlab-Token, generic X-Webhook-Signature / -V2, and the Svix v1
header) against a computed hex/base64 digest with hmac.compare_digest on
two str values. compare_digest raises TypeError on a str containing
non-ASCII characters, and the header is raw client input on an
unauthenticated endpoint — so any internet client could POST a single
non-ASCII byte in the signature header and raise out of the handler,
returning a 500 instead of a clean 401. Fail-closed, but an on-demand
crash of the request path.

Route all five comparisons through a small _hmac_str_equal() helper that
encodes both sides to UTF-8 bytes before the constant-time compare
(compare_digest has no ASCII restriction on bytes). Semantics are
unchanged for valid signatures; a hostile non-ASCII header now fails
closed with a rejection instead of raising.

Adds regression tests: non-ASCII GitHub/GitLab/generic/V2 signature
headers return False (no raise), and a non-ASCII configured secret still
matches its exact token value.

Also maps drexux0@gmail.com in scripts/release.py AUTHOR_MAP.
…gression

The fix routes the Svix v1 comparison through _hmac_str_equal too, but the
existing non-ASCII tests only exercised the GitHub/GitLab/generic V1/V2
branches. Add a Svix case (valid svix-id + fresh svix-timestamp so it
reaches the v1,<sig> compare) with a non-ASCII signature, which raised
TypeError before the fix and now rejects cleanly.
…g sites

Same bug class as the salvaged #65305/#65307: hmac.compare_digest (and
secrets.compare_digest) raise TypeError when given a str containing
non-ASCII characters, and these call sites feed it raw request input.
Compare as UTF-8 bytes everywhere:

- gateway/platforms/msgraph_webhook.py: clientState from request body
- gateway/platforms/whatsapp_cloud.py: hub.verify_token query param +
  X-Hub-Signature-256 header (comment claimed 'works on str' — it
  doesn't for non-ASCII)
- plugins/platforms/feishu: verification token + x-lark-signature
- plugins/platforms/raft: bridge token header
- plugins/platforms/line: X-Line-Signature
- plugins/platforms/sms: X-Twilio-Signature
- tools/code_execution_tool.py: sandbox RPC token (both loops)

Regression tests for the two gateway-core sites (msgraph, whatsapp).
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets platform/webhook Webhook / API server platform/whatsapp WhatsApp Business adapter platform/feishu Feishu / Lark adapter platform/sms SMS (Twilio) adapter area/auth Authentication, OAuth, credential pools sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Jul 16, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Comment

Overview

  • Security fix: reject non-ASCII auth/signature input with 401 instead of crashing
  • 169 additions, 19 deletions
  • Affects all compare_digest sites

Assessment

  • Good defensive security fix — non-ASCII input to HMAC comparison can cause type errors or unexpected behavior
  • Using .encode() on both sides before compare_digest is correct for Python 3 string handling
  • Covers multiple providers (Telegram, GitLab, etc.) — comprehensive

Note

  • No input validation seen for the secret.encode() call itself — if self._api_key could be None, this would crash. Verify this is prevented upstream.

Reviewed by Hermes Agent

@teknium1
teknium1 merged commit a6d9d1d into main Jul 16, 2026
33 checks passed
@teknium1
teknium1 deleted the salvage/65305-65307-nonascii-hmac branch July 16, 2026 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets P2 Medium — degraded but workaround exists platform/feishu Feishu / Lark adapter platform/sms SMS (Twilio) adapter platform/webhook Webhook / API server platform/whatsapp WhatsApp Business adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants