The 12-class checklist
for vibe-coded SaaS.
Twelve vulnerability classes I find over and over in AI-generated SaaS. Each one is grounded in a confirmed finding from real research — not theory, not OWASP boilerplate. The taxonomy is public; the hunt protocols, fingerprinting signatures, and remediation diffs are part of the audit.
-
auth tier mismatch
Authorization-tier mismatch
Plan, quota, role, or ownership constraint enforced in the app layer but missing from the data layer (Supabase RLS, ORM policy, row scoping). The API rejects; the database doesn't.
Real exampleOutrank F1 — 30-articles-per-month plan limit enforced in Next.js, missing from Supabase RLS. 35 INSERTs in one run, all succeeded.
-
oauth state forgery
OAuth / connector flaws
Unauthenticated OAuth init or callback. Unsigned state parameters. Missing org-binding when persisting third-party tokens. The canonical Stack Overflow snippet assumes single-tenancy; multi-tenant apps inherit the assumption silently.
Real exampleOutrank F4 — unauthenticated cross-account Notion integration injection via unsigned OAuth state.
-
unauth endpoint leak
Unauth API endpoints leaking data or config
Routes the developer thought were protected, but middleware doesn't cover. Free recon turns into free findings. Sub-patterns: credential over-disclosure on authenticated endpoints, and credentials accepted as URL path parameters.
Real exampleOutrank F2/F3 — unauthenticated subscription and integrations endpoints.
-
agent ssrf
SSRF via fetch features
URL-accepting features (link previews, importers, summarisers, screenshot services) that pass user input to a server-side fetch. Naive IP blocklists fall to DNS rebinding and redirect chains.
Real exampleParakeetAI — SSRF via DNS rebinding to internal metadata. Embargoed writeup; published August 2026.
-
cors null + creds
CORS null / echoed origin with credentials
Access-Control-Allow-Origin: null(or echoed-origin) combined withAccess-Control-Allow-Credentials: true. Sandboxed iframes attack cleanly. "Allow CORS from anywhere" requested casually; emitted dangerously.Real exampleParakeetAI. Embargoed writeup; published August 2026.
-
toctou on creation
TOCTOU / race conditions on creation flows
Quota check happens before the write, not as an atomic transaction. Twenty concurrent requests pass the check before any of them complete. Correct in single-threaded code, broken under load.
Real exampleParakeetAI. Embargoed writeup; published August 2026.
-
sse tool-call inject
Response stream / tool-call integrity gaps
AI features stream SSE responses from the model to the client. The client trusts every event in the stream. A network attacker forges events — including tool calls that execute code — and the client acts on them with no signature check, no sandbox, no approval prompt.
Real exampleClicky F-05 — unauthenticated RCE on a macOS AI assistant via forged
exec_commandtool call in the OpenAI Responses stream. -
jwt confused-deputy
JWT confused-deputy / cross-purpose token reuse
One JWT secret signs tokens for many distinct purposes — session, invite, webhook callback, integration credential, enterprise control. No
audorpurposeclaim binds a token to its intended use. A token minted for one path verifies cleanly when replayed on another. Compounds when the auth middleware trusts JWT body fields without re-resolving the user from the database.Real examplePostiz F1 — one Skool cookie became SUPERADMIN on api.postiz.com (CVE-2026-48781).
-
key reuse + static iv
Cryptographic key reuse + static-IV ciphers
At-rest encryption keyed off the same secret as JWT signing, with a fixed IV derived from that secret. Same plaintext → same ciphertext (leaks equality). Single secret compromise decrypts every stored credential AND forges every session.
Real exampleObserved during the Postiz audit. This specific sub-finding remains unaddressed in v2.21.8 — full detail held back pending vendor remediation.
-
default secrets
Default secrets in distributed config
docker-compose.yaml,.env.example, or onboarding script ships with a literal default value for a secret. Self-hosters who don't override it run with a publicly known key. No startup check refuses the default.Real exampleObserved during the Postiz audit. This specific sub-finding remains unaddressed in v2.21.8 — full detail held back pending vendor remediation.
-
secret reveal endpoint
Per-tenant secret reveal endpoints
A high-value secret — per-tenant JWT signing key, webhook signing secret, encryption key, API key — is retrievable in plaintext from a dashboard endpoint on every call, instead of being shown once at creation. Pair this with a sibling
POSTthat silently rotates the secret with no confirmation, and any org member becomes a DoS primitive against every downstream consumer of that key until they redeploy with the new value.Real exampleObserved during a 2026 audit on a helpdesk SaaS —
GET /admin/helpdesk/jwt-secret/revealreturned the customer-side JWT signing secret as plaintext on every call, and the unauthenticated rotation endpoint accepted an emptyPOST. Embargoed pending disclosure. -
agent task injection
Autonomous AI agent task creation as prompt-injection surface
Product exposes an endpoint that creates an autonomous AI agent task with user-controlled prompt or description. The agent has access to organization context and an unenumerated tool inventory (
fetch_url,search_org_data,post_to_slack, …). Prompt injection in the task description becomes a remote-execution primitive — SSRF, cross-tenant data read, outbound action via tool calls, system-prompt exfiltration — all driven by natural language from any user who can mint a task.Real exampleObserved during a 2026 audit on an AI helpdesk product —
POST /admin/tasks/create-agent-taskaccepted adescriptionfield that the agent executed verbatim, with no separation between user-controlled input and the system prompt. Embargoed pending disclosure.
The depth
The hunt protocols are the audit.
- Fingerprinting
- How I identify a target with each class — before testing.
- Hunt protocol
- Step-by-step procedure to confirm or exclude.
- Remediation diff
- Copy-pasteable fix, scoped to your stack.
- Where it lives
- Inside the engagement — not on this page.