This repository was archived by the owner on Jan 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 128
Expand file tree
/
Copy pathLogInjectionCustomizations.qll
More file actions
106 lines (95 loc) · 3.11 KB
/
LogInjectionCustomizations.qll
File metadata and controls
106 lines (95 loc) · 3.11 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
/**
* Provides default sources, sinks, and sanitizers for reasoning about
* log injection vulnerabilities, as well as extension points for adding your own.
*/
import go
private import semmle.go.StringOps
/**
* Provides extension points for customizing the data-flow tracking configuration for reasoning
* about log injection.
*/
module LogInjection {
/**
* A data flow source for log injection vulnerabilities.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for log injection vulnerabilities.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A sanitizer for log injection vulnerabilities.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A sanitizer guard for log injection vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A source of untrusted data, considered as a taint source for log injection. */
class UntrustedFlowAsSource extends Source {
UntrustedFlowAsSource() { this instanceof UntrustedFlowSource }
}
/** An argument to a logging mechanism. */
class LoggerSink extends Sink {
LoggerSink() { this = any(LoggerCall log).getAMessageComponent() }
}
/**
* A call to `strings.Replace` or `strings.ReplaceAll`, considered as a sanitizer
* for log injection.
*/
class ReplaceSanitizer extends Sanitizer {
ReplaceSanitizer() {
exists(string name, DataFlow::CallNode call |
this = call and
call.getTarget().hasQualifiedName("strings", name) and
call.getArgument(1).getStringValue().matches("%" + ["\r", "\n"] + "%")
|
name = "Replace" and
call.getArgument(3).getNumericValue() < 0
or
name = "ReplaceAll"
)
}
}
/**
* A call to `strings.Replacer.Replace`, considered as a sanitizer for log
* injection.
*/
class ReplacerReplaceSanitizer extends Sanitizer {
ReplacerReplaceSanitizer() {
exists(DataFlow::MethodCallNode call |
call.(DataFlow::MethodCallNode)
.getTarget()
.hasQualifiedName("strings", "Replacer", "Replace") and
this = call.getResult()
)
}
}
/**
* A call to `strings.Replacer.WriteString`, considered as a sanitizer for log
* injection.
*/
class ReplacerWriteStringSanitizer extends Sanitizer {
ReplacerWriteStringSanitizer() {
exists(DataFlow::MethodCallNode call |
call.getTarget().hasQualifiedName("strings", "Replacer", "WriteString") and
this = call.getArgument(1)
)
}
}
/**
* An argument that is formatted using the `%q` directive, considered as a sanitizer
* for log injection.
*
* This formatting directive replaces newline characters with escape sequences.
*/
private class SafeFormatArgumentSanitizer extends Sanitizer {
SafeFormatArgumentSanitizer() {
exists(StringOps::Formatting::StringFormatCall call, string safeDirective |
this = call.getOperand(_, safeDirective) and
// Mark "%q" formats as safe, but not "%#q", which would preserve newline characters.
safeDirective.regexpMatch("%[^%#]*q")
)
}
}
}