agentsclimarketplace

Api security

Skill ShieldNet-360/secure-vibe/skills/api-security

SecureVibe — prevention-first security for AI-written code. Signed SKILL.md knowledge that makes AI coding assistants write secure code at generation time, plus a deterministic CI gate. Offline · keyless · Ed25519-signed. By ShieldNet360.

Install
npx -y skills add ShieldNet-360/secure-vibe --skill api-security

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Apply OWASP API Top 10 patterns to authentication, authorization, and input validation

SKILL.md

9.3 KB, as published. Nobody here has run it

API Security

Rules (for AI agents)

ALWAYS

  • Require authentication on every non-public endpoint. Default to authenticated; opt out for genuinely public routes by explicit annotation.
  • Apply authorization at the object level — confirm the authenticated subject actually has access to the requested resource ID, not just that they're logged in (defeats the OWASP API1 BOLA / IDOR class).
  • Bind object-level authz to the gateway-authenticated principal, never to an actor id echoed in the request: a check that a request-supplied senderId/ownerId/actedBy is a valid member validates the claimed actor, not the caller (looks like authz, isn't).
  • On /{scopeId}/.../{subjectId} routes, authorize the relationship — confirm the subject belongs to that scope; a caller-vs-scope check alone does not authorize the subject (multi-key BOLA).
  • Authorize each subject on streaming responses (SSE/chunked/WebSocket): the 200 is committed before the handler runs, so an empty/filtered stream — not a 4xx — is the deny signal; an unauthorized subject gets zero events.
  • 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.
  • Use short-lived access tokens (≤ 1 hour) with refresh tokens, not long-lived bearer tokens.
  • Return generic error messages externally (invalid credentials) and log specifics internally — avoid leaking which of username/password was wrong.
  • 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.
  • Trust Authorization headers without verifying the signature and expiration.
  • Accept none algorithm JWTs. Pin the expected algorithm at verification time.
  • 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.
  • Act on a subject/owner id asserted by an upstream producer (queue/topic/webhook) without authenticating the channel and re-validating the asserted subject — a spoofed producer otherwise drives forged cross-tenant effects.
  • 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.
  • Disable CSRF protection on state-changing endpoints used by browsers.
  • Return stack traces or framework error pages to the client in production.
  • 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.)
  • Gate a write / create endpoint on authentication only when the created resource is rendered to all users or tenants (a global gallery, shared catalog, public template list). Authentication is not authorization: enforce a function-level role / privilege check on any write that publishes into a shared or global namespace (OWASP API5 — Broken Function Level Authorization). A low-privilege user posting into a globally-visible store is a delivery vector for stored-XSS / malicious-link chains.

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.
  • A write into the caller's own private / tenant-scoped namespace needs only authentication + object-level ownership — function-level role gating applies specifically to writes whose result becomes visible beyond the creator.

Context (for humans)

The OWASP API Top 10 differs from the web Top 10 mostly because APIs have weaker defaults: they often skip CSRF, they expose object IDs directly, and they tend to trust developer-provided client-side state. This skill codifies the most common high-impact mistakes.

A recurring architectural failure is trusting the perimeter instead of the service: a BFF/gateway enforces auth, strips fields, and checks CSRF, while the core service is also directly reachable and authenticates nothing because it's "internal". Anyone who can reach the core service — via SSRF, a foothold inside the allowlisted network, or simply a public DNS name that resolves to the same backend — bypasses every perimeter control. Network position is a mitigation, not an authentication boundary; the owning service must enforce auth/authz itself.

Verify & lock (triaging a finding)

A scanner/review hit is a candidate, not a confirmed bug. Confirm it, fix it, then lock it so it can't come back.

  1. Confirm it's real (probe the suspect input). Replay the endpoint as an attacker would. BOLA/IDOR: authenticate as user A, request user B's resource ID (GET /orders/{B_id}) — a real hit returns B's data or 200; a false positive returns 403/404. Broken auth: call the endpoint with no token, an expired token, and a none/wrong-alg JWT — acceptance is a real hit. Mass assignment: POST/PATCH with an extra privileged field ({"role":"admin","is_verified":true}) and re-read the object — if the field stuck, it's real. Rate-limit: fire N rapid auth/reset requests; absence of 429 after the threshold confirms it. Perimeter trust: hit the backend service directly (bypassing the gateway) — a 200 without auth confirms the control lives only at the proxy. Streaming authz: subscribe to another tenant's subject id over SSE/WebSocket — a real hit streams their events or replays their last state, while a fixed endpoint yields an empty stream (the 200 alone proves nothing). Claimed-actor: send a state-changing call whose body names a different actor id than your principal — a 2xx with the effect applied confirms the handler trusts request-supplied identity rather than the caller.
  2. Fix, then lock with a regression test (unit or integration — dev's call): assert the attack input now yields the secure outcome (cross-tenant ID → 403/404; forged/expired/none-alg token → 401; unknown privileged field → ignored or rejected, never persisted; over-threshold burst → 429; direct-to-service call → auth enforced), AND that a legitimate request (owner reading own resource, valid token, allowed fields) still succeeds. Commit it to CI so the guard can't be silently dropped in a later refactor.

References

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.