GHSA-gj48-438w-jh9v: XSS
Summary
Bleach clean() / Cleaner() fails to sanitize dangerous URI schemes in allowed formaction attributes.
Bleach applies URI protocol sanitization only to attributes listed in attrvalisuri. While URI-bearing attributes such as action, href, src, and poster are included in that set, formaction is not. As a result, if a downstream application explicitly allows formaction on submit-capable controls in untrusted HTML, Bleach preserves dangerous values such as javascript:alert(1) instead of stripping them.
This can lead to submit-triggered JavaScript execution in applications that rely on Bleach to sanitize untrusted HTML and allow the relevant tag/attribute combination.
---
Details
The issue appears to be a URI-sanitization coverage gap in Bleach’s sanitizer logic.
Relevant code paths:
bleach/sanitizer.py — BleachSanitizerFilter.allowtoken (around line 553) bleach/vendor/html5lib/filters/sanitizer.py — attrvalisuri (around line 525)
In BleachSanitizerFilter.allowtoken, URI protocol sanitization is only applied when:
python id="pft79m" if namespacedname in self.attrvalisuri:
However, (None, 'formaction') is currently missing from attrvalisuri.
This creates an inconsistency where action is protocol-sanitized, but formaction is not.
As a result, if a downstream application allows:
tags such as <button> or <input> the formaction attribute
then Bleach preserves dangerous URI schemes such as javascript: in formaction.
Examples of affected submit-capable controls include:
<button> (default submit behavior unless type="button" is set) <input type="submit"> <input type="image">
This appears to be a real library-side sanitizer gap rather than only an application misuse issue, because Bleach already treats similar URI-bearing attributes (such as action) as protocol-sensitive and sanitizes them.
Suggested minimal fix:
Add:
python id="4v4fkn" (None, 'formaction')
to attrvalisuri in:
bleach/vendor/html5lib/filters/sanitizer.py
I also prepared a minimal patch and focused regression tests if helpful.
---
PoC
Below are minimal reproductions using bleach.clean().
1) <button>
python id="d3g0v7" from bleach import clean
print(clean( '<form><button formaction="javascript:alert(1)">go</button></form>', tags={'form', 'button'}, attributes={'button': ['formaction']}, ))
Actual output:
html id="i4nd7s" <form><button formaction="javascript:alert(1)">go</button></form>
Expected output:
html id="g4d2r1" <form><button>go</button></form>
---
2) <input type="submit">
python id="l4dy0j" print(clean( '<form><input type="submit" formaction="javascript:alert(1)" value="go"></form>', tags={'form', 'input'}, attributes={'input': ['type', 'formaction', 'value']}, ))
Actual output:
html id="h8lgbt" <form><input type="submit" formaction="javascript:alert(1)" value="go"></form>
Expected output:
html id="6y8mws" <form><input type="submit" value="go"></form>
---
3) <input type="image">
python id="g8q0x8" print(clean( '<form><input type="image" formaction="javascript:alert(1)" src="/foo.png"></form>', tags={'form', 'input'}, attributes={'input': ['type', 'formaction', 'src']}, ))
Actual output:
html id="fd22kg" <form><input type="image" formaction="javascript:alert(1)" src="/foo.png"></form>
Expected output:
html id="z6t6je" <form><input type="image" src="/foo.png"></form>
---
Impact
This is a client-side HTML sanitization bypass / dangerous URI preservation issue.
If an application relies on Bleach to sanitize untrusted HTML and explicitly allows:
formaction and submit-capable controls such as <button> or <input>
then Bleach can emit sanitized output that still contains a dangerous javascript: URI in formaction.
That can lead to submit-triggered JavaScript execution when the user activates the control.
Impact is limited to configurations that explicitly allow the relevant tag/attribute combination, but the issue is still security-relevant because:
formaction is a real browser sink Bleach already protocol-sanitizes similar URI-bearing attributes like action the omission creates inconsistent sanitizer coverage for dangerous URI schemes
I would currently assess this as Medium severity.
If useful, I also have:
a minimal patch focused regression tests for:
<button formaction="javascript:..."> <input type="submit" formaction="javascript:..."> <input type="image" formaction="javascript:..."> a safe control case where formaction="/submit" is preserved
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/bleachto a version that resolves this vulnerability.Fixed in 6.4.0 - Configuration
Add (None, 'formaction') to attr_val_is_uri so Bleach applies URI protocol sanitization to formaction attributes (e.g., update attr_val_is_uri list in bleach/_vendor/html5lib/filters/sanitizer.py).
bleach/_vendor/html5lib/filters/sanitizer.py attr_val_is_uri = add (None, 'formaction')
Event History
Frequently Asked Questions
What is the severity of GHSA-gj48-438w-jh9v?
The severity of GHSA-gj48-438w-jh9v is medium with a CVSS score of 6.1.
How do I fix GHSA-gj48-438w-jh9v?
To fix GHSA-gj48-438w-jh9v, update to Bleach version 6.4.0 or later.
What type of vulnerability is GHSA-gj48-438w-jh9v?
GHSA-gj48-438w-jh9v is an XSS (Cross-Site Scripting) vulnerability.
Which software is affected by GHSA-gj48-438w-jh9v?
GHSA-gj48-438w-jh9v affects the Bleach library used in Python applications.
What are the implications of GHSA-gj48-438w-jh9v?
The implications of GHSA-gj48-438w-jh9v include the potential for attackers to execute malicious scripts in the context of a user's browser.