Pre-Ship Security
This is the last security gate before production: a quick, repeatable review of the finished code. It verifies that nothing slipped through what secure-coding prevented during the build.
Analogy: secure-coding is the seatbelt you wear while driving. A deep audit (Trail of Bits, fuzzing) is the garage that x-rays every part. This skill is the walk-around inspection before a road trip — lights, tire pressure, fuel. Quick, done every time, catches the obvious before you pull out of the driveway.
It does not replace a professional audit for high-risk apps — its job is to tell you when you need one. Security is never 100%; this skill is honest about that.
Trigger
Run when the user is about to deploy, merge to main, launch, or asks "is this safe to ship?". It pairs with secure-coding (which ran during the build) and deployment (which ships it).
Discovery (max 3 questions, only if unknown)
- What does the app handle — payments, personal data (PII), health, or crypto/keys?
- Is this the first production launch, or an incremental deploy?
- Public-facing or internal-only?
Step 1 — Automated quick scans
npm audit --omit=dev(orpnpm audit) → fix high/critical advisories; don't ship known-vulnerable dependencies.- Secret scan:
npx gitleaks detect(and check git history) → no API keys, tokens, or.envcommitted. If something is found, rotate the secret — deleting the commit is not enough, it's in the history. - Confirm
.env,.env*.local,*.pem,*.keyare git-ignored. - Client-bundle leak check: grep the built JS for known key prefixes; on Vite, anything that isn't
VITE_-prefixed must be absent from the bundle.
Step 2 — Review the diff against the prevention checklist
Re-check the finished code — the secure-coding rules, now verified instead of assumed:
- Authz on every endpoint? Each route checks the user and resource ownership (no IDOR). A route with no explicit check is the bug.
- Input validated? Every handler parses input with a
zod.strict()schema; noreq.bodyspread into a DB write (mass assignment). - No raw SQL concatenation — parameterized queries / ORM only.
- CORS is an explicit allowlist, not
*with credentials. - Security headers present (Helmet or platform headers): CSP, HSTS, X-Content-Type-Options.
- Webhooks verify signatures (Stripe, etc.) and read the raw body correctly.
- Errors don't leak stack traces in prod; logs contain no PII, tokens, or passwords.
- Auth routes rate-limited; passwords hashed with bcrypt/argon2.
Step 2b — Outside-in checks (from a terminal, against the deployed app)
Reading the code tells you what it should do. These tell you what it does. Each one has found a real hole in an app whose tests were green:
- Protected routes, no session:
curl -s -o /dev/null -w '%{http_code} %{size_download}\n' <url>. A redirect with a large body is a data leak. - Each guarded endpoint, both ends: rejected without the credential and accepted with it. A 403 alone can be a typo.
- The database, with the public key: read each non-public table; write to a row you do not own. On Supabase, InsForge or any Postgres + auto-API backend, run
rls-audit. - Secrets in the wrong files: scan
docs/,*.md,*.jsonexports and the git history — not only source. - Environment variables: pull production and grep for trailing newlines (see
deployment). - Headers: CSP without
'unsafe-inline'inscript-src, HSTS,frame-ancestors. Then confirm analytics still records. - Legal and policy pages: return 200 on the live domain.
- Shared demo account: try to spend money and to write through the API, not through the UI.
Record what you ran and what came back. A check nobody can re-run is an opinion.
Step 3 — Risk gate (escalate when needed)
Based on Discovery answer 1, decide whether a deeper review is required — and be explicit that deep auditing is out of this plugin's scope on purpose:
- Handles money, PII at scale, health data, or crypto/keys → recommend a deep audit before or shortly after launch, and point to specialized tooling:
- Static analysis: Semgrep / CodeQL (e.g. the
static-analysisor Trail of Bits skills). - Dependency / supply-chain: Dependabot, Snyk, supply-chain auditors.
- Fuzzing: only if there's parsing, crypto, or native code — AFL++, libFuzzer (the testing-handbook skills). Not relevant to a typical CRUD SaaS.
- Static analysis: Semgrep / CodeQL (e.g. the
- Money, auth, user data or deploys were touched and nobody outside the agent confirmed the result → the
proof-firstplugin (/plugin marketplace add MartinOlivero/proof-first) sends a clean-context verifier to gather evidence observable from outside and records it. Optional; without it, do Step 2b by hand. - Standard low-risk CRUD SaaS → the checks above are a reasonable bar for launch. Say so honestly: this is a review, not a guarantee.
Legal exposure
If the product has users or a legal entity in Argentina, the EU, the US, Brazil or the UK, run the legal-docs plugin (/plugin marketplace add MartinOlivero/saas-legal-docs) in audit
mode before shipping. Two obligations from 2025 that almost no product has implemented yet,
because they are newer than most templates:
- Botón de arrepentimiento and botón de baja de servicio (Disposición 954/2025) — both required "a simple vista, en lugar destacado y en el primer acceso", with no prior login. A link in the footer no longer satisfies this.
- Any provider outside the AAIP adequacy list (the US is not on it) needs the international transfer declared with a legal basis.
That skill also compares the published legal text against the actual code, which catches the worst class of problem: a policy promising encryption, deletion or "we don't share data" that the codebase contradicts.
Output
Deliver: the scan results (audit + secrets), a pass/fail list against the checklist with the exact file:line of anything to fix, and a clear verdict — "safe to ship at this risk level", "fix these N items first", or "high-risk: get a deep audit". Never claim the app is fully secure.
Reference
OWASP Cheat Sheet Series (~29k⭐), npm audit, gitleaks (~18k⭐), Helmet. Escalation targets: Semgrep/CodeQL, Trail of Bits skills, testing-handbook (fuzzing), Snyk/Dependabot.


