kanban-dev-webapp/tests/integration
Dave 8c860f2d50 fix(auth): verify sessions against PocketBase instead of trusting the cookie
getCurrentUser() only decoded the pb_auth cookie locally and trusted its
embedded role/client/active fields directly — the PocketBase JS SDK holds
no secret to check a JWT signature against, so a completely forged cookie
(garbage signature, role: "owner", any email) was accepted as a real
session. Verified exploitable end-to-end: a raw Cookie header against the
live app, no browser and no password, rendered the owner's home page.

This mattered most for actions writing through the superuser connection
(log-work.ts, summarise.ts, ingest.ts, and critically users.ts for account
creation) — those never route the caller's token through PocketBase's own
rule engine at all, so the app-level role check was the ONLY gate, and it
was reading an unverified claim. Actions using the caller's own token
(cards.ts, projects.ts) still made the wrong authorization DECISION from
the forged role, even though PocketBase's rule engine would have rejected
the actual data write.

Fixed by having getCurrentUser() call authRefresh(), which asks PocketBase
to confirm the token is genuine; a forged or tampered token is refused
there and treated as signed-out. Wrapped in React's cache() so the extra
round-trip happens once per request, not once per call site (several pages
call this more than once). Re-fetching the live record also means a
deactivated account (`active: false`) stops working on its very next
request instead of only being blocked at a new login.

Regression test builds the exact forged cookie used to verify this,
confirmed red against the vulnerable code and green against the fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 12:47:18 +02:00
..
activity-log.test.ts test(permissions): integration coverage for the client write boundary 2026-09-16 09:46:58 +02:00
admin.test.ts test(admin): board invariants, owner-only writes, deactivation 2026-09-16 11:31:38 +02:00
ai-settings.test.ts fix(tests): stop the settings test destroying the configured API key 2026-09-17 08:13:24 +02:00
client-permissions.test.ts test(permissions): integration coverage for the client write boundary 2026-09-16 09:46:58 +02:00
helpers.ts test(ai): settings page never exposes the API key 2026-09-16 15:59:49 +02:00
ingest.test.ts test(ingest): webhook and cron endpoint protection 2026-09-16 11:50:20 +02:00
intake-submit.test.ts test(intake): server-decided fields and project scoping 2026-09-16 18:07:16 +02:00
intake.test.ts test(intake): cap enforcement, brief whitelist, project scoping 2026-09-16 17:56:37 +02:00
linking.test.ts test(metrics): cached figures agree with stored commits + vitest stubs 2026-09-16 15:19:32 +02:00
metrics.test.ts test(metrics): cached figures agree with stored commits + vitest stubs 2026-09-16 15:19:32 +02:00
narrative.test.ts test(narrative): no invention, and raw-subject fallback 2026-09-16 16:26:29 +02:00
owner-actions.test.ts test(actions): cover audit-log immunity and request flags 2026-09-16 11:06:38 +02:00
project-kind-and-nav.test.ts test(nav): prototype visibility and client scoping on the new home page 2026-09-17 10:42:52 +02:00
roadmap.test.ts test(roadmap): reschedule auditing and role scoping 2026-09-17 07:19:54 +02:00
session-verification.test.ts fix(auth): verify sessions against PocketBase instead of trusting the cookie 2026-09-19 12:47:18 +02:00
summarise.test.ts test(ai): merge exclusion, graceful degradation, summary persistence 2026-09-16 16:18:40 +02:00
user-rules.test.ts fix(security): lock the users collection against privilege escalation 2026-09-16 11:18:13 +02:00