
Api Audit
- 140 installs
- 341 repo stars
- Updated May 27, 2026
- briiirussell/cybersecurity-skills
API Audit is a Claude skill that audits REST, GraphQL, and RPC APIs against the OWASP API Security Top 10 (2023).
About
API Audit performs a systematic security audit of REST, GraphQL, and RPC APIs against the OWASP API Security Top 10 (2023). A developer uses it to review every endpoint for broken object-level authorization, broken authentication, excessive data exposure, mass assignment, resource-consumption limits, and SSRF. It is surface-driven over the API contract with specific grep patterns and bypass checks per category.
- Endpoint-by-endpoint pass over the OWASP API Security Top 10 (2023)
- Concrete grep patterns for BOLA, mass assignment, and SSRF
- Surface-driven over the API contract, complementing a whole-codebase audit
Api Audit by the numbers
- 140 all-time installs (skills.sh)
- Ranked #918 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
api-audit capabilities & compatibility
- Capabilities
- api security audit · security audit · code review · vulnerability scan
- Use cases
- security audit · code review · api development
What api-audit says it does
Perform a systematic security audit of API endpoints against the OWASP API Security Top 10 (2023).
The #1 API vulnerability by exploitation frequency. Every endpoint that accepts an object ID needs an explicit ownership check
UUIDs are not access control. Sequential IDs make enumeration trivial; UUIDs only slow it down
npx skills add https://github.com/briiirussell/cybersecurity-skills --skill api-auditAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 140 |
|---|---|
| repo stars | ★ 341 |
| Last updated | May 27, 2026 |
| Repository | briiirussell/cybersecurity-skills ↗ |
What it does
Audit REST, GraphQL, and RPC API endpoints against the OWASP API Security Top 10 for authorization and exposure flaws.
Who is it for?
A focused security pass over every API endpoint with API-specific bypass patterns
Skip if: A category-driven audit over a whole codebase (use owasp-audit)
When should I use this skill?
the user mentions API security, BOLA, BFLA, mass assignment, GraphQL security, or reviewing endpoints for weaknesses
What you get
A per-endpoint list of authorization, authentication, and exposure findings mapped to OWASP API categories.
- per-endpoint API security findings against the OWASP API Top 10
By the numbers
- Covers the OWASP API Security Top 10 (2023)
- BOLA is the #1 API vulnerability by exploitation frequency
Files
API Audit — REST / GraphQL / RPC Security Review
Perform a systematic security audit of API endpoints against the OWASP API Security Top 10 (2023). Distinct from owasp-audit — that's category-driven over a whole codebase, this is surface-driven over the API contract.
Use owasp-audit for the codebase as a whole. Use this when you need a focused pass over every endpoint with API-specific bypass patterns. They cross-reference each other where categories overlap.
Scope the Audit
1. Inventory every API surface — REST routes, GraphQL resolvers, tRPC procedures, gRPC services, Server Actions, webhook handlers, internal RPC 2. Identify auth model — JWT, session cookies, API keys, mTLS, OAuth scopes 3. Identify the tenancy model — single-tenant, multi-tenant, row-level isolation 4. Map sensitive resources — user data, payments, files, admin functions
Audit Checklist
API1: Broken Object Level Authorization (BOLA)
The #1 API vulnerability by exploitation frequency. Every endpoint that accepts an object ID needs an explicit ownership check before reading or mutating.
- For each route that takes an ID parameter (
/users/:id,/orders/:id,/projects/:id), verify a query likefindFirst({ where: { id, userId } })runs before any data access — notfindById(id)then a separate check - ORM relation traversal:
posts.find(id).user.creditCardreturns another tenant's card if the relation isn't guarded. Audit every.include,.with,includes, eager-loaded relation - UUIDs are not access control. Sequential IDs make enumeration trivial; UUIDs only slow it down
- Predictable surrogate keys (slugs, public_ids) used as if they were unguessable
- Grep for:
params.id,req.params.<id>,formData.get("<id>"), ORM.findById(/.find(without awhereclause, GraphQL resolvers that take anidarg and call.findUnique
API2: Broken Authentication
- JWT with
alg: noneaccepted by the verifier - JWT secret comparison without
crypto.timingSafeEqual/ equivalent - Refresh tokens that never rotate or have no revocation list
- Password reset that returns a token in the response body instead of mailing it
- API keys passed in URL query string (logged everywhere — access logs, CDN, proxies)
- Bearer-token compare against
process.env.Xwithout a presence check — when X is unset,"Bearer ${undefined}"is a valid literal - Grep for:
jwt.verify,jsonwebtoken,Bearer ${process.env,jwt.decode(without verify),verify.*alg
API3: Broken Object Property Level Authorization (BOPLA / BFLA / Excessive Data Exposure)
- API returns the whole DB row instead of a curated DTO —
res.json(user)leakspassword_hash,stripe_customer_id, internal flags - Admin-only fields (role, is_verified, tenant_id) accepted on update endpoints from regular users — mass assignment
- GraphQL exposes admin-mutation fields without role-based field-level auth —
mutation UpdateUser($id, $role)succeeds because the resolver only checks "is the user logged in" - Grep for:
res.json(<entity>)without explicit field projection,Object.assign(record, req.body), MongoosefindByIdAndUpdate(id, req.body), Drizzle.update().set(req.body), Sequelizeupdate(req.body), GraphQL resolvers without role checks
API4: Unrestricted Resource Consumption
- No rate limit on auth endpoints (login, signup, password-reset, SMS-send, email-verify)
- No per-tenant quota on expensive operations (LLM calls, search, file processing, webhook fan-out)
- Page size unbounded —
?limit=10000000returns 10M rows - GraphQL query depth not capped —
user { posts { user { posts { ... } } } }runs forever - GraphQL query complexity not analyzed — single query that triggers N+1 against 100M rows
- Webhook handlers that re-trigger expensive work without idempotency
API5: Broken Function Level Authorization (BFLA)
- Auth check on the route but not on the handler — wildcard middleware misses a manually-mounted route
- "Admin-ish" endpoints reachable by changing
POST /api/v1/users/metoPOST /api/v1/users/<other_id> - HTTP verb tampering —
DELETE /admin/users/123blocked, butPOST /admin/users/123/deletesucceeds - Conditional auth based on
req.user.role === "admin"where role is set from a header the client controls - Sister-route gaps —
PUT /:idis guarded butPOST /:id/sendwrites the same row without the guard. Run sister-route audit (seeowasp-audit) - Grep for: every route handler — does it call an auth check explicitly, or rely on something upstream that may or may not match this route's path?
API6: Unrestricted Access to Sensitive Business Flows
- Endpoint allows automation that bypasses business intent — buying limited stock 1000× per second, reserving every seat in a venue, brute-forcing referral codes
- No CAPTCHA / proof-of-work / device fingerprint on flows that have business-rate constraints (signup, coupon redemption, vote, like)
- Anti-automation checks only on UI, not on the API
API7: Server-Side Request Forgery (SSRF)
- User-controlled URLs passed to server-side fetch — webhook URLs, image-fetch, SSO callback, PDF render, OG-scrape, link unfurling
- Allow-list checks only the hostname — see
owasp-auditA10 for the full bypass matrix (9+ patterns including IPv4-mapped IPv6, trailing-dot, cloud metadata, encoded IPs) redirect: "follow"(default) on fetches with user-controlled URLs lets an attacker bounce through a 302 into the metadata service- Webhook delivery from your domain to attacker URL — your server's IP is now their proxy
API8: Security Misconfiguration
- CORS
Access-Control-Allow-Origin: *combined withAllow-Credentials: true(browsers refuse this; servers shouldn't ship it) - CORS reflection of the
Originheader without an allow-list — any origin gets allowed - Verbose error responses leaking stack traces, query strings, internal IDs
- Default OpenAPI / GraphQL introspection exposed in production with full schema
- Missing security headers — see
owasp-auditA05 for the full baseline values - HTTP-only flag missing on session cookies
API9: Improper Inventory Management
- Old API versions (
/v1/) still live and unpatched alongside/v2/— attackers prefer the version with fewer checks - "Internal" / "staging" endpoints reachable from the internet (deploy-preview URLs,
*-staging.fly.devleft open) - Undocumented endpoints — every endpoint should appear in the OpenAPI spec / type-generated client; orphans are an audit signal
- Auto-generated debug endpoints —
/__debug,/__db,/.well-known/internal/, framework-default routes - Grep for:
app.get,router.get,pages/api/,app/api/directory contents; reconcile against the published API contract
API10: Unsafe Consumption of APIs
- Your service calls a third-party API and trusts the response without validation — open redirect via
provider.user.profile_url, XSS viaprovider.user.biorendered un-escaped - Server-to-server calls without integrity check (signed JWT, mTLS, HMAC) — anyone who can reach the upstream URL can pretend to be the upstream
- Caching upstream errors as success — a 200 with a JSON error body cached as data
GraphQL-specific
- Introspection enabled in production (
__schema,__typequeries return the full schema) - Field-level authorization missing — resolvers check "is this query allowed" but not "is this field allowed for this user"
- Query depth + complexity limits absent
- Batching abuse — single HTTP request containing 1000 queries each costing 100ms
- Error messages reveal internal field paths the user shouldn't know exist
REST-specific
- HTTP verbs not enforced —
GETaccepted on state-changing endpoints (CSRF risk + cache poisoning) - Content-Type assumptions — handler expects
application/jsonbut acceptsapplication/x-www-form-urlencodedand parses inconsistently - Path traversal in resource IDs —
/files/../../etc/passwd
Webhook handler-specific
- Signature verification missing or bypassable (see
owasp-auditA02 type-coercion + A04 multi-tenant signature N-way matching) - Replay attack — no timestamp tolerance or nonce check
- Endpoint exists at a predictable path (
/webhooks/stripe) without IP allow-list or signature
Verify Fixes at Runtime
- For BOLA fixes: actually authenticate as user A and request user B's resource; observe 404, not 200
- For mass-assignment fixes: send the request with the extra field set; observe the field is ignored or rejected
- For rate-limit fixes: hit the endpoint at 10× the configured rate; observe 429 not 200
- For CORS fixes: send the request with
Origin: https://evil.com; observe the browser blocks, not the server
tsc --noEmit + build success ≠ fix verified. See also owasp-audit's Verify Fixes at Runtime + Second-Opinion Pass — same playbook applies.
Report Format
Findings have three dispositions (Fixed / Deferred / Accepted Risk) per the owasp-audit convention. For every finding:
#### [SEVERITY] APIN: [Title]
**Endpoint:** `METHOD /path/to/endpoint`
**Handler:** `path/to/handler.ts:42`
**CWE:** CWE-XXX
**Description:** [What the vulnerability is]
**Proof of concept:**[curl / request showing the bypass]
**Vulnerable Code:**
[snippet]
**Remediation:**
[fixed snippet]
**Verification:** [Concrete adversarial input and the observed response that proves the fix holds]Produce an executive summary grouped by API category, plus an inventory of every endpoint with one of:
- Audited — clean (with what was checked)
- Audited — N findings (with severities)
- N/A (with reason — e.g. health-check endpoint with no auth surface)
Boundaries
- Only audit APIs the user provides or points you to
- Provide remediation, not exploits — for proof-of-concept, generate the minimum request that demonstrates the issue, not a weaponized payload
- Flag low-confidence findings as "Potential" rather than confirmed
- Never run a BOLA proof-of-concept against a live production endpoint without explicit written authorization — read the code, then propose how to verify in a test environment
- Refuse mass-scanning, credential-stuffing, or any active abuse-flow exploitation
References
- OWASP API Security Top 10 (2023)
- OWASP Cheat Sheet: REST Security
- OWASP Cheat Sheet: GraphQL Security
- CWE-639 (Authorization Bypass Through User-Controlled Key)
- CWE-915 (Improperly Controlled Modification of Dynamically-Determined Object Attributes)
Related skills
FAQ
How does it differ from owasp-audit?
owasp-audit is category-driven over a whole codebase; this is surface-driven over the API contract with API-specific bypass patterns, and they cross-reference each other.
What is the top API vulnerability it checks?
Broken Object Level Authorization (BOLA), the number-one API vulnerability by exploitation frequency, requiring an ownership check on every endpoint that accepts an object ID.