You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
perf(backend): full backend audit — offload blocking SDK calls, harden rate limiter + AI cache
- Offload all remaining synchronous Supabase/PostgREST SDK calls to worker
threads via run_blocking: auth endpoints (login, refresh, register, logout,
forgot/reset-password), lighter chat handlers, ~13 email-controller sites
(ownership helpers now async), and the OAuth callback upsert — slow
upstream calls no longer stall concurrent requests
- Rate limiter: compaction sweep for the in-memory sliding window — keys
embed caller-controlled input (login:{ip}:{email}) and previously grew
without bound (memory-exhaustion DoS vector)
- AI suggestion cache: SHA-256 keys (built-in 64-bit hash() collision could
serve one user another user's cached suggestions) + expired-entry sweep
on write instead of leaking until a same-key read
Verification: ruff check/format clean, pytest 102/102, bandit 0 issues,
frontend build OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: AGENT.md
+10Lines changed: 10 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,16 @@ description: Foundational agent rules for the Gemini + LiteStar + React project.
5
5
6
6
# Agent Rules
7
7
8
+
### 2026-06-13 (Australia/Sydney) — Full Backend Audit + Hardening/Performance Pass
9
+
10
+
**Raouf:**
11
+
12
+
-**Scope:** Audit all 21 backend modules (auth middleware, controllers, services, rate limiting, data protection, email service/poller, OAuth, config, security headers, observability) + schemas/tests, then fix findings directly.
13
+
- **Summary:** The backend was already strongly hardened (alg-confusion-guarded JWT with issuer/audience checks, RLS-scoped per-user PostgREST clients, PKCE+state OAuth with Host validation, Fernet-encrypted tokens/takeaways, prompt scrubbing + circuit breaker, Sentry scrubbing, production config guards). Four real issues fixed: **(1) Event-loop blocking on auth hot paths** — every synchronous Supabase auth SDK call (`/auth/login`, `/auth/refresh` which fires on every silent refresh, `register`, `logout` revocation, `forgot/reset-password`) ran directly on the event loop, stalling all concurrent requests during slow upstream calls; all now offloaded via `run_blocking`. Same completion for the remaining sync `.execute()` sites in `chat_controller` (list/create/delete sessions, get_messages), `email_controller` (~13 sites incl. the `_get_account`/`_get_email` ownership helpers, now async), and the OAuth callback upsert — this clears the deferred follow-up from the 2026-05-31 performance pass. **(2) In-memory rate limiter unbounded key growth (DoS)** — keys embed caller-controlled input (`login:{ip}:{email}`) and were never evicted; an attacker spraying unique emails could grow the dict without bound. Added a compaction sweep (threshold 10k keys) that drops keys whose entries have aged out. **(3) AI suggestion cache cross-user collision risk** — cache keys used Python's built-in 64-bit `hash()`; a collision would hand one user another user's cached suggestions. Switched to SHA-256. **(4) Suggestion cache slow leak** — expired entries were only removed on same-key reads; now swept on every write.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+10Lines changed: 10 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,15 @@
1
1
# Change Log
2
2
3
+
### 2026-06-13 (Australia/Sydney) — Full Backend Audit + Hardening/Performance Pass
4
+
5
+
**Raouf:**
6
+
7
+
-**Scope:** Full audit of all 21 backend modules with direct fixes (security + performance + production-readiness).
8
+
-**Summary:** Fixed four real issues in an otherwise heavily-hardened backend: (1) offloaded every remaining synchronous Supabase/PostgREST SDK call to worker threads via `run_blocking` — auth endpoints (login, refresh, register, logout, forgot/reset-password), the four lighter chat handlers, ~13 email-controller sites (ownership helpers `_get_account`/`_get_email` are now async), and the OAuth callback upsert — so slow upstream calls no longer stall every concurrent request (completes the deferred follow-up from the 2026-05-31 performance pass); (2) added a compaction sweep to the in-memory sliding-window rate limiter, whose keys embed caller-controlled input and previously grew without bound (memory-exhaustion DoS vector); (3) switched the AI suggestion cache key from Python's 64-bit `hash()` to SHA-256 — a collision could have served one user another user's cached suggestions; (4) the suggestion cache now sweeps expired entries on write instead of leaking them until a same-key read.
-**Follow-ups:** Optional: parallelise Gmail N+1 fetch + account polling in the poller; shared httpx transport for PostgREST clients; streaming chat responses. Not deployed to the droplet yet.
12
+
3
13
### 2026-06-13 (Australia/Sydney) — Full UI/UX Audit + Accessibility/Polish Pass
0 commit comments