Skip to content

Commit 686638a

Browse files
authored
Merge pull request github#6049 from RasmusWL/jmespath
Python: Add modeling of `jmespath`
2 parents 4a19a99 + 447099a commit 686638a

File tree

9 files changed

+78
-0
lines changed

9 files changed

+78
-0
lines changed

docs/codeql/support/reusables/frameworks.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ Python built-in support
164164
fabric, Utility library
165165
idna, Utility library
166166
invoke, Utility library
167+
jmespath, Utility library
167168
multidict, Utility library
168169
yarl, Utility library
169170
aioch, Database
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Added modeling of the PyPI package `jmespath`.

python/ql/src/semmle/python/Frameworks.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ private import semmle.python.frameworks.Fabric
1515
private import semmle.python.frameworks.Flask
1616
private import semmle.python.frameworks.Idna
1717
private import semmle.python.frameworks.Invoke
18+
private import semmle.python.frameworks.Jmespath
1819
private import semmle.python.frameworks.Multidict
1920
private import semmle.python.frameworks.Mysql
2021
private import semmle.python.frameworks.MySQLdb
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `jmespath` PyPI package.
3+
* See https://pypi.org/project/jmespath/.
4+
*/
5+
6+
private import python
7+
private import semmle.python.dataflow.new.DataFlow
8+
private import semmle.python.dataflow.new.TaintTracking
9+
private import semmle.python.Concepts
10+
private import semmle.python.ApiGraphs
11+
12+
/**
13+
* Provides models for the `jmespath` PyPI package.
14+
* See https://pypi.org/project/jmespath/.
15+
*/
16+
private module Jmespath {
17+
class JmespathAdditionalTaintSteps extends TaintTracking::AdditionalTaintStep {
18+
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
19+
exists(DataFlow::CallCfgNode call |
20+
call = API::moduleImport("jmespath").getMember("search").getACall() and
21+
nodeFrom in [call.getArg(1), call.getArgByName("data")] and
22+
nodeTo = call
23+
or
24+
call =
25+
API::moduleImport("jmespath")
26+
.getMember("compile")
27+
.getReturn()
28+
.getMember("search")
29+
.getACall() and
30+
nodeFrom in [call.getArg(0), call.getArgByName("value")] and
31+
nodeTo = call
32+
)
33+
}
34+
}
35+
}

python/ql/test/library-tests/frameworks/jmespath/ConceptsTest.expected

Whitespace-only changes.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import python
2+
import experimental.meta.ConceptsTest
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
argumentToEnsureNotTaintedNotMarkedAsSpurious
2+
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
3+
failures
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import experimental.meta.InlineTaintTest
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import jmespath
2+
3+
def test_taint():
4+
untrusted_data = TAINTED_DICT
5+
6+
safe_expression = jmespath.compile("foo.bar")
7+
8+
ensure_tainted(
9+
jmespath.search("foo.bar", untrusted_data), # $ tainted
10+
jmespath.search("foo.bar", data=untrusted_data), # $ tainted
11+
12+
safe_expression.search(untrusted_data), # $ tainted
13+
safe_expression.search(value=untrusted_data) # $ tainted
14+
)
15+
16+
# since ```jmespath.search("{wat: `foo`}", {})``` works (and outputs a dictionary),
17+
# we _could_ add a taint-step from the search expression to the output. However, it
18+
# seems more likely to lead to FPs than good results, so these have deliberately not
19+
# been included.
20+
21+
ts = TAINTED_STRING
22+
safe_data = {"foo": "bar"}
23+
24+
unsafe_expression = jmespath.compile(ts)
25+
26+
ensure_not_tainted(
27+
jmespath.search(ts, safe_data),
28+
jmespath.search(expression=ts, data=safe_data),
29+
30+
unsafe_expression,
31+
unsafe_expression.search(safe_data),
32+
unsafe_expression.search(value=safe_data),
33+
)

0 commit comments

Comments
 (0)