What it is: Improper Neutralization of Invalid Characters in Identifiers in Web Pages (CWE-86) is a type of cross-site scripting vulnerability where invalid characters or byte sequences hidden inside a tag name or URI scheme cause a filter and the browser to disagree about what the identifier means.
Why it matters: A filter checking for an exact tag name or scheme string can be bypassed by an attacker who hides an invalid byte in the middle of it, since the browser's parser may silently strip that byte and still recognize the dangerous identifier.
How to fix it: Normalize and strip invalid characters from identifiers before filtering, so the filter and the downstream renderer interpret the exact same string.
TL;DR: CWE-86 lets an attacker bypass an XSS filter by hiding invalid characters or null bytes inside a tag name or URI scheme; the fix is normalizing identifiers before filtering, so the filter sees what the browser will actually render.
| Field | Value |
|---|---|
| CWE ID | CWE-86 |
| OWASP Category | A05:2025 - Injection |
| CAPEC | CAPEC-247, CAPEC-73, CAPEC-85 |
| Typical Severity | High |
| Affected Technologies | Web applications, browsers |
| Detection Difficulty | Hard |
| Last Updated | 2026-07-27 |
What is Invalid Characters in Identifiers XSS?
Improper Neutralization of Invalid Characters in Identifiers in Web Pages (CWE-86) is a type of cross-site scripting vulnerability that occurs when a product does not neutralize invalid characters or byte sequences in the middle of tag names, URI schemes, and other identifiers. As defined by the MITRE Corporation under CWE-86, and classified by the OWASP Foundation under A05:2025 - Injection, this weakness is a direct child of both Cross-site Scripting (CWE-79) and Interpretation Conflict (CWE-436).
Quick Summary
This is a parser-disagreement attack: the filter checks whether an identifier (like a tag name or URI scheme) matches a known-dangerous string, but an attacker hides an invalid character inside that identifier that the filter’s exact-match check trips on — while the browser’s more forgiving HTML/URI parser silently discards the invalid byte and still recognizes the underlying dangerous tag or scheme.
Jump to: Quick Summary · Invalid Characters in Identifiers XSS Overview · How Invalid Characters in Identifiers XSS Works · Business Impact of Invalid Characters in Identifiers XSS · Invalid Characters in Identifiers XSS Attack Scenario · How to Detect Invalid Characters in Identifiers XSS · How to Fix Invalid Characters in Identifiers XSS · Framework-Specific Fixes for Invalid Characters in Identifiers XSS · How to Ask AI to Check Your Code for Invalid Characters in Identifiers XSS · Invalid Characters in Identifiers XSS Best Practices Checklist · Invalid Characters in Identifiers XSS FAQ · Vulnerabilities Related to Invalid Characters in Identifiers XSS · References · Scan Your Own Site
Invalid Characters in Identifiers XSS Overview
What: An invalid character or byte sequence is hidden inside a tag name or URI scheme, causing a security filter and the downstream HTML/URI parser to interpret the same string differently.
Why it matters: The filter’s check can fail to recognize a dangerous identifier that the browser will still parse and act on.
Where it occurs: Any XSS filter that checks tag names, URI schemes, or other identifiers using exact or simple pattern matching rather than first normalizing the string.
Who is affected: Applications whose filters check raw identifier strings without stripping invalid characters first.
Who is NOT affected: Applications that normalize identifiers (removing invalid characters/bytes) before applying any filter logic, matching what the downstream renderer will actually see.
How Invalid Characters in Identifiers XSS Works
Root Cause
A security filter checks a tag name or URI scheme as a raw string, without accounting for invalid characters the downstream HTML/URI parser will silently strip during interpretation.
Attack Flow
- The attacker identifies a filter that blocks specific dangerous tag names or URI schemes (e.g. “script” or “javascript:”).
- The attacker inserts an invalid character or null byte into the middle of that identifier, e.g.
scr\x00ipt. - The filter’s exact-match check does not recognize this as the blocked identifier and passes it through.
- The browser’s HTML parser strips the invalid byte during parsing and still recognizes the underlying
<script>tag, executing it.
Prerequisites to Exploit
- A security filter checks tag names or URI schemes using exact or simple pattern matching.
- The filter does not normalize/strip invalid characters before comparison.
- The downstream browser or renderer silently discards the same invalid characters during its own parsing.
Vulnerable Code
def is_safe_tag(tag_name):
return tag_name.lower() != "script"
def render(tag_name, content):
if is_safe_tag(tag_name):
return f"<{tag_name}>{content}</{tag_name}>"
return ""
The check only rejects the exact string "script", so a tag name containing an embedded invalid byte the browser will later strip bypasses this filter while still resolving to a real <script> element at render time.
Secure Code
import re
def normalize_identifier(tag_name):
return re.sub(r"[^\x20-\x7E]", "", tag_name).lower()
def is_safe_tag(tag_name):
return normalize_identifier(tag_name) != "script"
def render(tag_name, content):
if is_safe_tag(tag_name):
return f"<{tag_name}>{content}</{tag_name}>"
return ""
Normalizing the identifier (stripping non-printable/invalid characters) before comparison ensures the filter evaluates the exact same string the browser’s parser will ultimately interpret.
Business Impact of Invalid Characters in Identifiers XSS
Confidentiality: Attackers may read application data reachable from the victim’s session via a filter-bypassing script injection.
Integrity: Attackers may perform actions as the victim through script that slipped past an identifier-based filter.
Availability: Attackers may disrupt page functionality for the victim through the same bypass.
- Bypass of security controls specifically designed to block known-dangerous tag names or URI schemes
- False confidence in a filter that appears correct against simple, unencoded test payloads
Invalid Characters in Identifiers XSS Attack Scenario
- An attacker finds a rich-text input feature that blocks the literal string “script” as a tag name.
- They submit a tag name with an embedded null byte hidden in the middle of the word “script”.
- The filter’s exact-string check does not recognize this as blocked and allows it through.
- The browser’s HTML parser strips the invalid byte during rendering and still creates a real, executing
<script>element.
How to Detect Invalid Characters in Identifiers XSS
Manual Testing
- Identify filters that check tag names or URI schemes against a blocklist.
- Test with invalid characters or null bytes embedded inside the blocked identifier.
- Confirm whether the rendered page still executes the payload despite the filter passing it.
Automated Scanners (SAST / DAST)
Static analysis can flag identifier filters that compare raw strings without normalization, while dynamic testing with invalid-character payloads confirms whether the live renderer still executes the underlying dangerous identifier.
PenScan Detection
PenScan’s scanner engines test XSS filters with invalid-character and null-byte payloads hidden inside tag names and URI schemes.
False Positive Guidance
If the application’s filter normalizes and strips invalid characters before comparison, an embedded null byte in test input should already be neutralized identically to the clean form — confirm the actual filter implementation before treating a passed test as a real finding.
How to Fix Invalid Characters in Identifiers XSS
- Normalize identifiers (strip invalid characters/bytes) before applying any filter or comparison logic.
- Ensure the filter evaluates the exact same string representation the downstream renderer will interpret.
- Use an allowlist of known-safe tag names/schemes rather than a blocklist of specific dangerous ones.
Framework-Specific Fixes for Invalid Characters in Identifiers XSS
- Java: normalize identifiers with a strict character-class filter before any tag/scheme comparison, and rely on a vetted HTML sanitizer library (e.g. OWASP Java HTML Sanitizer) rather than custom filtering.
- Node.js: use a maintained HTML sanitization library (e.g. DOMPurify) that already accounts for parser quirks, rather than custom regex-based tag filtering.
- Python/Django: use
bleachor an equivalent vetted sanitizer library instead of custom identifier filtering. - PHP: use HTML Purifier or an equivalent vetted sanitizer rather than custom tag-name blocklists.
How to Ask AI to Check Your Code for Invalid Characters in Identifiers XSS
Review the following [language] code block for potential CWE-86 invalid-character identifier XSS vulnerabilities and rewrite it to normalize identifiers before filtering, or use a vetted HTML sanitizer library: [paste code here]
Invalid Characters in Identifiers XSS Best Practices Checklist
✅ Normalize identifiers (strip invalid characters/bytes) before any filter comparison ✅ Use a vetted HTML sanitizer library instead of custom tag/scheme filtering ✅ Prefer allowlisting known-safe tags/schemes over blocklisting dangerous ones ✅ Test filters with invalid-character and null-byte payloads during review
Invalid Characters in Identifiers XSS FAQ
How do invalid characters inside a tag name bypass an XSS filter?
A filter looking for the exact string “script” can be fooled if the attacker inserts a null byte or other invalid character in the middle (e.g. “scr\x00ipt”), since the filter’s string match fails while the browser’s HTML parser may still strip the invalid byte and recognize the tag anyway.
How is this different from Basic XSS (CWE-80)?
CWE-80 covers unescaped script-enabling characters at the tag boundaries; CWE-86 covers invalid bytes hidden inside identifiers (tag names, URI schemes) that cause the filter and the downstream renderer to interpret the same string differently.
How does this relate to Interpretation Conflict (CWE-436)?
This weakness is a direct child of Interpretation Conflict — the filter and the browser’s HTML/URI parser disagree about what a string means once invalid characters are involved, and the attacker exploits that disagreement.
How do I detect this in my own application?
Test XSS filters with tag names and URI schemes containing embedded null bytes or other invalid characters, and confirm whether the rendered page still executes the payload despite the filter appearing to pass it as “safe”.
How do I fix this correctly?
Normalize and strip invalid characters from identifiers before filtering, so the filter evaluates the exact same string the downstream renderer will ultimately interpret.
How can PenScan help find this weakness?
PenScan tests XSS filters with invalid-character and null-byte payloads hidden inside tag names and URI schemes to find interpretation-conflict bypasses.
Vulnerabilities Related to Invalid Characters in Identifiers XSS
| CWE | Name | Relationship |
|---|---|---|
| CWE-79 | Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’) | ChildOf |
| CWE-436 | Interpretation Conflict | ChildOf |
References
Scan Your Own Site
Manual code review catches what you know to look for. An automated scan catches what you didn’t. Scan your own website using PenScan to find this XSS bypass and other risks before an attacker does.