agentsclimarketplace

Graphql security

Skill ShieldNet-360/secure-vibe/skills/graphql-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 graphql-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

Defend GraphQL APIs: depth/complexity limits, introspection in production, batching/aliasing abuse, field-level authorization, persisted queries

SKILL.md

6.8 KB, as published. Nobody here has run it

GraphQL Security

Rules (for AI agents)

ALWAYS

  • Enforce a maximum query depth (typical: 7–10) and query complexity (cost) at the server. A 5-level nested query against a many-to-many relationship can return billions of nodes; without a cost limit, one client crashes the database.
  • Disable introspection in production. Introspection makes reconnaissance trivial; legitimate clients have the schema baked in via codegen or a .graphql artifact.
  • Use persisted queries (allowlisted operation hashes) for any high-traffic / public API. Anonymous arbitrary GraphQL is the GraphQL equivalent of eval(req.body).
  • Apply field-level authorization in resolvers, not just at the endpoint. GraphQL aggregates many fields into one HTTP response — a single missing @auth on a sensitive field leaks data across the whole query.
  • Limit the number of aliases per request (typical: 15) and the number of operations per batch (typical: 5). Apollo / Relay both allow batched queries — without limits this is an N-pages-of-the-API amplification primitive.
  • Reject circular fragment definitions early (most servers do, but custom executors don't). A self-referencing fragment causes exponential parse-time cost.
  • Return generic errors to clients (INTERNAL_SERVER_ERROR, UNAUTHORIZED) and route stack traces / SQL snippets to server logs only. Default Apollo errors leak schema and query internals.
  • Set a request size limit (typical: 100 KiB) and a request timeout (typical: 10 s) on the HTTP layer in front of the GraphQL server. A 1 MiB GraphQL query has no legitimate use.

NEVER

  • Expose /graphql introspection on a production endpoint. The GraphQL playground (GraphiQL, Apollo Sandbox) must also be disabled in production builds.
  • Trust the depth / complexity of a query because "our clients only send well-formed queries." Any attacker can hand-craft a request to /graphql.
  • Allow @skip(if: ...) / @include(if: ...) directives to gate authorization checks. Directives run after authorization in most executors, but custom directive ordering has produced authz bypasses.
  • Implement N+1 patterns in resolvers (one DB query per parent record). Use a DataLoader or join-based fetch. N+1 is both a performance bug and a DoS amplifier.
  • Allow file uploads via GraphQL multipart (apollo-upload-server, graphql-upload) without size limits, MIME validation, and out-of-band virus scan. The 2020 CVE-2020-7754 (graphql-upload) showed how a malformed multipart can crash the server.
  • Cache GraphQL responses by URL alone. POST /graphql always uses the same URL; cache must key on operation hash + variables + auth claims to avoid cross-tenant leaks.
  • Expose mutations that take untrusted JSON input: objects without schema validation. GraphQL types are mandatory at the schema layer, but JSON / Scalar types bypass them entirely.

KNOWN FALSE POSITIVES

  • Internal admin GraphQL endpoints behind an authenticated VPN may legitimately leave introspection on for developer ergonomics.
  • Static-allowlisted persisted queries make depth / complexity checks redundant on those operations — keep the checks for any operation that isn't in the allowlist (i.e. operations through a disabled flag).
  • Public, read-only data APIs may use very high cost limits with caching aggressively configured at the CDN layer; the trade-off is documented per endpoint.

Context (for humans)

GraphQL gives clients a query language. That language is Turing-complete in practice — depth, aliasing, fragments, and unions combine to form near-arbitrary computation against the resolver graph. Treating /graphql as a single endpoint with simple WAF / rate-limit controls is inadequate.

The 2022-2024 era of GraphQL incidents (Hyatt, Slack research from Apollo, several account-takeover-via-batching cases) all hinged on either missing field-level authorization or missing cost analysis. graphql-armor (Escape) and Apollo's built-in validation rules now provide off-the-shelf middleware for most of these — use them.

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). POST directly to /graphql (bypass your client — attackers do). For introspection: send { __schema { types { name } } }; a real hit returns the full type list (and GraphiQL/Sandbox loads) — an FP returns a generic error or 400. For DoS: send a deeply-nested recursive query (e.g. user { friends { friends { friends { … } } } } past your depth limit) or one with 50+ aliases / a batch of many operations; real if it hangs, spikes DB load, or amplifies — FP if rejected with a depth/complexity/alias error. For authz: request a sensitive field as a low-priv user; real if it returns data instead of UNAUTHORIZED.
  2. Fix, then lock with a regression test (unit or integration — dev's call): assert introspection is OFF in the prod config ({ __schema } → error, not schema); assert a query exceeding the depth/complexity/alias limit is rejected before execution; assert a sensitive field returns UNAUTHORIZED for an unauthorized caller. Include a benign case that must still pass — a normal shallow query under the limits returns data, and an authorized caller reads the field. 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.