RETROFIT PLAYBOOK — Securing Any Existing Platform
A generic, reusable guide for retrofitting the Spotlight security baseline into **any** existing platform you've already built. Use this for Champion Neon, GMALC/Mizan, ZEROAGENCY, getgoldsilver, newworld.education, createagent.ai, drrashidalameri, and every platform after.
**Time per platform:** ~1 hour after you've done the first one.
**Outcome:** No friend-with-AI can find anything meaningful. You can send the client a "we audited and closed everything" reply with confidence.
---
Phase 0 — Preparation (5 minutes)
```bash
# 1. Open the existing platform in your terminal
cd ~/dev/[platform-name]
2. Make a safety branch — never retrofit on main
3. Make sure you have spotlight-secure-starter handy as a reference
4. Open Claude Code in this folder
**The mindset:** You are NOT replacing the platform. You are adding a security layer on top of what already works. Every change is additive.
---
Phase 1 — Audit First, Don't Fix Blind (15 minutes)
Paste this exact prompt into Claude Code:
```
This is an existing platform. Before I retrofit security, I need a complete
findings report. Do NOT change any code yet. Output a markdown report only.
Scan everything and report findings grouped by severity (Critical / High /
Medium / Low). For each finding give: file path, line numbers, what's wrong,
why it matters, exact fix.
CHECK ALL OF THESE:
1. EXPOSED SECRETS — hardcoded API keys/tokens/passwords; anything sensitive
in NEXT_PUBLIC_* or equivalent client-exposed vars; service role keys
reachable from client; .env files committed to git history
2. SUPABASE RLS (or equivalent DB access control) — list every table;
confirm RLS is enabled; confirm each has owner-scoped policies; flag any
wide-open table
3. UNPROTECTED API ROUTES / ENDPOINTS — every route that mutates data or
returns user-specific data must check auth + authorization
4. IDOR — any endpoint that takes an ID and returns/mutates data without
verifying the caller owns that resource
5. INPUT VALIDATION — every form body, query param, route param validated
with a schema; reject unknown keys; bound string/number lengths
6. XSS — any dangerouslySetInnerHTML, unescaped user content, unsafe
markdown rendering
7. SECURITY HEADERS — CSP, HSTS, X-Frame-Options, X-Content-Type-Options,
Referrer-Policy, Permissions-Policy
8. RATE LIMITING — every public endpoint (login, signup, contact form,
AI calls, password reset) has limits
9. CORS — no wildcards on credentialed routes
10. DEPENDENCY CVEs — run npm audit (or equivalent), report HIGH/CRITICAL
11. ERROR HANDLING — no stack traces, DB errors, or internal paths leaked
to the client
12. AUTH FLOW — password rules, logout actually clears session, password
reset uses signed expiring tokens, no user enumeration
13. FILE UPLOADS (if any) — server-side type/size validation, signed URLs,
no execution of uploaded content
14. CSRF — state changes only via POST/PUT/DELETE; SameSite cookies
15. LOGGING — no passwords, tokens, or full PII in logs
End with a one-line verdict: GREEN / YELLOW / RED, and the top 3 things
to fix first.
```
**Save the report.** Create `SECURITY-AUDIT-[date].md` in the project root and paste the findings. This becomes your fix list AND the proof-of-work to send the client.
---
Phase 2 — Fix Critical/High Findings First (30 minutes)
Order matters. Do them in this sequence:
2A. Kill exposed secrets (10 min, highest impact)
```
For every secret finding from the audit:
1. Move the secret out of the code into .env.local (or platform equivalent)
2. If it's in NEXT_PUBLIC_* and shouldn't be — rename it without that prefix
and only access it server-side
3. Add the var name to .env.example with an empty value
4. If the secret was ever committed to git history, ROTATE it (assume it's
burned). Generate a new one in the provider dashboard.
5. Confirm .env.local is in .gitignore
After fixing, search the codebase one more time for: "sk_", "key=", "token=",
"password=", and the literal first 6 chars of each known key. Report findings.
```
2B. Lock down the database (10 min, biggest "vulnerability" closer)
For Supabase platforms:
```
For every table in this project's Supabase database:
1. Generate a SQL migration to ALTER TABLE ... ENABLE ROW LEVEL SECURITY
if not already on
2. Generate owner-scoped policies (SELECT/INSERT/UPDATE/DELETE) for each
table that has user-owned rows
3. For tables that should be admin-only, write admin-role policies
4. For tables that are public-readable (e.g. published blog posts), write
explicit public-read policies — never leave RLS off
5. Output all migrations as a single .sql file I can paste into the
Supabase SQL editor
Also check: is the SUPABASE_SERVICE_ROLE_KEY used anywhere in client code
or in API routes that don't first check auth? Flag every instance.
```
For non-Supabase platforms (raw Postgres, Firebase, MongoDB, etc.):
```
This platform uses [database name]. For every collection/table:
1. List what access controls exist
2. Identify any that allow unauthenticated reads/writes of user data
3. Generate the equivalent of "owner can only read their own rows" rules
for this database
4. Output as a migration/config I can apply
```
2C. Wrap API routes with guards (10 min)
```
For every API route in this project, add these four checkpoints in this
order at the top of the handler:
1. RATE LIMIT — reject if too many requests from this IP/user
2. AUTH — reject if not logged in (unless route is intentionally public)
3. VALIDATION — parse input with a strict schema; reject unknown keys
4. AUTHORIZATION — for routes that touch a specific resource, fetch it
first, verify the current user owns it, then proceed
Don't rewrite the business logic — just wrap it. Use a try/catch that
returns clean JSON errors (no stack traces).
If this project doesn't have rate limiting, validation, or auth helpers,
create lib/rate-limit.ts, lib/validation.ts, lib/auth.ts, and lib/errors.ts
following standard Next.js patterns. Use Upstash Ratelimit, Zod, and
Supabase's getUser() (or this project's auth equivalent).
Show me the diff for each route before applying.
```
---
Phase 3 — Add the Foundation Layer (10 minutes)
These are the four files that go into every platform regardless of what it does:
3A. Security headers
```
Add a security headers block to next.config.js (or this project's config
file). Required headers:
- Content-Security-Policy
- Strict-Transport-Security
- X-Frame-Options: DENY
- X-Content-Type-Options: nosniff
- Referrer-Policy: strict-origin-when-cross-origin
- Permissions-Policy: camera=(), microphone=(), geolocation=()
Tune the CSP to allow only the third-party domains this project actually
uses (Supabase, Anthropic, analytics, etc.). Also set
poweredByHeader: false.
After applying, the live URL should score A or A+ on securityheaders.com.
```
3B. Auth middleware (if not already present)
```
Add or update middleware.ts to:
1. Refresh the auth session on every request
2. Block unauthenticated users from protected routes (redirect to login)
3. Block non-admin users from admin routes (redirect away)
Use the project's existing auth provider. Don't break existing flows —
just add the guard. Show me the list of routes you'll protect before
applying.
```
3C. Pre-deploy checklist
```
Create PRE-DEMO-CHECKLIST.md in the project root with these checkpoints:
- npm audit clean
- securityheaders.com grade A+
- observatory.mozilla.org grade A+
- incognito test (logged-out can't access protected pages)
- two-user test (user A can't see user B's data)
- form fuzz test (XSS payloads render as text)
- no .env files in git history
Make it tickable.
```
3D. Threat model (retroactive)
```
Create THREAT-MODEL.md with these four sections, filled in based on what
this platform actually does:
1. WHO ARE THE USERS — public visitors / logged-in users / admins / API
consumers? What can each do?
2. WHAT SENSITIVE DATA — PII, payments, business confidential, uploads,
chat history?
3. WORST-CASE SCENARIOS — what's the worst a malicious user could do?
For each, what stops them?
4. REGULATIONS — UAE PDPL, GDPR, PCI, etc. What applies?
Read the codebase to fill this in accurately, then ask me to confirm or
correct each section.
```
---
Phase 4 — Verify (10 minutes)
```bash
# 1. Run dependency audit
npm audit --audit-level=high
2. Build to make sure nothing is broken
3. Deploy to a Vercel PREVIEW URL (not production yet)
4. Check the preview URL on:
5. Manual user tests in incognito:
6. Re-run the audit prompt from Phase 1
7. Only then merge security-hardening into main and deploy production.
---
Phase 5 — Send Client the Proof (5 minutes)
This is the bit that turns the original Champion Neon situation around.
After retrofit, send the client this template:
```
Hi [name],
Following the feedback, I've put the platform through a full security audit
covering 15 attack categories (exposed secrets, database access controls,
API protections, input validation, XSS, security headers, rate limiting,
CORS, dependency vulnerabilities, error handling, auth flow, file uploads,
CSRF, logging, and dependency CVEs).
Findings closed:
- [X] Critical
- [Y] High
- [Z] Medium
The platform now scores A+ on securityheaders.com and on Mozilla's
Observatory. Here are the live grades:
[link to securityheaders.com result]
[link to observatory.mozilla.org result]
If your team wants to run additional scans, please go ahead — happy to
respond to any further findings. The platform is on a security-first
baseline going forward, so this becomes the standard for everything we
build together.
```
This converts a complaint into a credential. Most clients have never had a vendor respond like this.
---
Generic principles for ANY stack
If a platform isn't Next.js + Supabase (e.g. Python/FastAPI like TitanTrader, or static HTML, or pure WhatsApp/USSD), the **principles stay identical** — only the implementation changes:
| Principle | Next.js+Supabase | Python/FastAPI | Static HTML | Vanilla Node |
|---|---|---|---|---|
| Don't expose secrets | `.env.local` not committed | `.env` + python-dotenv, gitignored | No secrets in HTML/JS | `.env` + dotenv |
| Auth on every protected route | `middleware.ts` + `requireUser()` | FastAPI `Depends()` auth | N/A (static) | Express middleware |
| DB owner checks | Supabase RLS | SQLAlchemy + manual ownership check | N/A | ORM + manual check |
| Input validation | Zod | Pydantic | N/A | Joi / Zod |
| Rate limiting | Upstash Ratelimit | slowapi | Cloudflare rules | express-rate-limit |
| Security headers | `next.config.js` headers block | FastAPI middleware | `_headers` file (Vercel/Netlify) | helmet |
| Error sanitization | `errorResponse()` helper | FastAPI exception handlers | N/A | Express error middleware |
| Pre-demo audit | Claude Code prompt | Same prompt | Same prompt (skip DB items) | Same prompt |
**The audit prompt in Phase 1 works for all of them** — Claude Code adapts its findings to the actual stack it's reading.
---
When NOT to retrofit
Don't waste time retrofitting if:
- The platform is a pure landing page with no forms, no auth, no DB → just add security headers and you're done
- The platform was a one-off demo that's no longer in use → archive it, don't retrofit
- The platform is days from a major rewrite → retrofit during the rewrite, not before
For everything else: retrofit. The first one takes 60–90 minutes. Every one after that takes 30–45 minutes because Claude Code recognises the pattern and you reuse the same prompts.
---
The repeat-this-monthly habit
For every active platform, once a month:
1. `git pull` latest
2. `npm audit --audit-level=high`
3. Run the audit prompt against the codebase
4. Re-check securityheaders.com on the live URL
5. Apply any new fixes
Calendar block: 30 minutes per platform per month. For 20 platforms, that's 10 hours/month of security maintenance — but it's the difference between a platform business and a platform-shaped lawsuit waiting to happen.