Files
ani-web/docs/CHANGES-2026-09.md
T

2.0 KiB

Code-audit fix batch (2026-09)

Findings from the 2026-09-15 code audit, in shipping order. The systemd cutover was explicitly deferred — the process stays on run.sh's nohup model; only the restart mechanism's blast radius is fixed here.

1. login handler blocks the event loop (HIGH)

login is async def, so the anti-brute-force time.sleep(0.5) inside the lockout check runs ON the event loop: every wrong password stalls every in-flight request (all streams included) on the single worker. Fix: make the handler a plain def (uvicorn runs it on the threadpool); move the lockout logic into a side-effect-free server/auth.py so it is unit-testable without booting the app. Regression test measures /api/cdn latency while a wrong-password login is mid-sleep.

2. run.sh global pkill (HIGH)

pkill -f "uvicorn .*app:app" also matches the test server (uvicorn server.app:app --host 127.0.0.1 --port 8399): an ani-web restart kills running test sessions (and vice versa). Fix: PID file (server.pid) becomes the primary kill path; any pattern fallback is port-scoped to the real instance.

3. lockout is per-username only (MEDIUM)

Spreading failures across usernames bypasses the per-username lockout entirely (and anyone can lock a known account for 15 min). Add a per-IP failure budget (ANIWEB_IP_FAILS / window) on top of the per-username lockout. Client IP = request.client.host; the reverse proxy's X-Forwarded-For is consulted only when ANIWEB_TRUST_XFF=1 (set by run.sh), so a spoofed header can't widen or narrow the gate.

4. login is exempt from the CSRF header check (MEDIUM)

The custom-header check that makes cross-site form POSTs fail excludes /login. The exemption is load-bearing only by accident (JSON body content-type); login becomes covered by the same check as every other mutation, and login.html sends the header.

5. dependencies unpinned (MEDIUM)

curl_cffi version churn = impersonation churn = silent upstream 403 waves. requirements.txt becomes a full freeze; bump deliberately.