Skip to content

Commit 350f79e

Browse files
committed
Python: Model sensitive data based on variable names
1 parent f5fd0f8 commit 350f79e

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

python/ql/src/semmle/python/dataflow/new/SensitiveDataSources.qll

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,43 @@ private module SensitiveDataModeling {
111111
override SensitiveDataClassification getClassification() { result = classification }
112112
}
113113

114+
/**
115+
* Any kind of variable assignment (also including with/for) where the name indicates
116+
* it contains sensitive data.
117+
*
118+
* Note: We _could_ make any access to a variable with a sensitive name a source of
119+
* sensitive data, but to make path explanations in data-flow/taint-tracking good,
120+
* we don't want that, since it works against allowing users to understand the flow
121+
* in the program (which is the whole point).
122+
*
123+
* Note: To make data-flow/taint-tracking work, the expression that is _assigned_ to
124+
* the variable is marked as the source (as compared to marking the variable as the
125+
* source).
126+
*/
127+
class SensitiveVariableAssignment extends SensitiveDataSource::Range {
128+
SensitiveDataClassification classification;
129+
130+
SensitiveVariableAssignment() {
131+
exists(DefinitionNode def |
132+
nameIndicatesSensitiveData(def.(NameNode).getId(), classification) and
133+
(
134+
this.asCfgNode() = def.getValue()
135+
or
136+
this.asCfgNode() = def.getValue().(ForNode).getSequence()
137+
) and
138+
not this.asExpr() instanceof FunctionExpr and
139+
not this.asExpr() instanceof ClassExpr
140+
)
141+
or
142+
exists(With with |
143+
nameIndicatesSensitiveData(with.getOptionalVars().(Name).getId(), classification) and
144+
this.asExpr() = with.getContextExpr()
145+
)
146+
}
147+
148+
override SensitiveDataClassification getClassification() { result = classification }
149+
}
150+
114151
/** An attribute access that is considered a source of sensitive data. */
115152
class SensitiveAttributeAccess extends SensitiveDataSource::Range {
116153
SensitiveDataClassification classification;

python/ql/test/experimental/dataflow/sensitive-data/TestSensitiveDataSources.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import python
22
import semmle.python.dataflow.new.DataFlow
3+
import semmle.python.dataflow.new.TaintTracking
34
import TestUtilities.InlineExpectationsTest
45
import semmle.python.dataflow.new.SensitiveDataSources
56
private import semmle.python.ApiGraphs
@@ -21,7 +22,7 @@ class SensitiveDataSourcesTest extends InlineExpectationsTest {
2122
or
2223
exists(DataFlow::Node use |
2324
use = API::builtin("print").getACall().getArg(_) and
24-
DataFlow::localFlow(source, use) and
25+
TaintTracking::localTaint(source, use) and
2526
location = use.getLocation() and
2627
element = use.toString() and
2728
value = source.getClassification() and

python/ql/test/experimental/dataflow/sensitive-data/test.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,20 @@ def encrypt_password(pwd):
2929
foo.secret # $ SensitiveDataSource=secret
3030
foo.username # $ SensitiveDataSource=id
3131

32+
3233
# based on variable/parameter names
3334
def my_func(password): # $ SensitiveDataSource=password
3435
print(password) # $ SensitiveUse=password
3536

36-
password = some_function()
37-
print(password) # $ MISSING: SensitiveUse=password
37+
password = some_function() # $ SensitiveDataSource=password
38+
print(password) # $ SensitiveUse=password
39+
40+
for password in some_function2(): # $ SensitiveDataSource=password
41+
print(password) # $ SensitiveUse=password
42+
43+
with some_function3() as password: # $ SensitiveDataSource=password
44+
print(password) # $ SensitiveUse=password
45+
3846

3947
# Special handling of lookups of sensitive properties
4048
request.args["password"], # $ SensitiveDataSource=password

0 commit comments

Comments
 (0)