-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathSensitiveActions.qll
More file actions
129 lines (116 loc) · 4.44 KB
/
SensitiveActions.qll
File metadata and controls
129 lines (116 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* Sensitive data and methods for security.
*
* 'Sensitive' data in general is anything that should not be
* sent around in unencrypted form. This library tries to guess
* where sensitive data may either be stored in a variable or
* produced by a method.
*
* In addition, there are methods that ought not to be executed or not
* in a fashion that the user can control. This includes authorization
* methods such as logins, and sending of data, etc.
*/
overlay[local?]
module;
import java
private string suspicious() {
result =
[
"%password%", "%passwd%", "pwd", "%account%", "%accnt%", "%trusted%", "%refresh%token%",
"%secret%token"
]
}
private string nonSuspicious() {
result = "%hashed%" or
result = "%encrypted%" or
result = "%crypt%"
}
/**
* Gets a regular expression for matching common names of variables that
* indicate the value being held contains sensitive information.
*/
string getCommonSensitiveInfoRegex() {
result = "(?i).*(challenge|pass(wd|word|code|phrase))(?!.*question).*" or
result = "(?i).*(token|secret).*"
}
/**
* Gets a regular expression for matching common names of variables that
* indicate the value being held does not contain sensitive information,
* but is a false positive for `getCommonSensitiveInfoRegex`.
*
* - "tokenizer" is often used for java.util.StringTokenizer.
* - "tokenImage" appears in parser code generated by JavaCC.
* - Pagination/iteration tokens: "nextToken" (AWS SDK), "pageToken" (GCP), etc.
* - Token metadata: "tokenType" (OAuth), "tokenEndpoint" (OIDC), "tokenCount", etc.
* - Secret metadata: "secretName" (K8s/AWS), "secretId" (Azure), "secretVersion", etc.
*/
string getCommonSensitiveInfoFPRegex() {
result = "(?i).*(null|tokenizer).*"
or
result = "tokenImage"
or
// Pagination/iteration tokens (e.g., AWS SDK pagination cursors, parser tokens)
result = "(?i).*(next|previous|current|page|continuation|cursor)tokens?.*"
or
// Token metadata/infrastructure (token followed by a non-value descriptor)
result =
"(?i).*tokens?(type|kind|count|index|position|length|offset|endpoint|url|uri|bucket|rate|delimiter|separator|format|number|name|id|prefix|suffix|pattern|class|style).*"
or
// Secret metadata (secret followed by a non-value descriptor)
result =
"(?i).*secrets?(name|id|version|ref|arn|path|type|label|description|manager|client|provider|store|factory|properties).*"
}
/** An expression that might contain sensitive data. */
abstract class SensitiveExpr extends Expr { }
/** A method access that might produce sensitive data. */
class SensitiveMethodCall extends SensitiveExpr, MethodCall {
SensitiveMethodCall() {
this.getMethod() instanceof SensitiveDataMethod
or
// This is particularly to pick up methods with an argument like "password", which
// may indicate a lookup.
exists(string s | this.getAnArgument().(StringLiteral).getValue().toLowerCase() = s |
s.matches(suspicious()) and
not s.matches(nonSuspicious())
)
}
}
/** Access to a variable that might contain sensitive data. */
class SensitiveVarAccess extends SensitiveExpr, VarAccess {
SensitiveVarAccess() {
exists(string s | this.getVariable().getName().toLowerCase() = s |
s.matches(suspicious()) and
not s.matches(nonSuspicious())
)
}
}
/** A method that may produce sensitive data. */
abstract class SensitiveDataMethod extends Method { }
class CredentialsMethod extends SensitiveDataMethod {
CredentialsMethod() {
exists(string s | s = this.getName().toLowerCase() | s.matches(suspicious()))
}
}
/** A method whose execution may be sensitive. */
abstract class SensitiveExecutionMethod extends Method { }
/** A method that may perform authorization. */
class AuthMethod extends SensitiveExecutionMethod {
AuthMethod() {
exists(string s | s = this.getName().toLowerCase() |
s.matches(["%login%", "%auth%"]) and
not s.matches(["get%", "set%", "parse%", "%loginfo%", "remove%", "clean%", "%unauth%"]) and
// exclude "author", but not "authorize" or "authority"
not s.regexpMatch(".*[aA]uthors?([A-Z0-9_].*|$)")
) and
not this.getDeclaringType().getAnAncestor() instanceof TypeException
}
}
/** A method that sends data, and so should not be run conditionally on user input. */
class SendingMethod extends SensitiveExecutionMethod {
SendingMethod() {
exists(string s | s.matches("%Socket") |
this.getDeclaringType().hasQualifiedName("java.net", s) and
this.hasName("send")
)
}
}