1+ id : graphql-subscription-oob
2+
3+ info :
4+ name : GraphQL Subscription OOB Callback Detection
5+ author : geeknik
6+ severity : medium
7+ description : |
8+ Detects GraphQL endpoints that support subscriptions with external callback URLs,
9+ potentially leading to SSRF via subscription webhook notifications or schema fetching.
10+ reference :
11+ - https://graphql.org/blog/subscriptions-in-graphql-and-relay/
12+ - https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/19-Testing_for_Server-Side_Request_Forgery
13+ classification :
14+ cvss-metrics : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N
15+ cvss-score : 5.8
16+ cwe-id : CWE-918
17+ tags : graphql,oob,ssrf,subscription,callback
18+
19+ variables :
20+ callback_url : " {{interactsh-url}}"
21+
22+ http :
23+ - method : POST
24+ path :
25+ - " {{BaseURL}}/graphql"
26+ - " {{BaseURL}}/api/graphql"
27+ - " {{BaseURL}}/v1/graphql"
28+ - " {{BaseURL}}/query"
29+
30+ headers :
31+ Content-Type : application/json
32+ Accept : application/json
33+
34+ body : |
35+ {
36+ "query": "subscription { __schema { subscriptionType { fields { name description args { name type { name } } } } } }",
37+ "variables": {}
38+ }
39+
40+ matchers-condition : and
41+ matchers :
42+ - type : word
43+ part : body
44+ words :
45+ - ' "subscriptionType"'
46+ - ' "fields"'
47+ condition : and
48+
49+ - type : status
50+ status :
51+ - 200
52+
53+ - method : POST
54+ path :
55+ - " {{BaseURL}}/graphql"
56+ - " {{BaseURL}}/api/graphql"
57+ - " {{BaseURL}}/v1/graphql"
58+ - " {{BaseURL}}/query"
59+
60+ headers :
61+ Content-Type : application/json
62+ Accept : application/json
63+
64+ body : |
65+ {
66+ "query": "mutation RegisterWebhook($url: String!) { registerWebhook(callbackUrl: $url) { id status } }",
67+ "variables": {
68+ "url": "{{callback_url}}"
69+ }
70+ }
71+
72+ - method : POST
73+ path :
74+ - " {{BaseURL}}/graphql"
75+ - " {{BaseURL}}/api/graphql"
76+ - " {{BaseURL}}/v1/graphql"
77+ - " {{BaseURL}}/query"
78+
79+ headers :
80+ Content-Type : application/json
81+ Accept : application/json
82+
83+ body : |
84+ {
85+ "query": "mutation CreateSubscription($callback: String!) { createSubscription(webhookUrl: $callback) { subscriptionId } }",
86+ "variables": {
87+ "callback": "{{callback_url}}"
88+ }
89+ }
90+
91+ - method : POST
92+ path :
93+ - " {{BaseURL}}/graphql"
94+ - " {{BaseURL}}/api/graphql"
95+ - " {{BaseURL}}/v1/graphql"
96+ - " {{BaseURL}}/query"
97+
98+ headers :
99+ Content-Type : application/json
100+ Accept : application/json
101+
102+ body : |
103+ {
104+ "query": "mutation ImportSchema($url: String!) { importSchema(schemaUrl: $url) { success errors } }",
105+ "variables": {
106+ "url": "{{callback_url}}/schema.graphql"
107+ }
108+ }
109+
110+ matchers :
111+ - type : word
112+ part : interactsh_protocol
113+ words :
114+ - " http"
115+ - " dns"
116+ condition : or
0 commit comments