Skip to content

Security audit fixes: 2 prod bugs + auth hardening + action SHA-pinning - #10

Merged
xdroberto merged 4 commits into
developfrom
fix/security-audit
Jul 8, 2026
Merged

Security audit fixes: 2 prod bugs + auth hardening + action SHA-pinning#10
xdroberto merged 4 commits into
developfrom
fix/security-audit

Conversation

@xdroberto

Copy link
Copy Markdown
Owner

Summary

Applies the read-only security + logic/config audit findings (2 parallel auditors). No feature changes — hardening plus 2 real production-only bugs. CSP, logout-CSRF, and rate-limit trustedProxies are deferred (documented in docs/limitations.md).

🔴 Production bugs (invisible until prod / an incident):

  • __Secure- session cookie now clears with Secure (api/session/clear). Browsers reject a Set-Cookie for a __Secure--prefixed name without Secure, so in prod the stale cookie never cleared → the /login ↔ /dashboard loop this route exists to break could recur (secret rotation / DB reset). Untested before (e2e runs on HTTP dev).
  • remote-deploy.sh aborts on a failed docker compose pull. Without set -e, a failed pull fell through to up -d (no-op), health-checked the OLD app, and reported a green deploy on stale code.

🟠 Auth-surface hardening:

  • Removed getValueFromCookie — a dead "use server" action that returned any cookie incl. the HttpOnly session token (XSS → session-theft amplifier).
  • Allow-listed setValueToCookie against PREFERENCE_REGISTRY (was a generic same-origin cookie-write primitive).
  • Added a /sign-up/email rate limit (10/60s) — the global 100/10s was far too loose for account provisioning.
  • seed.ts fails closed — SEED_PASSWORD required, no repo-visible NovaReview2026! default (.env.example documents it).
  • removeConsole keeps console.error in prod (server error visibility, incl. the pg pool handler).

🔗 Supply-chain / CI:

  • Pinned every GitHub Action in deploy.yml + ci.yml to its current tag's commit SHA (esp. appleboy/ssh-action + scp-action, which receive root VPS SSH secrets), with a trailing # vX comment.
  • ci.yml gets a top-level permissions: contents: read.

Deferred (in docs/limitations.md): CSP (strict script-src/style-src risks breaking Next inline styles/scripts right before the deadline — no proven injection path today), GET-logout CSRF (nuisance only), rate-limit trustedProxies.

Test plan

  • CI commits gate — 4 conventional commits
  • CI quality — lint + tsc + test:unit + branding + build
  • CI e2e — full Playwright incl. the security suite (verified 11/11 locally against these changes, in an isolated worktree)
  • On merge → main: push-to-deploy still works — the pinned actions are the same commits the tags currently point to (identical behavior); the deploy pull-guard + rollback path are behavior-preserving. deploy.yml runs only on push-main, so it's exercised on the next promotion.

Notes

  • Built in an isolated worktree off origin/develop (cf4058f) — no overlap with the parallel dashboard-data / UI-landing sessions.
  • The SEED_PASSWORD change affects only fresh seeding; the live reviewer account already exists and is unaffected.
  • Promotion decision is the maintainer's — do not auto-merge.

xdroberto added 4 commits July 8, 2026 11:44
…n failed deploy pull

1) session/clear set an expiring cookie without Secure; browsers reject that for a __Secure--prefixed name, so the prod session cookie never cleared and the /login<->/dashboard loop could recur (untested — e2e is HTTP dev). Now sets Secure to match the cookie's prefix. 2) remote-deploy.sh: a failed 'compose pull' fell through to up -d (no-op), health-checked the OLD app, and reported a green deploy on stale code. Now aborts on pull failure.
- Removed getValueFromCookie: a dead 'use server' action that returned ANY cookie incl. the HttpOnly session token (XSS->session-theft amplifier). - Allow-listed setValueToCookie against PREFERENCE_REGISTRY (was a generic same-origin cookie-write primitive). - Added a /sign-up/email rate limit (10/60s) — the global 100/10s was far too loose for account provisioning. - seed.ts fails closed: SEED_PASSWORD now required (no repo-visible 'NovaReview2026!' default); .env.example documents it. - next.config removeConsole keeps console.error in prod (server error visibility incl. the pg pool handler).
…ssions

Supply-chain: every third-party action (checkout, setup-node, docker/*, appleboy/scp+ssh — the last two receive root VPS SSH secrets) pinned to its current tag's commit SHA with a trailing version comment, so a re-pointed tag can't inject code. Added top-level 'permissions: contents: read' to ci.yml (deploy.yml already scopes it).
CSP deferred pre-deadline (strict script-src/style-src risks breaking Next inline styles/scripts; no proven injection path today). GET /api/session/clear force-logout CSRF deferred as cosmetic (nuisance only). Both recorded as accepted findings with next steps.
@xdroberto
xdroberto merged commit 4208cdc into develop Jul 8, 2026
3 checks passed
@xdroberto
xdroberto deleted the fix/security-audit branch July 8, 2026 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant