CWE-80 is the basic form of cross-site scripting. The product takes input from an upstream component but does not neutralize, or incorrectly neutralizes, special characters such as angle brackets and the ampersand that could be read as web-scripting elements when they reach a component that processes web pages.
It belongs to the same family as CWE-79, and applies to any page that shows user-supplied text.
How it happens
A page is built from text. If a value from a user lands in that text without escaping, the browser cannot tell the user's characters from the page's own markup. An attacker inserts special characters that are processed client-side in the context of the user's session.
A short Node example:
// Vulnerable
res.send("<p>Hello " + req.query.name + "</p>");
// Fixed: escape for HTML body context
const escapeHtml = s => s.replace(/&/g, "&")
.replace(/</g, "<").replace(/>/g, ">")
.replace(/"/g, """).replace(/'/g, "'");
res.send("<p>Hello " + escapeHtml(req.query.name) + "</p>");
The observed examples are from the early 2000s, and show the usual entry points: CVE-2002-0938 is XSS in a parameter in a link, CVE-2002-1495 is XSS in a web-based email product via attachment filenames, CVE-2003-1136 is HTML injection in a posted message and CVE-2004-2171 is XSS not quoted in an error page. See CVE-2002-0938, CVE-2002-1495, CVE-2003-1136 and CVE-2004-2171.
What an attacker gains
MITRE lists confidentiality, integrity and availability: reading application data and executing unauthorized code or commands, all within the victim's session.
How to find it
MITRE lists automated static analysis (SAST), which can find some instances by analyzing source or compiled code and modeling data flow, without running the program. Pair it with manual testing that feeds special characters to every field and checks how they come back in the page.
How to fix it
- Check all input against an allowlist. Define the specific characters and format allowed. Neutralize all data in the request, including hidden fields, cookies, headers and the URL, not only fields you expect to show. A field that is not reflected today may be reflected by a future developer.
- Specify an output encoding. Use one the downstream component handles, such as UTF-8. When no encoding is declared, browsers guess, and inconsistent encodings let attackers slip characters past filters.
- Encode on output for the context the data lands in.
Quick check
Why validate fields that are not displayed?
A field that is not reflected now may be used later by another developer, and the application server may reflect request data you did not expect.