deer-flow/backend/tests/test_gateway_utils.py
Hyeonsang Cho 14cd840bbf
fix(gateway): reject non-ASCII tokens instead of raising in constant-time compares (#6076)
* fix(gateway): reject non-ASCII tokens instead of raising in constant-time compares

hmac.compare_digest raises TypeError when a str operand holds non-ASCII
characters. Starlette decodes header bytes as latin-1 and query values as
UTF-8, so a single 0xE9 byte in a CSRF token, GitHub webhook signature,
internal auth token, or OIDC state turned the expected 403/401 into a 500.

Route the five client-facing comparisons through a new
app.gateway.utils.constant_time_equals helper that compares the UTF-8
encodings ("surrogatepass" so even a lone surrogate cannot raise). ASCII
results are unchanged, and no bypass was possible before the fix.

* fix(provisioner): reject non-ASCII API keys instead of raising; drive OIDC test over HTTP

The standalone provisioner compared X-API-Key with secrets.compare_digest on
str operands, so a non-ASCII header raised TypeError (500) the same way the
Gateway sites did. It cannot import app.gateway, so encode inline.

The OIDC state regression test now mounts the auth router and sends the
percent-encoded state through a real signed state cookie instead of stubbing
get_state_cookie and calling the handler directly.

* docs(changelog): reference #6076

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-09-30 17:41:11 +08:00

22 lines
558 B
Python

"""Tests for shared Gateway utility helpers."""
import pytest
from app.gateway.utils import constant_time_equals
@pytest.mark.parametrize(
("a", "b", "expected"),
[
("token", "token", True),
("token", "other", False),
("tok\xe9n", "tok\xe9n", True),
("token", "tok\xe9n", False),
("tok\xe9n", "token", False),
("tok\ud800n", "token", False),
("", "", True),
],
)
def test_constant_time_equals_never_raises_on_non_ascii(a, b, expected):
assert constant_time_equals(a, b) is expected