CVE-2026-50229: Verified Reproduction
CVE-2026-50229: Apache Tomcat examples app XSS in numguess.jsp
CVE-2026-50229 is verified against apache/tomcat · github. Affected versions: Apache Tomcat 11.0.0-M1 through 11.0.22; 10.1.0-M1 through 10.1.55; 9.0.0.M1 through 9.0.118; 8.5.0 through 8.5.100; 7.0.0 through 7.0.109. Vulnerability class: XSS. This medium reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00280.
What Is CVE-2026-50229?
CVE-2026-50229 is a low-severity reflected/stored cross-site scripting (XSS) vulnerability (CWE-80) in the bundled examples web application shipped with Apache Tomcat. Pruva reproduced it (reproduction REPRO-2026-00280).
CVE-2026-50229 Severity & CVSS Score
CVE-2026-50229 is rated medium severity, with a CVSS base score of 6.1 out of 10.
Medium — meaningful risk under specific conditions. Schedule a fix in the normal cycle.
Affected apache/tomcat Versions
apache/tomcat · github versions Apache Tomcat 11.0.0-M1 through 11.0.22; 10.1.0-M1 through 10.1.55; 9.0.0.M1 through 9.0.118; 8.5.0 through 8.5.100; 7.0.0 through 7.0.109 are affected.
How to Reproduce CVE-2026-50229
pruva-verify REPRO-2026-00280 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00280/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-50229
- reached the target end-to-end
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
HTTP GET parameter hint containing <script>alert(1)</script>
- /examples/jsp/num/numguess.jsp in the bundled Tomcat examples web application
reproduction_steps.sh How the agent worked
Root Cause and Exploit Chain for CVE-2026-50229
CVE-2026-50229 is a reflected/stored cross-site scripting (XSS) vulnerability in the bundled examples web application of Apache Tomcat. The vulnerable JSP page webapps/examples/jsp/num/numguess.jsp uses wildcard bean property binding (<jsp:setProperty name="numguess" property="*"/>) against a session-scoped NumberGuessBean. Because the NumberGuessBean exposes a hint property, an attacker can supply a hint request parameter that overwrites the bean's intended hint value. The page later renders the bean's hint value directly into the HTML response using <%= numguess.getHint() %>, which does not escape the content. This allows an attacker to inject arbitrary JavaScript/HTML into the response.
- Product / Component: Apache Tomcat, bundled
examplesweb application (webapps/examples/jsp/num/numguess.jsp) - Affected versions: 7.0.0 through 7.0.109, 8.5.0 through 8.5.100, 9.0.0.M1 through 9.0.118, 10.1.0-M1 through 10.1.55, and 11.0.0-M1 through 11.0.22
- Fixed versions: 11.0.23, 10.1.56, 9.0.119 (8.5 and 7.0 are end-of-life)
- Risk level / consequences: Medium. An attacker who can trick a user into visiting a crafted URL can execute JavaScript in the user's browser session in the context of the Tomcat examples application. Because the bean is session-scoped, the payload is also persisted until the session is reset, giving a stored-like behavior.
Impact Parity
- Disclosed / claimed maximum impact: XSS in the bundled Tomcat examples web application via attacker-controlled request parameters.
- Reproduced impact from this run: A live HTTP request to the
numguess.jspendpoint on Tomcat 10.1.55 rendered the unescaped<script>alert(1)</script>payload in the HTML response. The same request against Tomcat 10.1.56 did not render the payload because thehintparameter is no longer bound into the session bean. - Parity:
full— the reproduced behavior matches the disclosed XSS impact.
Root Cause
The root cause is the combination of two design choices in numguess.jsp:
Wildcard bean property binding:
<jsp:useBean id="numguess" class="num.NumberGuessBean" scope="session"/> <jsp:setProperty name="numguess" property="*"/>property="*"binds every request parameter to a bean property of the same name. This exposes properties other than the intendedguessparameter (e.g.,hint,answer,success,numGuesses).Unescaped output:
Good guess, but nope. Try <b><%= numguess.getHint() %></b>.The
hintvalue is emitted directly into the HTML without escaping. When an attacker setshintto HTML/JavaScript, the browser parses and executes it.
Apache fixed this by restricting the property binding to the intended guess parameter:
-<jsp:setProperty name="numguess" property="*"/>
+<jsp:setProperty name="numguess" property="guess"/>
Fix commit: 0d5bdd5b0dd964e9f73e530b7d753462b9bfd1d0 ("Minor optimisation. Only need to set 1 property so don't use wild card.")
Reproduction Steps
- Run
bundle/repro/reproduction_steps.sh. - The script installs Java if needed, downloads and extracts Apache Tomcat 10.1.55 (vulnerable) and 10.1.56 (fixed), then configures and starts each instance in turn on port
18080. - For each version, the script performs two requests in the same HTTP session:
- First request:
GET /examples/jsp/num/numguess.jsp?guess=abc— establishes a session and advances the game state so the hint branch is rendered. - Second request:
GET /examples/jsp/num/numguess.jsp?hint=%3Cscript%3Ealert(1)%3C%2Fscript%3E— attempts to bind the attacker-controlledhintparameter into the session bean.
- First request:
- The script inspects the second response for the literal string
<script>alert(1)</script>.
Expected evidence:
- Vulnerable (10.1.55): the second response contains
Good guess, but nope. Try <b><script>alert(1)</script></b>. - Fixed (10.1.56): the second response contains the default hint (e.g.,
a number next time) and no attacker-controlled markup.
Evidence
bundle/logs/reproduction_steps.log— full script execution log.bundle/repro/vulnerable_resp2.html— HTTP response from the vulnerable Tomcat 10.1.55 showing the unescaped payload.bundle/repro/fixed_resp2.html— HTTP response from the fixed Tomcat 10.1.56 showing the payload is absent.bundle/repro/runtime_manifest.json— runtime evidence manifest.
Key excerpt from vulnerable_resp2.html:
Good guess, but nope. Try <b><script>alert(1)</script></b>.
Key excerpt from fixed_resp2.html:
Good guess, but nope. Try <b>a number next time</b>.
Environment:
- OpenJDK 25.0.3 (installed via
default-jdkpackage) - Apache Tomcat 10.1.55 and 10.1.56 binary distributions from
https://archive.apache.org/dist/tomcat/
Recommendations / Next Steps
- Upgrade to a fixed Tomcat version (10.1.56+, 9.0.119+, or 11.0.23+).
- Remove or disable the
examplesweb application in production environments; it is intended for demonstration only. - Avoid wildcard bean property binding (
property="*") when the request can contain untrusted parameters; explicitly whitelist the parameters the application intends to bind. - Escape output when rendering dynamic content, or use a framework that escapes expression-language output by default.
- Add regression tests that verify untrusted request parameters are not bound into session beans and are not reflected unescaped in responses.
Additional Notes
- The reproduction script is idempotent: it reuses cached Tomcat archives, reconfigures ports deterministically, and cleanly stops each instance before starting the next one.
- The script was run twice consecutively and produced the same confirmed result both times.
- The examples application is typically not deployed in production, which limits real-world exploitability, but the vulnerability is real in the shipped product.
CVE-2026-50229 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Artifacts and Evidence for CVE-2026-50229
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-50229
FAQ: CVE-2026-50229
How does the CVE-2026-50229 XSS attack work?
Which Apache Tomcat versions are affected by CVE-2026-50229, and where is it fixed?
How severe is CVE-2026-50229?
How can I reproduce CVE-2026-50229?
References for CVE-2026-50229
Authoritative sources for CVE-2026-50229 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.