Daeseon Yoo
Back to project
·Tech retro·2 min·Review needed

Adversarial Security Review: 11 Confirmed Flaws and What We Fixed Now

After the build, we ran a multi-agent adversarial review (security/auth/data/capture/PWA/spec) and confirmed 11 flaws. Fixed immediately the ones that break the demo/spec; documented the 2 production-scale items.

AI version

Once the app was working at e1a924e, we ran an adversarial review across 6 dimensions (security/auth/data/capture/PWA/spec) and adopted each finding only after independent verification. 11 confirmed flaws. All verified by reading the code directly.

Fixed immediately (all ed3600c)

FlawVerificationFix
dev-login auth bypass in productionRoute has no NODE_ENV guard → an email alone issues a session for someone else's boxProduction notFound() guard
Upload MIME unvalidated → stored XSSThe contributor's file.type is stored and reflected as-is; svg/html possibleMIME whitelist (isAllowedImageMime/Audio) + X-Content-Type-Options: nosniff on media responses
SW caches private box HTMLThe navigate branch ran caches.put on every response → leak on logout / shared devicenetwork-only + offline fallback, cache v1→v2 to clear out the old
Media route ignores Range (iOS playback broken)Advertises Accept-Ranges but always returns 200Parse Range → 206 + Content-Range
No CSRF protectionCookie is the sole authority for state changes, no Origin checkEnforce same-origin via proxy.ts (Next 16, formerly middleware)
No per-token rate limit + unbounded body bufferingPublic endpointsPer-token throttle + early cutoff on body Content-Length
Partial env regenerates session secretAll-or-nothing, so giving just SESSION_SECRET was ignoredApply each key individually
AudioRecorder reports every failure as 'mic denied'The recordFailed copy was dead code (violates §18)Distinguish by err.name + unmount-safe

Verification method (run directly): evil Origin POST → 403, same-origin → 200; text/html as photo → 400; curl -H "Range: bytes=0-99"206/content-range; unauthenticated media → 401.

Not fixed now, documented instead (production-scale only, no demo impact)

  • Persist notification dedupe: currently in-memory (fine for a single process). With multiple instances/restarts, duplicate sends are possible → needs a persistent (reminderId, date, HH:MM) marker. PGlite today is single-instance, so no impact on the demo.
  • Trusted proxy IP: the rate-limit key is based on the raw X-Forwarded-For (spoofable) → should use the hosting trusted IP. Partial defense is already in place via per-token throttle.

Notes

  • The review is structured as find → independent verification → adopt. We separated the verification step to filter out "plausible but wrong" findings.
  • One honest limitation: the fixes above were verified by running the dev server, but we did not reproduce the actual attack scenarios (e.g., a real cross-site form) — only confirmed standard defenses like Origin checks and nosniff at the code level.

Review needed

No human review on this entry yet.