B704 false negative for local Markup subclasses (CVE-2025-54384)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 8.3k
- Forks
- 836
- Avg merge
- 5d 3h
- Merged PRs (30d)
- 1
Description
Describe the bug
B704 catches direct use of markupsafe.Markup / flask.Markup, but it misses the same pattern when a project wraps Markup in a local subclass.
That causes false negatives on real CVE code. One example is CVE-2025-54384 in CKAN and CVE-2025-64187 in OctoPrint: user-controlled HTML is processed, insufficiently sanitized, and then wrapped in a local literal(Markup) class. Stock Bandit does not report these.
Reproduction steps
import re
from markdown import markdown
from markupsafe import Markup
RE_MD_HTML_TAGS = re.compile(r"<[^><]*>")
class literal(Markup):
pass
def markdown_extract(text):
plain = RE_MD_HTML_TAGS.sub("", markdown(text))
return literal(plain)
Run Bandit on this file with the stock ruleset.
Expected behavior
I would expect a B704-style finding here.
This is the same unsafe sink as Markup(...), just behind a local subclass. It seems reasonable for B704 to handle simple subclasses / wrappers of markupsafe.Markup, not only exact qualified names.
Bandit version
1.9.1 (Default)
Python version
3.10
Additional context
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the B704 rule and run Bandit with the provided Python reproduction under the stock ruleset. Compare how direct Markup calls are recognized with the local Markup subclass case. Done means the subclass example produces a B704-style finding, with regression coverage for this behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100