GHSA-GJ48-438W-JH9V

Vulnerability from github – Published: 2026-06-16 14:07 – Updated: 2026-06-16 14:07
VLAI
Summary
Bleach clean() / Cleaner() fails to sanitize dangerous URI schemes in allowed formaction attributes
Details

Summary

Bleach clean() / Cleaner() fails to sanitize dangerous URI schemes in allowed formaction attributes.

Bleach applies URI protocol sanitization only to attributes listed in attr_val_is_uri. 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.allow_token (around line 553)
  • bleach/_vendor/html5lib/filters/sanitizer.py — attr_val_is_uri (around line 525)

In BleachSanitizerFilter.allow_token, URI protocol sanitization is only applied when:

```python id="pft79m" if namespaced_name in self.attr_val_is_uri:


However, `(None, 'formaction')` is currently missing from `attr_val_is_uri`.

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 attr_val_is_uri 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( ' go', 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"

go

---

#### 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"


**Expected output:**

```html id="6y8mws"
<form><input type="submit" value="go"></form>

3) <input type="image">

```python id="g8q0x8" print(clean( ' ', 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"

```


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
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "bleach"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "6.4.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-79"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-16T14:07:49Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nBleach `clean()` / `Cleaner()` fails to sanitize dangerous URI schemes in allowed `formaction` attributes.\n\nBleach applies URI protocol sanitization only to attributes listed in `attr_val_is_uri`. 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.\n\nThis can lead to **submit-triggered JavaScript execution** in applications that rely on Bleach to sanitize untrusted HTML and allow the relevant tag/attribute combination.\n\n---\n\n### Details\n\nThe issue appears to be a URI-sanitization coverage gap in Bleach\u2019s sanitizer logic.\n\nRelevant code paths:\n\n* `bleach/sanitizer.py` \u2014 `BleachSanitizerFilter.allow_token` (around line 553)\n* `bleach/_vendor/html5lib/filters/sanitizer.py` \u2014 `attr_val_is_uri` (around line 525)\n\nIn `BleachSanitizerFilter.allow_token`, URI protocol sanitization is only applied when:\n\n```python id=\"pft79m\"\nif namespaced_name in self.attr_val_is_uri:\n```\n\nHowever, `(None, \u0027formaction\u0027)` is currently missing from `attr_val_is_uri`.\n\nThis creates an inconsistency where `action` is protocol-sanitized, but `formaction` is not.\n\nAs a result, if a downstream application allows:\n\n* tags such as `\u003cbutton\u003e` or `\u003cinput\u003e`\n* the `formaction` attribute\n\nthen Bleach preserves dangerous URI schemes such as `javascript:` in `formaction`.\n\nExamples of affected submit-capable controls include:\n\n* `\u003cbutton\u003e` (default submit behavior unless `type=\"button\"` is set)\n* `\u003cinput type=\"submit\"\u003e`\n* `\u003cinput type=\"image\"\u003e`\n\nThis 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.\n\nSuggested minimal fix:\n\nAdd:\n\n```python id=\"4v4fkn\"\n(None, \u0027formaction\u0027)\n```\n\nto `attr_val_is_uri` in:\n\n* `bleach/_vendor/html5lib/filters/sanitizer.py`\n\nI also prepared a minimal patch and focused regression tests if helpful.\n\n---\n\n### PoC\n\nBelow are minimal reproductions using `bleach.clean()`.\n\n#### 1) `\u003cbutton\u003e`\n\n```python id=\"d3g0v7\"\nfrom bleach import clean\n\nprint(clean(\n    \u0027\u003cform\u003e\u003cbutton formaction=\"javascript:alert(1)\"\u003ego\u003c/button\u003e\u003c/form\u003e\u0027,\n    tags={\u0027form\u0027, \u0027button\u0027},\n    attributes={\u0027button\u0027: [\u0027formaction\u0027]},\n))\n```\n\n**Actual output:**\n\n```html id=\"i4nd7s\"\n\u003cform\u003e\u003cbutton formaction=\"javascript:alert(1)\"\u003ego\u003c/button\u003e\u003c/form\u003e\n```\n\n**Expected output:**\n\n```html id=\"g4d2r1\"\n\u003cform\u003e\u003cbutton\u003ego\u003c/button\u003e\u003c/form\u003e\n```\n\n---\n\n#### 2) `\u003cinput type=\"submit\"\u003e`\n\n```python id=\"l4dy0j\"\nprint(clean(\n    \u0027\u003cform\u003e\u003cinput type=\"submit\" formaction=\"javascript:alert(1)\" value=\"go\"\u003e\u003c/form\u003e\u0027,\n    tags={\u0027form\u0027, \u0027input\u0027},\n    attributes={\u0027input\u0027: [\u0027type\u0027, \u0027formaction\u0027, \u0027value\u0027]},\n))\n```\n\n**Actual output:**\n\n```html id=\"h8lgbt\"\n\u003cform\u003e\u003cinput type=\"submit\" formaction=\"javascript:alert(1)\" value=\"go\"\u003e\u003c/form\u003e\n```\n\n**Expected output:**\n\n```html id=\"6y8mws\"\n\u003cform\u003e\u003cinput type=\"submit\" value=\"go\"\u003e\u003c/form\u003e\n```\n\n---\n\n#### 3) `\u003cinput type=\"image\"\u003e`\n\n```python id=\"g8q0x8\"\nprint(clean(\n    \u0027\u003cform\u003e\u003cinput type=\"image\" formaction=\"javascript:alert(1)\" src=\"/foo.png\"\u003e\u003c/form\u003e\u0027,\n    tags={\u0027form\u0027, \u0027input\u0027},\n    attributes={\u0027input\u0027: [\u0027type\u0027, \u0027formaction\u0027, \u0027src\u0027]},\n))\n```\n\n**Actual output:**\n\n```html id=\"fd22kg\"\n\u003cform\u003e\u003cinput type=\"image\" formaction=\"javascript:alert(1)\" src=\"/foo.png\"\u003e\u003c/form\u003e\n```\n\n**Expected output:**\n\n```html id=\"z6t6je\"\n\u003cform\u003e\u003cinput type=\"image\" src=\"/foo.png\"\u003e\u003c/form\u003e\n```\n\n---\n\n### Impact\n\nThis is a **client-side HTML sanitization bypass / dangerous URI preservation issue**.\n\nIf an application relies on Bleach to sanitize untrusted HTML and explicitly allows:\n\n* `formaction`\n* and submit-capable controls such as `\u003cbutton\u003e` or `\u003cinput\u003e`\n\nthen Bleach can emit sanitized output that still contains a dangerous `javascript:` URI in `formaction`.\n\nThat can lead to **submit-triggered JavaScript execution** when the user activates the control.\n\nImpact is limited to configurations that explicitly allow the relevant tag/attribute combination, but the issue is still security-relevant because:\n\n* `formaction` is a real browser sink\n* Bleach already protocol-sanitizes similar URI-bearing attributes like `action`\n* the omission creates inconsistent sanitizer coverage for dangerous URI schemes\n\nI would currently assess this as **Medium severity**.\n\nIf useful, I also have:\n\n* a minimal patch\n* focused regression tests for:\n\n  * `\u003cbutton formaction=\"javascript:...\"\u003e`\n  * `\u003cinput type=\"submit\" formaction=\"javascript:...\"\u003e`\n  * `\u003cinput type=\"image\" formaction=\"javascript:...\"\u003e`\n  * a safe control case where `formaction=\"/submit\"` is preserved",
  "id": "GHSA-gj48-438w-jh9v",
  "modified": "2026-06-16T14:07:49Z",
  "published": "2026-06-16T14:07:49Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/mozilla/bleach/security/advisories/GHSA-gj48-438w-jh9v"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/mozilla/bleach"
    },
    {
      "type": "WEB",
      "url": "https://github.com/mozilla/bleach/releases/tag/v6.4.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Bleach clean() / Cleaner() fails to sanitize dangerous URI schemes in allowed formaction attributes"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…