Listen to this Post
The vulnerability resides in the `_num_re` regex (r"^\d+(?:\.\d)?") used to validate `:width:` and `:height:` options in the Image directive plugin.
Because the regex is applied only with `re.match()` (anchoring only at the start of the string, not the end), any value that begins with one or more digits passes validation regardless of what follows.
When the validated value is not a plain integer, the `render_block_image()` function inserts it directly into a `style=”width:…;”` or `style=”height:…;”` attribute without any escaping.
Since the value was accepted by the prefix‑only regex, any CSS that appears after the leading digits reaches the `style=` attribute verbatim.
An attacker can therefore inject an arbitrary chain of CSS properties — including position:fixed, background-color, z-index, outline, and `opacity` — using nothing more than a single `:width:` option in a fenced image directive.
For example, a `:width:` value of `100vw;height:100vh;position:fixed;top:0;…` is accepted because it starts with 100vw, and the entire string is placed into the `style=` attribute unmodified.
The resulting `` element expands to fill the entire viewport, sits fixed above all page content, and is rendered with the attacker’s chosen background color, outline, and opacity.
This enables complete full‑page phishing overlays, UI redressing attacks, and even CSS‑based data exfiltration (e.g., via background-image: url(…)).
The root cause is the missing end‑of‑string anchor ($) in the validation regex, combined with the assumption that anything that passes the regex is a safe CSS length like `100px` or 50%.
The vulnerable code is located in src/mistune/directives/image.py, in the `_parse_attrs()` and `render_block_image()` functions.
No HTML escaping is applied to the injected CSS, and the `escape=True` flag in the Markdown parser does not block this attack because the payload never passes through the HTML escape code path.
The only safe path is when the `width` or `height` value is a plain integer, which triggers the `isdigit()` branch and uses a safe HTML attribute instead of the `style=` attribute.
All non‑integer values that pass the prefix‑only regex are directly concatenated into the `style=` attribute, making the attack trivial to execute.
A full PoC script is available that generates an HTML file with a live demonstration of the injected crimson overlay covering the entire browser viewport.
This vulnerability was assigned CVE‑2026‑44899 and is fixed in Mistune version 3.2.1.
DailyCVE form:
Platform: Mistune Python
Version: 3.2.0
Vulnerability : CSS Injection
Severity: High
date: 2026-05-14
Prediction: 2026-05-03
What Undercode Say:
Verify vulnerable version
pip show mistune | grep Version
Test script (save as test_cve.py)
python3 - <<EOF
from mistune import create_markdown
from mistune.directives import FencedDirective
from mistune.directives.image import Image
md = create_markdown(escape=True, plugins=[FencedDirective([Image()])])
payload = (
"```{image} x.jpg\n"
":width: 100vw;height:100vh;position:fixed;background-color:red\n"
":alt: injected\n```\n"
)
print(md(payload))
EOF
Exploit:
```{image} x.jpg
:width: 100vw;height:100vh;position:fixed;top:0;left:0;z-index:9999;background-color:e11d48;outline:8px solid facc15;color:fff;opacity:.93
:alt: ⚠ CSS INJECTED — click to dismiss ⚠
\```
Protection from this CVE:
- Upgrade to Mistune ≥3.2.1 (
pip install --upgrade mistune) - Sanitize all user‑supplied Markdown before rendering, removing any
:width:/:height:that contain CSS‑specific characters (;,:,{,}) - Use a different Markdown parser or disable the Image directive plugin if not needed
Impact:
- Confidentiality – CSS data exfiltration via `background-image: url(…?data=…)` in permissive CSP environments
- Integrity – Full‑page phishing overlays, fake login forms, UI redressing, clickjacking, brand impersonation
- Availability – Overlay obscures all legitimate page content until the user dismisses the page or navigates away
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

