Claude Code security checklist for quick web app spot-checks
Use a Claude Code security checklist to run fast, concrete spot-checks on auth, input validation, secrets handling, and injection surfaces in web apps.

What a lightweight security spot-check is
A lightweight security spot-check is a fast review (often 30-60 minutes) meant to catch obvious, high-impact problems before they ship. It’s not a full audit. Think of it like a safety walk-through: you scan the paths that fail most often in real apps and look for proof, not guesses.
This Claude Code security checklist focuses on the areas that break most often in everyday web apps:
- Authentication assumptions (how you know who the user is)
- Authorization gaps (what they’re allowed to do)
- Input validation
- Secrets handling
- Common injection surfaces (SQL, command execution, template rendering, redirects, uploads)
It does not try to prove the absence of bugs, model complex threat actors, or replace penetration testing.
“Concrete findings” means every issue you record has evidence a developer can act on immediately. For each finding, capture:
- The exact file(s) and function/handler name
- The risky behavior in one sentence
- A minimal repro step (request, payload, or click path)
- Why it matters (impact) and who can trigger it
- A safe fix direction (not a full rewrite)
AI is a helper, not an authority. Use it to search, summarize, and propose tests. Then verify by reading the code and, when possible, reproducing with a real request. If the model can’t point to specific locations and steps, treat the claim as unproven.
Set scope in 10 minutes
A fast review only works if you narrow the target. Before you ask Claude Code to look at anything, decide what you’re trying to prove today and what you’re not checking.
Start with 1 to 3 real user journeys where mistakes cost money, expose data, or grant power. Good candidates are login, password reset, checkout, and admin edit screens.
Next, name the assets you must protect. Be specific: user accounts, payment actions, personal data, admin-only operations.
Then write down your threat assumptions in plain words. Are you defending against a curious user clicking around, an external attacker with scripts, or an insider with some access? Your answer changes what “good enough” looks like.
Finally, define pass and fail so your spot-check ends with findings, not vibes. Simple rules work well:
- Pass: every sensitive action shows an explicit authn and authz check.
- Fail: any endpoint trusts the client for user ID or role.
- Pass: inputs are validated server-side, not just in the UI.
- Fail: secrets appear in logs, configs, or client code.
If you can’t describe what failure looks like, the scope is still too fuzzy.
Prep the context you give Claude Code
A spot-check only works if the model is looking at the right places. Gather a small bundle of code and notes so the review can produce evidence, not guesses.
Start by sharing the security-critical path: request entry points and the code that decides who the user is and what they can do. Include just enough surrounding code to show how data flows.
A practical bundle usually includes:
- Auth entry: session/JWT parsing, cookie settings, login callbacks, auth middleware
- Routes + handlers: controllers, RPC methods, GraphQL resolvers, background job handlers
- Data layer: ORM queries, raw SQL helpers, query builders, migrations for sensitive tables
- Policy checks: role checks, ownership checks, feature flags, admin-only endpoints
- Validation: request schema validators, file upload handlers, deserialization code
Add a few lines of environment notes so assumptions are explicit: session vs JWT, where tokens live (cookie or header), reverse proxy or API gateway behavior, queues/cron workers, and any “internal-only” endpoints.
Before chasing bugs, ask for an inventory: entry points, privileged endpoints, and data stores touched. This prevents missed surfaces.
Also agree on an output format that forces concrete findings. A simple table works well: Finding, Severity, Affected endpoint/file, Evidence (exact snippet or line range), Exploit scenario, Fix suggestion.
Step-by-step workflow for a 30-60 minute review
Timebox it:
- 10 minutes to orient
- 15-30 minutes to trace flows
- 10 minutes to write up
The goal isn’t perfect coverage. It’s a small set of testable findings.
Keep the app open while you read. Click through the UI and watch what requests fire. Notes should point to specific endpoints, parameters, and data sources.
A workflow that fits in one sitting:
- Sketch entry points and trust boundaries. Note public routes, logged-in routes, admin routes, webhooks, uploads, and third-party callbacks. Mark where data crosses from user-controlled to server-trusted.
- For each important endpoint, write down what proves identity and where it happens. If the check is “middleware,” confirm every route actually uses it.
- Do the same for authorization. Pick one risky action (view other users’ data, update roles, export, delete) and trace the permission decision all the way to the database query.
- Trace user input to sinks. Follow one parameter from request to SQL/ORM queries, template rendering, command execution, URL fetches (SSRF), redirects, and file paths.
- Scan secret and config flows while you trace. Look for tokens in logs, client-side code, error messages, environment dumps, and weak storage patterns.
A useful habit: for every “seems fine,” write what you would do to break it. If you can’t describe a breaking attempt, you probably haven’t verified it.
Authn spot-checks: prove who the user is
Authentication is where the app decides, “this request belongs to this person.” A quick spot-check isn’t about reading every line. It’s about finding the place identity is established, then checking the shortcuts and failure paths.
Locate the trust boundary: where does identity first get created or accepted? It might be a session cookie, a JWT bearer token, an API key, or mTLS at the edge. Ask Claude Code to point to the exact file and function that turns “anonymous” into a user id, and to list every other path that can do the same.
Authn checks worth scanning:
- Identify all auth entry points (web login, API tokens, mobile auth, internal service auth) and confirm they converge on one consistent identity model.
- Check login and password reset for rate limits, lockouts, and user enumeration (different error messages or timing for existing vs non-existing accounts).
- Inspect session and cookies: HttpOnly, Secure, SameSite, expiry, rotation on login and privilege change, and logout invalidation (server-side, not just “delete cookie”).
- Review MFA and recovery so the recovery path isn’t weaker than MFA (for example, email-only reset that bypasses MFA).
- Review auth failure logging: useful for ops, but don’t leak details that help attackers (no “user exists” hints, no token dumps).
A practical example: if reset emails return “account not found,” that’s a fast enumeration issue. Even with a generic message, timing differences can leak the same fact, so spot-check response timing too.
Authz spot-checks: prove the user is allowed
Authorization is the question that causes the most damage when it’s wrong: “Is this user allowed to do this action on this exact resource?” A fast spot-check should try to break that assumption on purpose.
Write roles and permissions in plain language. Keep it human:
- Owner can invite members
- Member can edit their own profile
- Support can view billing details but can’t change plan
- Admin can delete projects
Then verify every sensitive action enforces authz on the server, not just in the UI. Buttons can be hidden, routes can be blocked in the client, but an attacker can still call the API directly.
A quick scan that usually finds real issues:
- Find endpoints/mutations that create, delete, export, change roles, or access billing
- For each one, locate the server-side permission check (not the frontend)
- Look for user-controlled IDs (projectId, userId, orgId) and confirm ownership checks
- Confirm admin-only paths fail closed when role is missing
- Check tenant boundaries: orgId/accountId should come from session context, not only from request input
The classic IDOR smell is simple: a request like GET /projects/{id} where {id} is user-controlled, and the server loads it without verifying it belongs to the current user or tenant.
A prompt that forces a real answer:
“For this endpoint, show the exact code that decides access, and list the specific conditions that would allow a user from a different orgId to access it. If none, explain why with file and function names.”
Input validation: keep bad data out early
Most quick web app issues start with a gap: the app accepts input the developer didn’t expect. Treat “input” as anything a user or another system can influence, even if it feels harmless.
Start by naming the inputs for the endpoint you’re spot-checking:
- URL query and path values
- Request body fields (including nested JSON)
- Headers (auth headers, content type, forwarded IP)
- Cookies
- File uploads (name, size, type, metadata)
Validation should happen close to where data enters the app, not deep inside business logic. Check the basics: type (string vs number), max length, required vs optional, and format (email, UUID, date).
For known values like roles, status fields, or sort directions, prefer an allowlist. It’s harder to bypass than “block a few bad values.”
Also check error handling. If the app rejects input, don’t echo the raw value back in the response, logs, or UI. That’s how small validation bugs turn into data leaks or injection helpers.
A quick “bad input” mini-plan for risky endpoints (login, search, upload, admin actions):
- Overlong strings (10,000+ chars)
- Wrong types (array instead of string)
- Unexpected enum values
- Special characters that could change meaning
- Empty values for required fields
Example: a sort parameter that accepts any string can become a SQL fragment later. An allowlist like "date" or "price" prevents that class of mistake early.
Common injection surfaces to scan quickly
Most quick reviews find issues in the same few places: anywhere user input gets interpreted as code, a query, a path, or a URL. This section is where you hunt for “input crosses a trust boundary” moments.
Trace data from entry points (query params, headers, cookies, uploads, admin forms) to where it ends up.
Fast scan targets
Look for these patterns and require a concrete call site and payload example for each:
- SQL injection: string-built queries, dynamic
ORDER BY, andIN (...)builders that join user values - XSS: HTML rendering, templates, markdown previews, rich text editors where “sanitize later” is assumed
- Command injection: shell calls around image processing, PDF tools, backups, or “convert” steps that pass user-controlled flags
- SSRF: URL fetchers for webhooks, link previews, import-from-URL features, and internal status checks that accept a user URL
- Path traversal: file download endpoints, zip extraction, and upload pipelines that later read files back by name
Also watch for deserialization and template injection. Anything that parses user-provided JSON, YAML, or templated strings can hide risky behavior, especially when it supports custom types, expressions, or server-side rendering.
If a feature accepts a URL, a filename, or formatted text, assume it can be abused until you can prove otherwise with code paths and tests.
Secrets handling: find leaks and weak storage
Secrets problems are often loud once you know where to look. Focus on where secrets live and where they accidentally get copied.
Common places secrets show up:
- Environment variables and app config files
- CI output and build logs (including failed deploy logs)
- Client bundles and mobile builds (anything shipped to users)
- Debug endpoints, health pages, and admin tools
- Error pages, stack traces, and analytics events
Then force a concrete answer: if a secret is exposed today, what happens next? A good system has a rotation path (new key issued), revocation (old key disabled), and a way to redeploy quickly. If the answer is “we’d change it later,” treat that as a finding.
Least privilege is another fast win. Incidents get worse because keys are overpowered. Look for database users that can drop tables, third-party tokens that can manage accounts, or API keys shared across environments. Prefer one key per service, per environment, with the smallest set of permissions.
Quick spot-check prompts you can paste into Claude Code:
- “Search for hard-coded tokens, passwords, and private keys. List exact file paths and the string patterns you matched.”
- “Find any code that logs request headers, cookies, env vars, or full error objects. Show the log lines and what sensitive fields could appear.”
- “Check if secrets can end up in snapshots, exports, or build artifacts. Identify what gets captured and where it is stored.”
Finally, confirm guardrails: block secrets from source control (pre-commit/CI checks), and make sure backups or snapshots don’t include plain-text credentials. If your platform supports snapshots and rollback, verify secrets are injected at runtime, not baked into saved images.
Prompts that force concrete findings (copy-paste patterns)
Vague prompts get vague answers. Force the model to commit to evidence: exact locations, a trace you can follow, a repro you can run, and what would make the claim wrong.
Use one pattern at a time, then ask it to revise after you confirm or reject a detail.
- File-level evidence: “Search the repo for auth, sessions, tokens, and middleware. Name the exact files, functions, and line ranges involved. Quote the relevant snippets. If you cannot point to code, say ‘no evidence found’.”
- Trace from input to sink: “Pick one user-controlled input (header, query, body, cookie). Show the data flow step-by-step from entry point to where it is used (SQL, HTML, shell, template, redirect, file path). List each function in the chain.”
- Repro steps: “Give a minimal repro with curl (method, URL shape, headers, body). Include expected status code and a success/failure response example. State assumptions (roles, auth state).”
- False-positive control: “What would disprove this finding? List 2-3 checks: config flags, middleware order, allowlist validation, parameterized queries, framework escaping. If any are present, explain why risk changes.”
- Smallest safe fix + test: “Propose the smallest change that blocks the issue without breaking valid cases. Then write one test to add (name, intent, inputs, expected result). If there are tradeoffs, spell them out.”
If the output still feels fuzzy, pin it down:
“Answer only with: file path, function name, risky line, and one-sentence impact.”
A realistic example: turning a hunch into a verified issue
Profile update endpoints often hide access control bugs. Here’s a small case you can run through this checklist.
Scenario: an API endpoint updates a user profile:
PATCH /api/profile?accountId=123 with JSON like { "displayName": "Sam" }.
You ask Claude Code to find the handler, trace how accountId is used, and prove whether the server enforces ownership.
What shows up often:
- Authn: the request requires a session or token, so it looks protected.
- Authz: the handler trusts
accountIdfrom the query string and updates that account without checking it matches the logged-in user. - Input validation:
displayNameis trimmed, butaccountIdisn’t validated as an integer. - Injection surface: SQL is built with string concatenation like
"... WHERE account_id=" + accountId.
A good write-up is concrete:
- Severity: High (IDOR + possible SQL injection)
- Evidence: a request with a valid login changes another user when
accountIdis modified; SQL is built from untrusted input - Fix: ignore
accountIdfrom the client, use the authenticated user’s account id on the server; parameterize the query - Test: attempt to update another account and expect 403; reject non-numeric
accountId
After patching, re-check fast:
- Try the same request with a different
accountIdand confirm it fails. - Confirm logs show the server uses the authenticated id, not the query param.
- Confirm the query uses placeholders/params, not string building.
- Run one negative test for malformed input (letters, very large number).
Common traps that make spot-checks miss real issues
The fastest way to miss a vulnerability is to trust what the UI seems to enforce. A button that is hidden or disabled isn’t a permission check. If the server accepts the request anyway, anyone can replay it with a different user ID, a different role, or a direct API call.
Another common miss is a vague ask. “Do a security review” usually yields a generic report. A spot-check needs a tight scope (which endpoints, which roles, which data) and a strict output format (file name, function, risky line, minimal repro).
The same rule applies to AI output: don’t accept claims without pointers. If a finding doesn’t include a concrete code location and a step-by-step way to trigger it, treat it as unproven.
Quick ways spot-checks go off track
These traps show up again and again:
- Assuming “admin-only” because it’s an admin page, not because the server enforces it
- Asking for broad review results instead of “show me the exact request that bypasses X”
- Accepting “possible SQL injection” without the query construction point and input path
- Skipping less obvious entry points like webhooks, scheduled jobs, import tools, and internal admin actions
- Patching symptoms (adding a filter or regex) while the root cause is missing validation or missing authorization
If you catch yourself adding more filters after every new edge case, pause. The fix is usually earlier and simpler: validate inputs at the boundary, and make authorization checks explicit and centralized so every code path uses them.
Quick checks you can run before you ship
These don’t replace a full review, but they catch mistakes that slip in when everyone is tired. Keep them focused on what you can prove quickly: a request you can send, a page you can load, a log line you can find.
Five fast spot-checks that usually pay off:
- Authn friction: Try 10 bad logins in a row. Do you see rate limits, lockouts, or at least a slowdown? Can you tell if an email exists from error messages or timing?
- Authz by ID swap: Pick a real resource (order, invoice, profile). Change the ID in the URL, JSON body, or GraphQL variables. Do you get data that isn’t yours, even “just metadata”?
- Input guardrails: For key fields (email, name, search, file upload), try very long strings, weird Unicode, and unexpected types (number instead of string). Do you enforce length limits and allowlists where they matter?
- Secrets exposure: Search recent logs and client bundles for tokens, API keys, JWTs, or “Authorization: Bearer”. Check error pages too. “It was only in staging” often becomes “it shipped”.
- Injection surfaces: Look for string concatenation into SQL, filters, template rendering, shell commands, or redirect URLs. If input reaches one of these without strong validation, assume risk until proven otherwise.
Write down the top 3 fixes you can ship this week, not a wish list. Example: (1) add rate limiting to login and password reset, (2) enforce server-side ownership checks on the “get by id” endpoint, (3) cap input length and reject unexpected characters for the search field.
Next steps: make this checklist part of your build process
A spot-check only pays off if the results change what you ship. Treat this checklist as a small, repeatable build step, not a one-time rescue mission.
Turn every finding into a backlog item that’s hard to misunderstand:
- Fix: what will change in code or config
- Test: how you will prove it’s fixed (one request, one unit test, one QA step)
- Owner: one person accountable
- Target date: next release or a specific day
- Evidence: file/endpoint and the exact request or payload that showed the issue
Pick a cadence that matches your risk and team size. For many teams, every release is best. If releases are frequent, do a 30-60 minute review monthly and a shorter check before shipping.
Make it easier to repeat by creating a reusable prompt pack and a checklist template. Keep prompts focused on concrete outputs: show the route, the guard, the failing request, and the expected behavior. Store the pack where your team already works so it doesn’t get skipped.
If you build apps through chat, bake the checklist into planning. Add a short “security assumptions” note for authn/authz, inputs, and secrets, then run the spot-check right after the first working version.
Platforms like Koder.ai (koder.ai) can fit well with this habit because they let you iterate quickly while keeping review checkpoints. Using snapshots and rollback around risky changes makes it easier to ship security fixes without getting stuck when a change breaks behavior.
FAQ
What is a lightweight security spot-check?
A lightweight spot-check is a focused 30 to 60 minute review of the riskiest paths in an app. It looks for obvious, high-impact mistakes before release, but it does not replace a full audit or penetration test.
Which parts of my web app should I check first?
Start with one to three journeys where a mistake could expose data, move money, or grant extra access. Login, password reset, checkout, admin actions, and account settings are sensible places to start.
How do I get useful security findings from Claude Code?
Ask for exact file paths, function names, risky code, a minimal repro request, impact, and a small fix suggestion. Treat any claim without code pointers and a way to test it as unproven.
What is the difference between authentication and authorization?
Authentication proves who sent the request. Authorization proves that person may perform the requested action on that specific resource. An endpoint can require a valid login and still expose another user's data if it skips the ownership check.
How can I quickly test for an IDOR issue?
Change a resource ID in a request while signed in as a different user. For example, try another projectId, accountId, or order ID, then confirm the server returns 403 or only data from the current user's tenant.
What should server-side input validation check?
Validate data on the server as soon as it enters the app. Check type, required fields, length, format, and allowed values, then reject unexpected input before it reaches business logic or storage.
Where do injection bugs usually hide?
Search for user input flowing into SQL, HTML, shell commands, URLs, file paths, templates, and upload handlers. String-built SQL, unrestricted redirect URLs, and filenames used as paths deserve immediate attention.
How do I spot secret leaks before release?
Check config files, logs, error reports, client bundles, mobile builds, debug endpoints, CI output, exports, snapshots, and backups. Any secret sent to a browser or logged in plain text should be removed and rotated.
What are the fastest authentication checks to run?
Review cookie flags such as HttpOnly, Secure, SameSite, expiry, and session rotation after login or privilege changes. Also test repeated failed logins and password resets for rate limits, account enumeration, and weak recovery paths.
What should I do after finding a security issue?
Create a concrete fix, one test that proves it works, an owner, a target date, and the original evidence. Use snapshots and rollback around risky changes so the team can deploy a fix and recover quickly if behavior breaks.