StudyNavi follows a rolling-release model on main. Security fixes are applied to the latest deployed version.
Please do not open public GitHub issues for security findings.
Report privately to:
- Email:
erald.mangubat@example.com - Subject:
StudyNavi Security Report
Include:
- Affected endpoint/file/flow
- Reproduction steps
- Expected vs actual behavior
- Potential impact
- Optional mitigation suggestion
- Initial acknowledgment target: within 2 business days
- Triage target: within 5 business days
- Fix timeline: depends on severity and exploitability
- Never commit
.env.local, service account JSON, or private keys. - Use Firebase App Hosting secrets for runtime credentials.
- Rotate compromised credentials immediately.
- In-scope: application code in this repository, API routes, deployment workflow configuration.
- Out-of-scope: social engineering, physical access attacks, third-party service outages.
- Firestore/Storage bug-report rules were tightened:
- report documents require authenticated access
- report image uploads are user-scoped (
reports/{uid}/...) and type/size restricted
- Bug report submission now enforces signed-in identity and stores actor metadata (
createdByUid,createdByEmail). - Login SSO token ingestion now prefers URL hash token over query token to reduce accidental token leakage in logs/referrer surfaces.
- Dependency hardening:
- removed unused
firebase-functionspackage - pinned
next/eslint-config-nextto16.1.7 - upgraded
jspdfto4.2.1 - added overrides for
node-forge,fast-xml-parser,dompurify
- removed unused
npm audit --omit=devresidual is low-severity transitive Firebase/Google chain (@tootallnate/once); no high/critical app-level production advisories remain.
- Protected API routes now require server-verified Firebase ID tokens (
Authorization: Bearer <idToken>):/api/chat/api/ai/brief-info/api/chat/corrections(staff/admin only)
- AI-costing routes now use shared persistent rate limiting (
__rateLimits) to work across instances. - Turnstile verification endpoint now enforces:
- timeout/retry-safe upstream calls
- hostname validation
- action validation (
loginby default) - per-client rate limits
- Report privacy tightened:
- report documents/screenshots are now staff-or-owner readable
- report creation requires owner UID consistency
- School/provider rendering hardening:
- removed risky raw HTML rendering for school names
- outbound school website URLs are protocol-validated (
http/httpsonly)
- Production safety guardrails:
- E2E auth/mock bypass flags are hard-blocked in production runtime even if env is mis-set
- TypeScript build errors are no longer ignored in
next.config.ts
- Login redirect hardening:
nextredirect targets now accept only internal relative paths (open-redirect patterns are rejected).
- Request identity hardening:
- server request IP derivation now uses strict IP parsing and explicit proxy trust mode (
TRUST_PROXY_MODE).
- server request IP derivation now uses strict IP parsing and explicit proxy trust mode (
- Runtime alert endpoint hardening:
/api/runtime-alertnow requires authenticated caller context and per-user rate limiting.- runtime alert sources are restricted to allowed prefixes (
RUNTIME_ALERT_ALLOWED_SOURCES, defaultpdf.).
- Firestore report-create hardening:
- strict create-shape/value checks now block status/email spoofing and unknown fields.
- Auth response normalization:
- invalid token failures return
401; auth infrastructure/runtime failures return503.
- invalid token failures return
- Turnstile verification tightening:
- expected action now requires exact match when configured.
- cross-site origin checks and challenge timestamp freshness checks added.
- SSRF hardening:
- Brave excerpt fetch now restricts targets to public HTTP(S) hosts and blocks localhost/private/reserved/internal targets.
- Rules assurance:
- semantic emulator-based rules tests added under
tests/rules/semantic-rules.test.ts.
- semantic emulator-based rules tests added under
- Browser policy hardening:
- added baseline CSP via
src/proxy.ts. - CSP still keeps
'unsafe-inline'for scripts/styles because current Next.js runtime + Turnstile/Maps integrations inject inline bootstrap/style paths. - optional stricter rollout mode is available via
CSP_ENABLE_STRICT_REPORT_ONLY=trueto measure breakage risk before enforced tightening. - added production HSTS (
Strict-Transport-Security). - protected routes now emit
Cache-Control: no-storeandX-Robots-Tag: noindex, nofollow.
- added baseline CSP via
- SSRF hardening uplift:
- Brave excerpt fetch now validates redirect chains (manual redirect mode).
- each redirect hop is re-validated for public-network-only targets.
- non-standard ports are blocked, response content-type is restricted, and response body size is capped.
- Claims-first posture tightening:
- server/client/rules now prioritize explicit claims (
admin,staff,support) as authority. - legacy staff-domain compatibility is now gated behind explicit claim bridge (
legacy_staff_email_fallback=true) plus optional runtime bridge flags:STUDYNAVI_ENABLE_LEGACY_STAFF_COMPAT_BRIDGENEXT_PUBLIC_STUDYNAVI_ENABLE_LEGACY_STAFF_COMPAT_BRIDGE
- chat-corrections mutation endpoints now require explicit staff/admin claim by default (
STUDYNAVI_REQUIRE_STAFF_CLAIM_FOR_CORRECTIONS=true).
- server/client/rules now prioritize explicit claims (
- Injection hardening:
- removed raw HTML rendering fallback from modal utility paths.
- external links in modal content now allow only explicit
http(s)URLs.
- API abuse/correctness hardening:
- request-body size caps added for
/api/chatand/api/ai/brief-info. - malformed JSON now returns explicit 4xx responses in protected JSON endpoints (
/api/ai/brief-info,/api/chat/corrections,/api/runtime-alert,/api/turnstile/verify).
- request-body size caps added for
- Turnstile trust-chain increment:
- proof cookie is signed with hostname+fingerprint binding and validated on reuse before upstream verification.
- server-session creation can require valid turnstile proof (
STUDYNAVI_SESSION_REQUIRE_TURNSTILE_PROOF=true) except explicit Pathfinder SSO source handoff.
- Ops drift hardening:
- added
npm run ops:check:drift(scripts/check-ops-drift.js) for repo + cloud drift checks (TTL/App Check/alerts when auth is available). - added scheduled workflow
.github/workflows/ops-drift-check.yml.
- added
- Server-trusted protected-page boundary:
- server issues/verifies
__studynavi_sessionhttpOnly cookie via/api/auth/session. - proxy now blocks unauthenticated protected routes before page render and redirects to
/login?next=.... /loginauto-redirects authenticated session holders to sanitized internalnexttarget.
- server issues/verifies
- Session/auth governance:
- session cookie TTL is configurable (
STUDYNAVI_SESSION_TTL_SECONDS). - production requires
STUDYNAVI_SESSION_SECRET. - session create/delete emits structured audit logs.
- session cookie TTL is configurable (
- CSP migration:
- enforced CSP now includes reporting endpoint (
/api/csp-report). - strict CSP report-only mode defaults to
truein production andfalsein non-production (setCSP_ENABLE_STRICT_REPORT_ONLY=truelocally to rehearse stricter policy safely).
- enforced CSP now includes reporting endpoint (
- Release posture:
- staging rollout and manual promotion workflows added:
.github/workflows/firebase-app-hosting-staging-rollout.yml.github/workflows/promote-to-production.yml
- staging rollout and manual promotion workflows added:
- Firebase Auth sign-in is still client-initiated (
signInWithEmailAndPassword/signInWithCustomToken) to preserve current Pathfinder contract and StudyNavi login UX. - Full claims-only enforcement still depends on claims hygiene in Firebase Auth (assignment/revocation operations are outside this repo and documented in ops runbooks).
- Claims cutover:
STUDYNAVI_CLAIMS_CUTOVER_MODE=bridge|strict- strict mode hard-disables legacy bridge fallback.
- readiness checks:
npm run check:claims-cutovernpm run check:claims-cutover:cloud
- CSP cutover:
CSP_ENABLE_STRICT_REPORT_ONLYfor staged violation collection.CSP_ENABLE_STRICT_ENFORCEfor strict enforcement after report triage.- CSP reports are ingested at
/api/csp-report.
- Drift and release enforcement:
- repo + cloud drift modes are separated (
ops:check:drift,ops:check:drift:cloud). - staging/promotion workflows include Pathfinder contract and cloud drift gating.
- repo + cloud drift modes are separated (
- Recovery discipline:
npm run check:recovery-drillvalidates restore/rollback drill assets and dry-run restore path.
- Turnstile proof validation now uses a stable request binding suitable for App Hosting proxy hops (instead of edge-IP-derived binding).
- Turnstile proof cookie behavior was tuned for live auth flow stability:
- proof cookie now uses
SameSite=Laxwith host+binding+TTL signature validation still enforced server-side.
- proof cookie now uses
- Login client explicitly sends credentials on Turnstile verification request to avoid browser variance on cookie attach.
- Deployment discipline updated to require dual-backend sync (
studio->studio-asia) per release to prevent stale auth config drift.