Skip to content

Commit c270817

Browse files
committed
Python: Support %-style formatting for MarkupSafe
1 parent 0a4efd0 commit c270817

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

python/ql/src/semmle/python/frameworks/MarkupSafe.qll

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ private module MarkupSafeModel {
7171
StringFormat() { this.calls(instance(), "format") }
7272
}
7373

74+
/** A %-style string format with `markupsafe.Markup` as the format string. */
75+
class PercentStringFormat extends Markup::InstanceSource, DataFlow::CfgNode {
76+
override BinaryExprNode node;
77+
78+
PercentStringFormat() {
79+
node.getOp() instanceof Mod and
80+
instance().asCfgNode() = node.getLeft()
81+
}
82+
}
83+
7484
/** Taint propagation for `markupsafe.Markup`. */
7585
class AddtionalTaintSteps extends TaintTracking::AdditionalTaintStep {
7686
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
@@ -127,4 +137,15 @@ private module MarkupSafeModel {
127137

128138
override DataFlow::Node getOutput() { result = this }
129139
}
140+
141+
/** A escape from %-style string format with `markupsafe.Markup` as the format string. */
142+
private class MarkupEscapeFromPercentStringFormat extends MarkupSafeEscape,
143+
Markup::PercentStringFormat {
144+
override DataFlow::Node getAnInput() {
145+
result.asCfgNode() = node.getRight() and
146+
not result = Markup::instance()
147+
}
148+
149+
override DataFlow::Node getOutput() { result = this }
150+
}
130151
}

python/ql/test/library-tests/frameworks/markupsafe/taint_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def test():
3636
m_unsafe + SAFE, # $ escapeInput=SAFE escapeKind=html escapeOutput=BinaryExpr MISSING: tainted
3737
SAFE + m_unsafe, # $ escapeInput=SAFE escapeKind=html escapeOutput=BinaryExpr MISSING: tainted
3838
m_unsafe.format(SAFE), # $ escapeInput=SAFE escapeKind=html escapeOutput=m_unsafe.format(..) MISSING: tainted
39-
m_unsafe % SAFE, # $ tainted MISSING: escapeInput=ts escapeKind=html escapeOutput=BinaryExpr
39+
m_unsafe % SAFE, # $ escapeInput=SAFE escapeKind=html escapeOutput=BinaryExpr MISSING: tainted
4040
m_unsafe + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr MISSING: tainted
4141

4242
m_safe.format(m_unsafe), # $ tainted
@@ -56,7 +56,7 @@ def test():
5656
m_safe + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr
5757
ts + m_safe, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr
5858
m_safe.format(ts), # $ escapeInput=ts escapeKind=html escapeOutput=m_safe.format(..)
59-
m_safe % ts, # $ SPURIOUS: tainted MISSING: escapeInput=ts escapeKind=html escapeOutput=BinaryExpr
59+
m_safe % ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr
6060

6161
escape(ts) + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escapeOutput=escape(..)
6262
escape_silent(ts) + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escapeOutput=escape_silent(..)

0 commit comments

Comments
 (0)