python/flask: catch inline render_template_string() calls in dangerous-template-string - #4040
Open
shmulc8 wants to merge 1 commit into
Open
Conversation
|
Semgrep found 6
Found a template created with string formatting. This is susceptible to server-side template injection and cross-site scripting attacks. |
shmulc8
force-pushed
the
fix/dangerous-template-string-inline-calls
branch
2 times, most recently
from
August 18, 2026 21:45
8949589 to
b6b7d40
Compare
Author
|
For what it is worth, the whole rule also collapses into an allowlist: patterns:
- pattern: flask.render_template_string($X, ...)
- pattern-not: flask.render_template_string("...", ...)It covers the same cases plus |
shmulc8
force-pushed
the
fix/dangerous-template-string-inline-calls
branch
2 times, most recently
from
August 18, 2026 21:51
5f932cc to
8be86a1
Compare
Every pattern in dangerous-template-string requires the template to be
assigned to a variable before the call, so a template formatted inline at
the call site is missed:
return flask.render_template_string(f"<h1>{request.url}</h1>")
Adds four patterns matching the call expression itself (f-string, .format,
%, concatenation). Matching the expression also covers
`return render_template_string(...), 404` without needing a separate
pattern per formatting style, which is why the existing set has two
entries each.
Also enables the error3 test case that was commented out as "Doesn't work
yet". The assignment-plus-f-string form it describes has been matched for
a while; the block could never have passed because
f'''{ extends "layout.html" }''' is not valid Python. Rewritten with
escaped braces so it parses, and it matches.
Test file gains five vulnerable cases and two `# ok:` cases, the latter
pinning the rule against being widened into flagging every
render_template_string call.
shmulc8
force-pushed
the
fix/dangerous-template-string-inline-calls
branch
from
August 18, 2026 21:54
8be86a1 to
2904f2c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
dangerous-template-stringrequires the template to be assigned to a variable before the call, so a template formatted inline at the call site is missed entirely:All eight existing patterns are of the form
$V = <formatted> ... render_template_string($V). This adds four that match the call expression itself — f-string,.format,%, concatenation. Matching the expression also coversreturn render_template_string(...), 404for free, which is why the existing set needs two entries per formatting style.The commented-out test
dangerous-template-string.pycarries anerror3case commented out as## Doesn't work yet. The assignment-plus-f-string form it describes is matched today; the block could never have passed becausef'''{ extends "layout.html" }'''is not valid Python — the braces are parsed as f-string expressions. Rewritten with escaped braces so it parses, and enabled.Tests
Five vulnerable cases and two
# ok:cases added. The# ok:half is deliberate: it pins the rule against being widened into flagging everyrender_template_stringcall, whichflask/security/audit/render-template-stringalready does at WARNING.semgrep --testpasses 1/1 on the rule.