Skip to content

Commit f151338

Browse files
authored
Merge pull request github#6198 from RasmusWL/fix-cleartext-logging
Python: Some minor fixes to `py/clear-text-logging-sensitive-data`
2 parents 8b7db8a + b0309dd commit f151338

File tree

3 files changed

+47
-21
lines changed

3 files changed

+47
-21
lines changed

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

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -76,28 +76,16 @@ private module SensitiveDataModeling {
7676
}
7777

7878
/**
79-
* Gets a reference to a string constant that, if used as the key in a lookup,
80-
* indicates the presence of sensitive data with `classification`.
81-
*/
82-
private DataFlow::LocalSourceNode sensitiveLookupStringConst(
83-
DataFlow::TypeTracker t, SensitiveDataClassification classification
84-
) {
85-
t.start() and
86-
nameIndicatesSensitiveData(result.asExpr().(StrConst).getText(), classification)
87-
or
88-
exists(DataFlow::TypeTracker t2 |
89-
result = sensitiveLookupStringConst(t2, classification).track(t2, t)
90-
)
91-
}
92-
93-
/**
94-
* Gets a reference to a string constant that, if used as the key in a lookup,
95-
* indicates the presence of sensitive data with `classification`.
96-
*
97-
* Also see `extraStepForCalls`.
79+
* Gets a reference (in local scope) to a string constant that, if used as the key in
80+
* a lookup, indicates the presence of sensitive data with `classification`.
9881
*/
9982
DataFlow::Node sensitiveLookupStringConst(SensitiveDataClassification classification) {
100-
sensitiveLookupStringConst(DataFlow::TypeTracker::end(), classification).flowsTo(result)
83+
// Note: If this is implemented with type-tracking, we will get cross-talk as
84+
// illustrated in python/ql/test/experimental/dataflow/sensitive-data/test.py
85+
exists(DataFlow::LocalSourceNode source |
86+
nameIndicatesSensitiveData(source.asExpr().(StrConst).getText(), classification) and
87+
source.flowsTo(result)
88+
)
10189
}
10290

10391
/** A function call that is considered a source of sensitive data. */
@@ -118,6 +106,8 @@ private module SensitiveDataModeling {
118106
/**
119107
* Tracks any modeled source of sensitive data (with any classification),
120108
* to limit the scope of `extraStepForCalls`. See it's QLDoc for more context.
109+
*
110+
* Also see `extraStepForCalls`.
121111
*/
122112
private DataFlow::LocalSourceNode possibleSensitiveCallable(DataFlow::TypeTracker t) {
123113
t.start() and
@@ -129,6 +119,8 @@ private module SensitiveDataModeling {
129119
/**
130120
* Tracks any modeled source of sensitive data (with any classification),
131121
* to limit the scope of `extraStepForCalls`. See it's QLDoc for more context.
122+
*
123+
* Also see `extraStepForCalls`.
132124
*/
133125
private DataFlow::Node possibleSensitiveCallable() {
134126
possibleSensitiveCallable(DataFlow::TypeTracker::end()).flowsTo(result)

python/ql/src/semmle/python/security/dataflow/CleartextLoggingCustomizations.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ module CleartextLogging {
5151
}
5252

5353
/** A piece of data printed, considered as a flow sink. */
54-
class PrintedDataAsSink extends Sink, DataFlow::CallCfgNode {
54+
class PrintedDataAsSink extends Sink {
5555
PrintedDataAsSink() {
5656
this = API::builtin("print").getACall().getArg(_)
5757
or

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,37 @@ def my_func(password): # $ SensitiveDataSource=password
7878

7979
from not_found import password2 as foo # $ SensitiveDataSource=password
8080
print(foo) # $ SensitiveUse=password
81+
82+
# ------------------------------------------------------------------------------
83+
# cross-talk between different calls
84+
# ------------------------------------------------------------------------------
85+
86+
# Case 1: providing name as argument
87+
88+
_configuration = {"sleep_timer": 5, "mysql_password": "1234"}
89+
90+
def get_config(key):
91+
# Treating this as a SensitiveDataSource is questionable, since that will result in
92+
# _all_ calls to `get_config` being treated as giving sensitive data
93+
return _configuration[key]
94+
95+
foo = get_config("mysql_password")
96+
print(foo) # $ MISSING: SensitiveUse=password
97+
98+
bar = get_config("sleep_timer")
99+
print(bar)
100+
101+
# Case 2: Providing function as argument
102+
103+
def call_wrapper(func):
104+
print("Will call", func)
105+
# Treating this as a SensitiveDataSource is questionable, since that will result in
106+
# _all_ calls to `call_wrapper` being treated as giving sensitive data
107+
return func() # $ SensitiveDataSource=password
108+
109+
foo = call_wrapper(get_password)
110+
print(foo) # $ SensitiveUse=password
111+
112+
harmless = lambda: "bar"
113+
bar = call_wrapper(harmless)
114+
print(bar) # $ SPURIOUS: SensitiveUse=password

0 commit comments

Comments
 (0)