OWASP API Top 10 for HTTP, GraphQL, and gRPC endpoints: input validation, route rate limiting, mass assignment, response caching, and gateway-versus-service control placement. Use when generating or reviewing HTTP handlers, GraphQL resolvers, gRPC service methods, or any API endpoint change.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add ShieldNet-360/secure-vibe --skill api-security --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Api Security?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/shieldnet-360-api-security)More formats (shields.io, HTML) on the badges page.
---
name: api-security
description: "OWASP API Top 10 for HTTP, GraphQL, and gRPC endpoints: input validation, route rate limiting, mass assignment, response caching, and gateway-versus-service control placement. Use when generating or reviewing HTTP handlers, GraphQL resolvers, gRPC service methods, or any API endpoint change."
---
<!-- Native skill bundle for agent-skills (cross-tool convention). Generated by `secure-vibe dev regenerate`. -->
<!-- Do not edit by hand; the source of truth is skills/api-security/SKILL.md. -->
# API Security
OWASP API Top 10 for HTTP, GraphQL, and gRPC endpoints: input validation, route rate limiting, mass assignment, response caching, and gateway-versus-service control placement. Use when generating or reviewing HTTP handlers, GraphQL resolvers, gRPC service methods, or any API endpoint change.
## ALWAYS
- Require authentication on every non-public endpoint. Default to authenticated; opt out for genuinely public routes by explicit annotation.
- Consult `auth-security` for **who the caller is and what they may touch**. It owns the credential (algorithm pinning, expiry, lifetime, session, CSRF) and the permission (object-level BOLA/IDOR checks, multi-key routes, streaming subjects, function-level role gating). Any endpoint that reads or writes a resource by id needs it; this skill covers everything else about the endpoint.
- Validate all request inputs against an explicit schema (JSON Schema, Pydantic, Zod, validator/v10 struct tags). Reject early; never propagate untrusted input deeper.
- Enforce rate limits at the route level for authentication endpoints, password reset, and any expensive operation.
- Consult `error-handling-security` for what an error response may carry. It owns the boundary between what crosses to the client and what stays in the log, including presence-of-record disclosure (`User not found` vs `Invalid credentials`).
- Include `Cache-Control: no-store` on responses containing personal or sensitive data.
## NEVER
- Use sequential integer IDs in URLs for resources accessible across tenants. Use UUIDs or unguessable opaque IDs.
- Mass-assign request bodies directly to ORM models (`User(**request.json)`) — this enables privilege escalation when the model has admin fields the user shouldn't control.
- Key a rate-limit / lockout counter on a **client-controllable header** (leftmost `X-Forwarded-For`, `X-Real-IP`, `Forwarded`) — rotating it yields a fresh bucket per request and defeats the limit. Derive the client IP from the trusted-proxy hop count (or key on the authenticated user), and fail closed on limiter error.
- Use `HTTP GET` for any state-changing operation — GET should be safe and idempotent.
- Rely on **network position** (IP allowlist, VPN, private subnet, "internal only", a WAF/edge rule) as the *only* control on a sensitive endpoint. Reachability is not authentication: the moment there's an SSRF, a compromised internal host, a tenant on the network, or a boundary change, an unauthenticated "internal" endpoint (`permission_classes = [AllowAny]`, no `RequireAuth`) is wide open. Enforce auth/authz at the service itself, behind any network control.
- Place security controls (auth, field-stripping, CSRF, rate-limit, input validation) only at a gateway / BFF / proxy while the backend service is **also directly reachable**. An attacker calls the service directly and bypasses every proxy-layer control — controls must live at the service that owns the data. (A common variant: the gateway checks that a JWT is *present* but the service never checks the caller's *role* or *object-level ownership* — the service reads the subject id from the body/path/query and trusts it.)
## KNOWN FALSE POSITIVES
- Public marketing-site endpoints serving anonymous traffic legitimately have no auth and no rate limits beyond the load balancer.
- Sequential IDs in paths are fine for genuinely public, non-tenant-scoped resources (e.g. blog post slugs, public product catalog items).
- Health-check endpoints (`/healthz`, `/ready`) intentionally bypass auth.
- A network control (mTLS service mesh, NetworkPolicy, private ingress) is fine as **defense-in-depth** — the anti-pattern is only when it's the *sole* control and the service itself authenticates nothing.
- Mutual-TLS / SPIFFE workload identity between services **is** authentication (a cryptographic caller identity), not mere network position — mTLS-authenticated service-to-service calls are fine even on a private network.
## Reference files
Read these only when the task calls for them.
- `references/verifying-findings.md`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!