Admin auth: constant-time panel-token comparison in require_admin

Fixes review finding P2: require_admin compared the Bearer credential
against config.panel_token with Python ==, which short-circuits and is
not constant-time. Compare with secrets.compare_digest on UTF-8 bytes
instead — the same pattern require_panel_token already uses for this
exact secret — keeping the truthiness guard on config.panel_token and
the same 403 rejection detail and behaviour.
This commit is contained in:
2026-09-23 00:55:15 -04:00
parent 4d697dc025
commit 42a205b4bd
+9 -1
View File
@@ -48,6 +48,7 @@ from __future__ import annotations
import asyncio
import binascii
import json
import secrets
import time
from collections.abc import Awaitable, Callable
from typing import Annotated
@@ -459,7 +460,14 @@ async def require_admin(
if (
config is not None
and config.panel_token
and credential.strip() == config.panel_token
# compare_digest on bytes (as require_panel_token does)
# so the refusal does not short-circuit on the first
# mismatching byte — a constant-time comparison keeps a
# timing side channel on the credential off the table.
and secrets.compare_digest(
credential.strip().encode("utf-8"),
config.panel_token.encode("utf-8"),
)
):
raise HTTPException(
status_code=403,