@@ -17,18 +17,15 @@ import semmle.python.security.TaintTracking
1717import semmle.python.filters.Tests
1818
1919class HardcodedValue extends TaintKind {
20-
21- HardcodedValue ( ) {
22- this = "hard coded value"
23- }
24-
20+ HardcodedValue ( ) { this = "hard coded value" }
2521}
2622
2723bindingset [ char, fraction]
2824predicate fewer_characters_than ( StrConst str , string char , float fraction ) {
2925 exists ( string text , int chars |
3026 text = str .getText ( ) and
31- chars = count ( int i | text .charAt ( i ) = char ) |
27+ chars = count ( int i | text .charAt ( i ) = char )
28+ |
3229 /* Allow one character */
3330 chars = 1 or
3431 chars < text .length ( ) * fraction
@@ -47,118 +44,88 @@ predicate possible_reflective_name(string name) {
4744 exists ( Object:: builtin ( name ) )
4845}
4946
50- int char_count ( StrConst str ) {
51- result = count ( string c | c = str .getText ( ) .charAt ( _) )
52- }
47+ int char_count ( StrConst str ) { result = count ( string c | c = str .getText ( ) .charAt ( _) ) }
5348
54- predicate capitalized_word ( StrConst str ) {
55- str .getText ( ) .regexpMatch ( "[A-Z][a-z]+" )
56- }
49+ predicate capitalized_word ( StrConst str ) { str .getText ( ) .regexpMatch ( "[A-Z][a-z]+" ) }
5750
58- predicate format_string ( StrConst str ) {
59- str .getText ( ) .matches ( "%{%}%" )
60- }
51+ predicate format_string ( StrConst str ) { str .getText ( ) .matches ( "%{%}%" ) }
6152
6253predicate maybeCredential ( ControlFlowNode f ) {
6354 /* A string that is not too short and unlikely to be text or an identifier. */
64- exists ( StrConst str |
65- str = f .getNode ( ) |
55+ exists ( StrConst str | str = f .getNode ( ) |
6656 /* At least 10 characters */
6757 str .getText ( ) .length ( ) > 9 and
6858 /* Not too much whitespace */
6959 fewer_characters_than ( str , " " , 0.05 ) and
7060 /* or underscores */
7161 fewer_characters_than ( str , "_" , 0.2 ) and
7262 /* Not too repetitive */
73- exists ( int chars |
74- chars = char_count ( str ) |
63+ exists ( int chars | chars = char_count ( str ) |
7564 chars > 15 or
76- chars * 3 > str .getText ( ) .length ( ) * 2
65+ chars * 3 > str .getText ( ) .length ( ) * 2
7766 ) and
7867 not possible_reflective_name ( str .getText ( ) ) and
7968 not capitalized_word ( str ) and
8069 not format_string ( str )
8170 )
8271 or
8372 /* Or, an integer with over 32 bits */
84- exists ( IntegerLiteral lit |
85- f .getNode ( ) = lit
86- |
73+ exists ( IntegerLiteral lit | f .getNode ( ) = lit |
8774 not exists ( lit .getValue ( ) ) and
8875 /* Not a set of flags or round number */
8976 not lit .getN ( ) .matches ( "%00%" )
9077 )
9178}
9279
9380class HardcodedValueSource extends TaintSource {
81+ HardcodedValueSource ( ) { maybeCredential ( this ) }
9482
95- HardcodedValueSource ( ) {
96- maybeCredential ( this )
97- }
98-
99- override predicate isSourceOf ( TaintKind kind ) {
100- kind instanceof HardcodedValue
101- }
102-
83+ override predicate isSourceOf ( TaintKind kind ) { kind instanceof HardcodedValue }
10384}
10485
10586class CredentialSink extends TaintSink {
106-
10787 CredentialSink ( ) {
10888 exists ( string name |
10989 name .regexpMatch ( getACredentialRegex ( ) ) and
110- not name .suffix ( name .length ( ) - 4 ) = "file"
111- |
90+ not name .suffix ( name .length ( ) - 4 ) = "file"
91+ |
11292 any ( FunctionObject func ) .getNamedArgumentForCall ( _, name ) = this
11393 or
114- exists ( Keyword k |
115- k .getArg ( ) = name and k .getValue ( ) .getAFlowNode ( ) = this
116- )
94+ exists ( Keyword k | k .getArg ( ) = name and k .getValue ( ) .getAFlowNode ( ) = this )
11795 or
118- exists ( CompareNode cmp , NameNode n |
119- n .getId ( ) = name
120- |
96+ exists ( CompareNode cmp , NameNode n | n .getId ( ) = name |
12197 cmp .operands ( this , any ( Eq eq ) , n )
12298 or
12399 cmp .operands ( n , any ( Eq eq ) , this )
124100 )
125101 )
126102 }
127103
128-
129- override predicate sinks ( TaintKind kind ) {
130- kind instanceof HardcodedValue
131- }
132-
104+ override predicate sinks ( TaintKind kind ) { kind instanceof HardcodedValue }
133105}
134106
135107/**
136- * Gets a regular expression for matching names of locations (variables, parameters, keys) that
137- * indicate the value being held is a credential.
138- */
108+ * Gets a regular expression for matching names of locations (variables, parameters, keys) that
109+ * indicate the value being held is a credential.
110+ */
139111private string getACredentialRegex ( ) {
140- result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or
141- result = "(?i).*(puid|username|userid).*" or
142- result = "(?i).*(cert)(?!.*(format|name)).*"
112+ result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or
113+ result = "(?i).*(puid|username|userid).*" or
114+ result = "(?i).*(cert)(?!.*(format|name)).*"
143115}
144116
145117class HardcodedCredentialsConfiguration extends TaintTracking:: Configuration {
146-
147118 HardcodedCredentialsConfiguration ( ) { this = "Hardcoded coredentials configuration" }
148119
149- override predicate isSource ( TaintTracking:: Source source ) { source instanceof HardcodedValueSource }
150-
151- override predicate isSink ( TaintTracking:: Sink sink ) {
152- sink instanceof CredentialSink
120+ override predicate isSource ( TaintTracking:: Source source ) {
121+ source instanceof HardcodedValueSource
153122 }
154123
124+ override predicate isSink ( TaintTracking:: Sink sink ) { sink instanceof CredentialSink }
155125}
156126
157-
158-
159127from HardcodedCredentialsConfiguration config , TaintedPathSource src , TaintedPathSink sink
160-
161- where config .hasFlowPath ( src , sink ) and
162- not any ( TestScope test ) .contains ( src .getAstNode ( ) )
163-
128+ where
129+ config .hasFlowPath ( src , sink ) and
130+ not any ( TestScope test ) .contains ( src .getAstNode ( ) )
164131select sink .getSink ( ) , src , sink , "Use of $@." , src .getSource ( ) , "hardcoded credentials"
0 commit comments