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.
npx -y skills add ShieldNet-360/secure-vibe --skill graphql-securityAssembled 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
.graphqlartifact. - 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
@authon 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
/graphqlintrospection 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
/graphqlalways 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, butJSON/Scalartypes 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
disabledflag). - 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.
- 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 ofUNAUTHORIZED. - 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 returnsUNAUTHORIZEDfor 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
rules/graphql_safe_config.json- OWASP GraphQL Cheat Sheet.
- CWE-400.
- Apollo Production Checklist.
- graphql-armor.