mirror of
https://github.com/github/codeql.git
synced 2026-03-23 16:06:47 +01:00
Problematic part is
```codeql
/** A escape from string format with `markupsafe.Markup` as the format string. */
private class MarkupEscapeFromStringFormat extends MarkupSafeEscape, Markup::StringFormat {
override DataFlow::Node getAnInput() {
result in [this.getArg(_), this.getArgByName(_)] and
not result = Markup::instance()
}
override DataFlow::Node getOutput() { result = this }
}
```
since the char-pred still holds even if `getAnInput` has no results...
I will say that doing it this way feels kinda dirty, and we _could_ fix
this by including the logic in `getAnInput` in the char-pred as well.
But as I see it, that would just lead to a lot of code duplication,
which isn't very nice.
79 lines
3.1 KiB
Python
79 lines
3.1 KiB
Python
from markupsafe import escape, escape_silent, Markup
|
|
|
|
def ensure_tainted(*args):
|
|
print("ensure_tainted")
|
|
for x in args: print(" ", x)
|
|
|
|
def ensure_not_tainted(*args):
|
|
print("ensure_not_tainted")
|
|
for x in args: print(" ", x)
|
|
|
|
# these contain `{}` so we can use .format
|
|
TAINTED_STRING = '<"TAINTED_STRING" {}>'
|
|
SAFE = "SAFE {}"
|
|
|
|
def test():
|
|
ts = TAINTED_STRING
|
|
|
|
# class `Markup` can be used for things that are already safe.
|
|
# if used with any text in a string operation, that other text will be escaped.
|
|
#
|
|
# see https://markupsafe.palletsprojects.com/en/2.0.x/
|
|
m_unsafe = Markup(TAINTED_STRING)
|
|
m_safe = Markup(SAFE)
|
|
|
|
|
|
# this 3 tests might look strange, but the purpose is to check we still treat `ts`
|
|
# as tainted even after it has been escaped in some place. This _might_ not be the
|
|
# case since data-flow library has taint-steps from adjacent uses...
|
|
ensure_tainted(ts) # $ tainted
|
|
ensure_not_tainted(escape(ts)) # $ escapeInput=ts escapeKind=html escapeOutput=escape(..)
|
|
ensure_tainted(ts) # $ tainted
|
|
|
|
ensure_tainted(
|
|
ts, # $ tainted
|
|
m_unsafe, # $ tainted
|
|
m_unsafe + SAFE, # $ escapeInput=SAFE escapeKind=html escapeOutput=BinaryExpr MISSING: tainted
|
|
SAFE + m_unsafe, # $ escapeInput=SAFE escapeKind=html escapeOutput=BinaryExpr MISSING: tainted
|
|
m_unsafe.format(SAFE), # $ escapeInput=SAFE escapeKind=html escapeOutput=m_unsafe.format(..) MISSING: tainted
|
|
m_unsafe + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr MISSING: tainted
|
|
|
|
m_safe.format(m_unsafe), # $ tainted
|
|
|
|
escape(ts).unescape(), # $ escapeInput=ts escapeKind=html escapeOutput=escape(..) MISSING: tainted
|
|
escape_silent(ts).unescape(), # $ escapeInput=ts escapeKind=html escapeOutput=escape_silent(..) MISSING: tainted
|
|
)
|
|
|
|
ensure_not_tainted(
|
|
escape(ts), # $ escapeInput=ts escapeKind=html escapeOutput=escape(..)
|
|
escape_silent(ts), # $ escapeInput=ts escapeKind=html escapeOutput=escape_silent(..)
|
|
|
|
Markup.escape(ts), # $ escapeInput=ts escapeKind=html escapeOutput=Markup.escape(..)
|
|
|
|
m_safe,
|
|
m_safe + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr
|
|
ts + m_safe, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr
|
|
m_safe.format(ts), # $ escapeInput=ts escapeKind=html escapeOutput=m_safe.format(..)
|
|
|
|
escape(ts) + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escapeOutput=escape(..)
|
|
escape_silent(ts) + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escapeOutput=escape_silent(..)
|
|
Markup.escape(ts) + ts, # $ escapeInput=ts escapeKind=html escapeOutput=BinaryExpr escapeOutput=Markup.escape(..)
|
|
)
|
|
|
|
# flask re-exports these, as:
|
|
# flask.escape = markupsafe.escape
|
|
# flask.Markup = markupsafe.Markup
|
|
import flask
|
|
|
|
ensure_tainted(
|
|
flask.Markup(ts), # $ tainted
|
|
)
|
|
|
|
ensure_not_tainted(
|
|
flask.escape(ts), # $ escapeInput=ts escapeKind=html escapeOutput=flask.escape(..)
|
|
flask.Markup.escape(ts), # $ escapeInput=ts escapeKind=html escapeOutput=flask.Markup.escape(..)
|
|
)
|
|
|
|
|
|
test()
|