Boring Docs
Security — IDOR + OWASP-10 Lockdown
Ownership bindings, allowlists, verification, headers, deps.
In this guide
Security
Threat model: solo-founder VPS behind nginx/boring.conf, PSP webhooks exposed, SQLite default. Deny by default.
A01 Broken Access Control (IDOR)
- Mutating routes scope by session: board
{_id,userId}, post via board ownership, product owner-or-admin with 404 masking, sync-dodosellerIdmatch, user self-only. assertActorIntegrity(session, body)inlibs/security.js: automatically verifies that client-provided IDs (userId,authorId,sellerId) matchsession.user.id.- Cancel subscription binds
subscriptionId→ order buyer/customer or admin (403 else). - Claim-repo binds to authenticated user only;
githubUsernameregex enforced. - Purchases/billing merge id+email orders with dedupe; never trust client-supplied owner ids.
A02 Crypto / A07 Auth
- NextAuth JWT + per-DB adapters;
NEXTAUTH_SECRETrequired; dev login dev-only; stale sessions →/authwithout loops;ADMIN_EMAILSfail-closed in prod.
A03 Injection
- SQL via prepared statements only (better-sqlite3, Supabase client, Mongoose). No string-built queries.
- Markdown → HTML is the one XSS sink (
dangerouslySetInnerHTML): repo-owned only; sanitize if opened. React escapes everything else.
A04/A05 Design + Misconfig
- Webhooks verify (Stripe SDK, Dodo Standard Webhooks + replay window, LS HMAC) and return 4xx/500 correctly for retry.
- Redirects must be relative same-origin: auth
callbackUrl, portalreturnUrl, checkoutsuccessUrl/cancelUrl. Enforced viasafeUrl(url, fallback)inlibs/security.js. - In-memory sliding-window
rateLimit(key, limit, windowMs)for lightweight route-level abuse prevention. - Headers in
next.config.js+ nginx (DENY/nosniff/referrer/permissions); nginx also rate-limits/api/auth+/api, denies dotfiles/env/db.
A06/A08/A09/A10
- Deps: run
npm audit, upgrade flagged (axios/form-data/eslint chain), retest. No new packages without need. - Integrity: prices from product row; webhooks dedupe on
providerPaymentRef(unique/sparse everywhere). - Logging & Incident Response:
scream(message, context)inlibs/telemetry.jsfires emergency alerts to Telegram/Discord with a 60-second circuit breaker. - SSRF: only fixed-host fetches (GitHub API, PSPs);
repofrom env, username encoded.