narvy-cli 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- narvy/__init__.py +3 -0
- narvy/android/__init__.py +0 -0
- narvy/android/source_analyzer.py +268 -0
- narvy/android/split_bundle.py +475 -0
- narvy/android_rule_context.py +196 -0
- narvy/apk_memory_preflight.py +248 -0
- narvy/auth.py +40 -0
- narvy/ci_templates/bitbucket.yml +25 -0
- narvy/ci_templates/github.yml +60 -0
- narvy/ci_templates/gitlab.yml +32 -0
- narvy/cloud/__init__.py +0 -0
- narvy/cloud/aws_scan.py +1188 -0
- narvy/comment_filter.py +134 -0
- narvy/crypto_taint_lite.py +82 -0
- narvy/decompiler.py +337 -0
- narvy/doctor.py +244 -0
- narvy/host/__init__.py +0 -0
- narvy/host/audit.py +157 -0
- narvy/host/host_knowledge.py +982 -0
- narvy/host/lynis_bootstrap.py +400 -0
- narvy/host/lynis_parser.py +358 -0
- narvy/host/narvy_checks.py +789 -0
- narvy/host/report.py +69 -0
- narvy/host/ssh_exec.py +219 -0
- narvy/ios/__init__.py +0 -0
- narvy/ios/binary_analyzer.py +1201 -0
- narvy/ios/plist_checks.py +249 -0
- narvy/ios/source_analyzer.py +301 -0
- narvy/ios/third_party_filter.py +242 -0
- narvy/ios/trust_all_context.py +66 -0
- narvy/main.py +1983 -0
- narvy/native_hardening.py +503 -0
- narvy/reporter.py +151 -0
- narvy/rule_engine.py +57 -0
- narvy/rules/android/config.yml +77 -0
- narvy/rules/android/crypto.yml +34 -0
- narvy/rules/android/secrets.yml +161 -0
- narvy/rules/android/storage.yml +24 -0
- narvy/rules/android/webview.yml +23 -0
- narvy/rules/android.yml +219 -0
- narvy/rules/ios/objc/crypto.yml +56 -0
- narvy/rules/ios/objc/network.yml +67 -0
- narvy/rules/ios/objc/secrets.yml +79 -0
- narvy/rules/ios/objc/storage.yml +45 -0
- narvy/rules/ios/objc/webview.yml +45 -0
- narvy/rules/ios_swift.yml +327 -0
- narvy/rules/web/go.yml +2837 -0
- narvy/rules/web/java.yml +1576 -0
- narvy/rules/web/javascript.yml +3683 -0
- narvy/rules/web/kotlin.yml +413 -0
- narvy/rules/web/local/csharp_narvy/config.yml +61 -0
- narvy/rules/web/local/csharp_narvy/crypto.yml +64 -0
- narvy/rules/web/local/csharp_narvy/deserialization.yml +59 -0
- narvy/rules/web/local/csharp_narvy/injection.yml +122 -0
- narvy/rules/web/local/csharp_narvy/xxe.yml +48 -0
- narvy/rules/web/local/java_narvy/auth_jwt.yml +134 -0
- narvy/rules/web/local/java_narvy/deserialization.yml +108 -0
- narvy/rules/web/local/java_narvy/mybatis.yml +39 -0
- narvy/rules/web/local/java_narvy/snakeyaml.yml +34 -0
- narvy/rules/web/local/java_narvy/spring_authz.yml +32 -0
- narvy/rules/web/local/java_narvy/spring_config.yml +67 -0
- narvy/rules/web/local/java_narvy/spring_hardening.yml +291 -0
- narvy/rules/web/local/java_narvy/sqli.yml +235 -0
- narvy/rules/web/local/java_narvy/xxe.yml +212 -0
- narvy/rules/web/php.yml +1644 -0
- narvy/rules/web/python.yml +3967 -0
- narvy/rules/web/ruby.yml +703 -0
- narvy/rules/web/rust.yml +258 -0
- narvy/rules/web/secrets.yml +1420 -0
- narvy/rules/web/secrets_supplement.yml +383 -0
- narvy/sca/__init__.py +1 -0
- narvy/sca/android_deps.py +349 -0
- narvy/sca/ios_deps.py +578 -0
- narvy/sca/osv_client.py +617 -0
- narvy/sca/web_deps.py +955 -0
- narvy/scope_config.py +195 -0
- narvy/semgrep_engine.py +219 -0
- narvy/stack_protector_evidence.py +96 -0
- narvy/third_party_filter.py +211 -0
- narvy/uploader.py +92 -0
- narvy/weak_prng_context.py +270 -0
- narvy/web/__init__.py +0 -0
- narvy/web/nuclei_binary.py +105 -0
- narvy/web/scan_blocklist.py +96 -0
- narvy/web/scanner.py +842 -0
- narvy/web/source_analyzer.py +714 -0
- narvy/web/ssrf_guard.py +374 -0
- narvy_cli-1.0.0.dist-info/METADATA +165 -0
- narvy_cli-1.0.0.dist-info/RECORD +93 -0
- narvy_cli-1.0.0.dist-info/WHEEL +5 -0
- narvy_cli-1.0.0.dist-info/entry_points.txt +2 -0
- narvy_cli-1.0.0.dist-info/licenses/LICENSE +202 -0
- narvy_cli-1.0.0.dist-info/top_level.txt +1 -0
narvy/rules/web/go.yml
ADDED
|
@@ -0,0 +1,2837 @@
|
|
|
1
|
+
# Go security rules, authored by Narvy.
|
|
2
|
+
# Injection, path traversal, SSRF, CORS, cookies, weak crypto, secrets.
|
|
3
|
+
|
|
4
|
+
rules:
|
|
5
|
+
- id: narvy.go.auth.insecure-string-compare-secret.insecure-string-compare-secret
|
|
6
|
+
message: A secret/token/signature/HMAC comparison uses `==` (or `strings.Compare`) instead of a constant-time comparison.
|
|
7
|
+
`==` short-circuits on the first mismatched byte, so response timing leaks how many leading bytes were correct - a timing
|
|
8
|
+
side-channel an attacker can use to recover the secret byte-by-byte (CWE-208). Use `subtle.ConstantTimeCompare()` or `hmac.Equal()`.
|
|
9
|
+
severity: WARNING
|
|
10
|
+
languages:
|
|
11
|
+
- go
|
|
12
|
+
metadata:
|
|
13
|
+
category: security
|
|
14
|
+
cwe:
|
|
15
|
+
- 'CWE-208: Observable Timing Discrepancy'
|
|
16
|
+
owasp:
|
|
17
|
+
- A07:2021 - Identification and Authentication Failures
|
|
18
|
+
subcategory:
|
|
19
|
+
- vuln
|
|
20
|
+
likelihood: LOW
|
|
21
|
+
impact: MEDIUM
|
|
22
|
+
confidence: LOW
|
|
23
|
+
technology:
|
|
24
|
+
- go
|
|
25
|
+
patterns:
|
|
26
|
+
- pattern-either:
|
|
27
|
+
- pattern: $SIG == $EXPECTED
|
|
28
|
+
- metavariable-regex:
|
|
29
|
+
metavariable: $SIG
|
|
30
|
+
regex: (?i).*(sig|signature|hmac|mac|token|secret)$
|
|
31
|
+
- pattern-not: $SIG == nil
|
|
32
|
+
- pattern-not: nil == $SIG
|
|
33
|
+
- pattern-not: $SIG == ""
|
|
34
|
+
- pattern-not: '"" == $SIG'
|
|
35
|
+
- metavariable-pattern:
|
|
36
|
+
metavariable: $EXPECTED
|
|
37
|
+
patterns:
|
|
38
|
+
- pattern-not: nil
|
|
39
|
+
- pattern-not: '""'
|
|
40
|
+
- id: narvy.go.auth.cookie-httponly-unset.cookie-httponly-unset
|
|
41
|
+
message: 'A session cookie is set (`http.SetCookie` with a name containing `session`) without `HttpOnly: true`. Without
|
|
42
|
+
it, JavaScript on the page (including an attacker''s, via any XSS) can read the cookie and exfiltrate it (CWE-1004). Set
|
|
43
|
+
`HttpOnly: true` on every session cookie.'
|
|
44
|
+
severity: WARNING
|
|
45
|
+
languages:
|
|
46
|
+
- go
|
|
47
|
+
metadata:
|
|
48
|
+
category: security
|
|
49
|
+
cwe:
|
|
50
|
+
- 'CWE-1004: Sensitive Cookie Without ''HttpOnly'' Flag'
|
|
51
|
+
owasp:
|
|
52
|
+
- A05:2021 - Security Misconfiguration
|
|
53
|
+
subcategory:
|
|
54
|
+
- vuln
|
|
55
|
+
likelihood: LOW
|
|
56
|
+
impact: MEDIUM
|
|
57
|
+
confidence: LOW
|
|
58
|
+
technology:
|
|
59
|
+
- go
|
|
60
|
+
patterns:
|
|
61
|
+
- pattern: 'http.SetCookie($W, &http.Cookie{..., Name: $NAME, ...})
|
|
62
|
+
|
|
63
|
+
'
|
|
64
|
+
- pattern-not: 'http.SetCookie($W, &http.Cookie{..., HttpOnly: true, ...})
|
|
65
|
+
|
|
66
|
+
'
|
|
67
|
+
- metavariable-regex:
|
|
68
|
+
metavariable: $NAME
|
|
69
|
+
regex: (?i).*session.*
|
|
70
|
+
- id: narvy.go.auth.cookie-secure-unset.cookie-secure-unset
|
|
71
|
+
message: 'A session cookie is set without `Secure: true`. Without it, the browser will also send the cookie over a plaintext
|
|
72
|
+
`http://` connection, letting a network attacker capture it (CWE-614). Set `Secure: true` on every session cookie in production.'
|
|
73
|
+
severity: WARNING
|
|
74
|
+
languages:
|
|
75
|
+
- go
|
|
76
|
+
metadata:
|
|
77
|
+
category: security
|
|
78
|
+
cwe:
|
|
79
|
+
- 'CWE-614: Sensitive Cookie in HTTPS Session Without ''Secure'' Attribute'
|
|
80
|
+
owasp:
|
|
81
|
+
- A05:2021 - Security Misconfiguration
|
|
82
|
+
subcategory:
|
|
83
|
+
- vuln
|
|
84
|
+
likelihood: LOW
|
|
85
|
+
impact: MEDIUM
|
|
86
|
+
confidence: LOW
|
|
87
|
+
technology:
|
|
88
|
+
- go
|
|
89
|
+
patterns:
|
|
90
|
+
- pattern: 'http.SetCookie($W, &http.Cookie{..., Name: $NAME, ...})
|
|
91
|
+
|
|
92
|
+
'
|
|
93
|
+
- pattern-not: 'http.SetCookie($W, &http.Cookie{..., Secure: true, ...})
|
|
94
|
+
|
|
95
|
+
'
|
|
96
|
+
- metavariable-regex:
|
|
97
|
+
metavariable: $NAME
|
|
98
|
+
regex: (?i).*session.*
|
|
99
|
+
- id: narvy.go.auth.cookie-samesite-none-mode-set.cookie-samesite-none-mode-set
|
|
100
|
+
message: 'A session cookie is set with `SameSite: http.SameSiteNoneMode`. `None` disables the CSRF-mitigating same-site
|
|
101
|
+
restriction entirely, sending the cookie on every cross-site request (CWE-352). Use `http.SameSiteLaxMode` (or `Strict`
|
|
102
|
+
for the most sensitive flows) unless the cookie genuinely needs to be sent from a third-party context, and pair `None`
|
|
103
|
+
with a separate CSRF token if it is required.'
|
|
104
|
+
severity: WARNING
|
|
105
|
+
languages:
|
|
106
|
+
- go
|
|
107
|
+
metadata:
|
|
108
|
+
category: security
|
|
109
|
+
cwe:
|
|
110
|
+
- 'CWE-352: Cross-Site Request Forgery (CSRF)'
|
|
111
|
+
owasp:
|
|
112
|
+
- A01:2021 - Broken Access Control
|
|
113
|
+
subcategory:
|
|
114
|
+
- vuln
|
|
115
|
+
likelihood: LOW
|
|
116
|
+
impact: MEDIUM
|
|
117
|
+
confidence: MEDIUM
|
|
118
|
+
technology:
|
|
119
|
+
- go
|
|
120
|
+
pattern: 'http.SetCookie($W, &http.Cookie{..., SameSite: http.SameSiteNoneMode, ...})
|
|
121
|
+
|
|
122
|
+
'
|
|
123
|
+
- id: narvy-go-cmdi-splat-args
|
|
124
|
+
patterns:
|
|
125
|
+
- pattern-either:
|
|
126
|
+
- pattern: 'exec.Command($ARGS[$IDX], ...)
|
|
127
|
+
|
|
128
|
+
'
|
|
129
|
+
- pattern: 'exec.CommandContext($CTX, $ARGS[$IDX], ...)
|
|
130
|
+
|
|
131
|
+
'
|
|
132
|
+
- pattern-not: 'exec.Command("...", ...)
|
|
133
|
+
|
|
134
|
+
'
|
|
135
|
+
- pattern-not: 'exec.CommandContext($CTX, "...", ...)
|
|
136
|
+
|
|
137
|
+
'
|
|
138
|
+
message: 'Command injection: `exec.Command` first argument is an indexed slice expression (e.g. `args[0]`), which means
|
|
139
|
+
the executable path itself is user-controlled. Even with subsequent arguments fixed, the attacker can run arbitrary binaries.
|
|
140
|
+
Use an allow-list of binary names.'
|
|
141
|
+
metadata:
|
|
142
|
+
cwe:
|
|
143
|
+
- 'CWE-78: Improper Neutralization of Special Elements used in an OS Command (''OS Command Injection'')'
|
|
144
|
+
owasp:
|
|
145
|
+
- A03:2021 - Injection
|
|
146
|
+
category: security
|
|
147
|
+
technology:
|
|
148
|
+
- go
|
|
149
|
+
confidence: HIGH
|
|
150
|
+
subcategory:
|
|
151
|
+
- vuln
|
|
152
|
+
likelihood: HIGH
|
|
153
|
+
impact: HIGH
|
|
154
|
+
severity: ERROR
|
|
155
|
+
languages:
|
|
156
|
+
- go
|
|
157
|
+
- id: narvy-go-syscall-exec-tainted
|
|
158
|
+
patterns:
|
|
159
|
+
- pattern-either:
|
|
160
|
+
- pattern: syscall.Exec($BIN, ...)
|
|
161
|
+
- pattern: syscall.ForkExec($BIN, ...)
|
|
162
|
+
- pattern: os.StartProcess($BIN, ...)
|
|
163
|
+
- pattern-not: syscall.Exec("...", ...)
|
|
164
|
+
- pattern-not: syscall.ForkExec("...", ...)
|
|
165
|
+
- pattern-not: os.StartProcess("...", ...)
|
|
166
|
+
message: Low-level process execution (`syscall.Exec` / `os.StartProcess`) with a non-literal binary path. If the path comes
|
|
167
|
+
from user input this is a command injection. Validate with an allow-list of approved binaries.
|
|
168
|
+
metadata:
|
|
169
|
+
cwe:
|
|
170
|
+
- 'CWE-78: Improper Neutralization of Special Elements used in an OS Command (''OS Command Injection'')'
|
|
171
|
+
owasp:
|
|
172
|
+
- A03:2021 - Injection
|
|
173
|
+
category: security
|
|
174
|
+
technology:
|
|
175
|
+
- go
|
|
176
|
+
confidence: MEDIUM
|
|
177
|
+
subcategory:
|
|
178
|
+
- audit
|
|
179
|
+
likelihood: MEDIUM
|
|
180
|
+
impact: HIGH
|
|
181
|
+
severity: ERROR
|
|
182
|
+
languages:
|
|
183
|
+
- go
|
|
184
|
+
- id: narvy-go-cmdi-shell-flag
|
|
185
|
+
patterns:
|
|
186
|
+
- pattern-either:
|
|
187
|
+
- pattern: 'exec.Command("sh", "-c", $X)
|
|
188
|
+
|
|
189
|
+
'
|
|
190
|
+
- pattern: 'exec.Command("bash", "-c", $X)
|
|
191
|
+
|
|
192
|
+
'
|
|
193
|
+
- pattern: 'exec.Command("/bin/sh", "-c", $X)
|
|
194
|
+
|
|
195
|
+
'
|
|
196
|
+
- pattern: 'exec.Command("/bin/bash", "-c", $X)
|
|
197
|
+
|
|
198
|
+
'
|
|
199
|
+
- pattern: 'exec.CommandContext($CTX, "sh", "-c", $X)
|
|
200
|
+
|
|
201
|
+
'
|
|
202
|
+
- pattern: 'exec.CommandContext($CTX, "bash", "-c", $X)
|
|
203
|
+
|
|
204
|
+
'
|
|
205
|
+
- pattern-not: 'exec.Command($S, "-c", "...")
|
|
206
|
+
|
|
207
|
+
'
|
|
208
|
+
- pattern-not: 'exec.CommandContext($CTX, $S, "-c", "...")
|
|
209
|
+
|
|
210
|
+
'
|
|
211
|
+
message: Shell expansion via `sh -c` / `bash -c` with a non-literal command string. Even properly-quoted user input is interpreted
|
|
212
|
+
by the shell (subshells, redirection, env expansion). Invoke the target binary directly without `-c` and pass arguments
|
|
213
|
+
as a slice.
|
|
214
|
+
metadata:
|
|
215
|
+
cwe:
|
|
216
|
+
- 'CWE-78: Improper Neutralization of Special Elements used in an OS Command (''OS Command Injection'')'
|
|
217
|
+
owasp:
|
|
218
|
+
- A03:2021 - Injection
|
|
219
|
+
category: security
|
|
220
|
+
technology:
|
|
221
|
+
- go
|
|
222
|
+
confidence: HIGH
|
|
223
|
+
subcategory:
|
|
224
|
+
- vuln
|
|
225
|
+
likelihood: HIGH
|
|
226
|
+
impact: HIGH
|
|
227
|
+
severity: ERROR
|
|
228
|
+
languages:
|
|
229
|
+
- go
|
|
230
|
+
- id: narvy.go.code-injection.embedded-js-run-non-literal.embedded-js-run-non-literal
|
|
231
|
+
message: An embedded JavaScript interpreter (goja / otto) executes a non-literal script string. If the script text is attacker-
|
|
232
|
+
influenced, this is full code execution inside your Go process (CWE-94) - these interpreters are not a real security sandbox
|
|
233
|
+
against a determined attacker and have full access to whatever Go functions you registered on the runtime. Never run request-derived
|
|
234
|
+
text as a script.
|
|
235
|
+
severity: ERROR
|
|
236
|
+
languages:
|
|
237
|
+
- go
|
|
238
|
+
metadata:
|
|
239
|
+
cwe:
|
|
240
|
+
- 'CWE-94: Improper Control of Generation of Code (''Code Injection'')'
|
|
241
|
+
owasp:
|
|
242
|
+
- A03:2021 - Injection
|
|
243
|
+
category: security
|
|
244
|
+
subcategory:
|
|
245
|
+
- vuln
|
|
246
|
+
technology:
|
|
247
|
+
- go
|
|
248
|
+
- goja
|
|
249
|
+
- otto
|
|
250
|
+
likelihood: LOW
|
|
251
|
+
impact: HIGH
|
|
252
|
+
confidence: MEDIUM
|
|
253
|
+
vulnerability_class:
|
|
254
|
+
- Code Injection
|
|
255
|
+
patterns:
|
|
256
|
+
- pattern-either:
|
|
257
|
+
- pattern: $VM.RunString($X)
|
|
258
|
+
- pattern: $VM.Run($X)
|
|
259
|
+
- pattern-not: $VM.RunString("...")
|
|
260
|
+
- pattern-not: $VM.Run("...")
|
|
261
|
+
- metavariable-regex:
|
|
262
|
+
metavariable: $VM
|
|
263
|
+
regex: (?i)(vm|runtime|interp|js|script|otto)
|
|
264
|
+
- id: narvy.go.code-injection.plugin-open-non-literal-path.plugin-open-non-literal-path
|
|
265
|
+
message: '`plugin.Open()` loads a Go shared-object (.so) plugin from a non-literal path. Loading a plugin runs its `init()`
|
|
266
|
+
functions immediately with the full privileges of your process - there is no sandboxing. If the path is attacker-influenced
|
|
267
|
+
(even indirectly, e.g. a filename derived from a request), this is remote code execution (CWE-94). Load plugins only from
|
|
268
|
+
a fixed, trusted, non-writable directory.'
|
|
269
|
+
severity: ERROR
|
|
270
|
+
languages:
|
|
271
|
+
- go
|
|
272
|
+
metadata:
|
|
273
|
+
cwe:
|
|
274
|
+
- 'CWE-94: Improper Control of Generation of Code (''Code Injection'')'
|
|
275
|
+
owasp:
|
|
276
|
+
- A08:2021 - Software and Data Integrity Failures
|
|
277
|
+
category: security
|
|
278
|
+
subcategory:
|
|
279
|
+
- vuln
|
|
280
|
+
technology:
|
|
281
|
+
- go
|
|
282
|
+
likelihood: LOW
|
|
283
|
+
impact: HIGH
|
|
284
|
+
confidence: MEDIUM
|
|
285
|
+
vulnerability_class:
|
|
286
|
+
- Code Injection
|
|
287
|
+
patterns:
|
|
288
|
+
- pattern: plugin.Open($PATH)
|
|
289
|
+
- pattern-not: plugin.Open("...")
|
|
290
|
+
- id: narvy.go.code-injection.reflect-methodbyname-non-literal.reflect-methodbyname-non-literal
|
|
291
|
+
message: '`reflect.ValueOf(...).MethodByName($NAME)` looks up and invokes a method whose name is not a literal. If `$NAME`
|
|
292
|
+
is influenced by request data, an attacker can call any exported method on the target object - including ones never meant
|
|
293
|
+
to be reachable from outside (unsafe reflection / unintended dispatch, CWE-470). Use an explicit allow-list mapping request
|
|
294
|
+
values to a fixed set of permitted method names.'
|
|
295
|
+
severity: WARNING
|
|
296
|
+
languages:
|
|
297
|
+
- go
|
|
298
|
+
metadata:
|
|
299
|
+
cwe:
|
|
300
|
+
- 'CWE-470: Use of Externally-Controlled Input to Select Classes or Code (''Unsafe Reflection'')'
|
|
301
|
+
owasp:
|
|
302
|
+
- A03:2021 - Injection
|
|
303
|
+
category: security
|
|
304
|
+
subcategory:
|
|
305
|
+
- audit
|
|
306
|
+
technology:
|
|
307
|
+
- go
|
|
308
|
+
- reflect
|
|
309
|
+
likelihood: LOW
|
|
310
|
+
impact: HIGH
|
|
311
|
+
confidence: LOW
|
|
312
|
+
vulnerability_class:
|
|
313
|
+
- Code Injection
|
|
314
|
+
patterns:
|
|
315
|
+
- pattern: reflect.ValueOf($OBJ).MethodByName($NAME)
|
|
316
|
+
- pattern-not: reflect.ValueOf($OBJ).MethodByName("...")
|
|
317
|
+
- id: narvy.go.cmdi.dangerous-exec-command.dangerous-exec-command
|
|
318
|
+
message: '`exec.Command()` / `exec.CommandContext()` called with a command or argument built from request-derived data.
|
|
319
|
+
`exec.Command` does not invoke a shell, so classic `;`/`&&` shell metacharacter injection does not apply directly - but
|
|
320
|
+
if the *binary name itself* or an argument that changes program behavior (e.g. a flag) is attacker-controlled, this is
|
|
321
|
+
still command injection / argument injection (CWE-78/CWE-88). Validate the binary against a fixed allow-list and treat
|
|
322
|
+
every argument as untrusted data, never as a flag.'
|
|
323
|
+
severity: WARNING
|
|
324
|
+
languages:
|
|
325
|
+
- go
|
|
326
|
+
metadata:
|
|
327
|
+
category: security
|
|
328
|
+
cwe:
|
|
329
|
+
- 'CWE-78: Improper Neutralization of Special Elements used in an OS Command (''OS Command Injection'')'
|
|
330
|
+
- 'CWE-88: Argument Injection or Modification'
|
|
331
|
+
owasp:
|
|
332
|
+
- A03:2021 - Injection
|
|
333
|
+
subcategory:
|
|
334
|
+
- vuln
|
|
335
|
+
likelihood: MEDIUM
|
|
336
|
+
impact: HIGH
|
|
337
|
+
confidence: LOW
|
|
338
|
+
technology:
|
|
339
|
+
- go
|
|
340
|
+
patterns:
|
|
341
|
+
- pattern-either:
|
|
342
|
+
- pattern: exec.Command($BIN, ...)
|
|
343
|
+
- pattern: exec.CommandContext($CTX, $BIN, ...)
|
|
344
|
+
- pattern-not: exec.Command("...", ...)
|
|
345
|
+
- pattern-not: exec.CommandContext($CTX, "...", ...)
|
|
346
|
+
- id: narvy.go.reflect.reflect-methodby-name-tainted.reflect-methodby-name-tainted
|
|
347
|
+
message: '`reflect.ValueOf(...).MethodByName()` (or `.FieldByName()`) called with a name taken from request data. This lets
|
|
348
|
+
an attacker invoke any exported method reachable through the reflected value by naming it in the request - the same class
|
|
349
|
+
of risk as PHP''s tainted `call_user_func()` (CWE-470). Restrict the name to a fixed allow-list keyed by a validated token,
|
|
350
|
+
never the raw input.'
|
|
351
|
+
severity: WARNING
|
|
352
|
+
languages:
|
|
353
|
+
- go
|
|
354
|
+
metadata:
|
|
355
|
+
category: security
|
|
356
|
+
cwe:
|
|
357
|
+
- 'CWE-470: Use of Externally-Controlled Input to Select Classes or Code (''Unsafe Reflection'')'
|
|
358
|
+
owasp:
|
|
359
|
+
- A03:2021 - Injection
|
|
360
|
+
subcategory:
|
|
361
|
+
- vuln
|
|
362
|
+
likelihood: LOW
|
|
363
|
+
impact: HIGH
|
|
364
|
+
confidence: LOW
|
|
365
|
+
technology:
|
|
366
|
+
- go
|
|
367
|
+
patterns:
|
|
368
|
+
- pattern-either:
|
|
369
|
+
- pattern: reflect.ValueOf($OBJ).MethodByName($NAME)
|
|
370
|
+
- pattern: reflect.ValueOf($OBJ).FieldByName($NAME)
|
|
371
|
+
- pattern-not: reflect.ValueOf($OBJ).MethodByName("...")
|
|
372
|
+
- pattern-not: reflect.ValueOf($OBJ).FieldByName("...")
|
|
373
|
+
- id: narvy.go.plugin.plugin-open-tainted-path.plugin-open-tainted-path
|
|
374
|
+
message: '`plugin.Open()` called with a path built from request data. Go plugins are arbitrary native code loaded and executed
|
|
375
|
+
in-process - if an attacker can influence which `.so` file gets opened (directly, or via a directory they can also write
|
|
376
|
+
to), this is remote code execution (CWE-94). Load plugins only from a fixed, non-writable-by-request path.'
|
|
377
|
+
severity: ERROR
|
|
378
|
+
languages:
|
|
379
|
+
- go
|
|
380
|
+
metadata:
|
|
381
|
+
category: security
|
|
382
|
+
cwe:
|
|
383
|
+
- 'CWE-94: Improper Control of Generation of Code (''Code Injection'')'
|
|
384
|
+
owasp:
|
|
385
|
+
- A03:2021 - Injection
|
|
386
|
+
subcategory:
|
|
387
|
+
- vuln
|
|
388
|
+
likelihood: LOW
|
|
389
|
+
impact: HIGH
|
|
390
|
+
confidence: MEDIUM
|
|
391
|
+
technology:
|
|
392
|
+
- go
|
|
393
|
+
patterns:
|
|
394
|
+
- pattern: plugin.Open($PATH)
|
|
395
|
+
- pattern-not: plugin.Open("...")
|
|
396
|
+
- id: narvy.go.misc.use-of-unsafe-block.use-of-unsafe-block
|
|
397
|
+
message: '`unsafe.$FUNC(...)` call (Pointer conversion, Slice/SliceData/String/StringData zero-copy cast, or Add/Sizeof/Alignof/Offsetof).
|
|
398
|
+
The `unsafe` package steps outside Go''s type and memory safety guarantees, so the compiler no longer checks size or
|
|
399
|
+
layout for you. Manual pointer arithmetic on a size that is not a compile-time constant or independently validated can
|
|
400
|
+
read or write past the intended buffer (CWE-119/CWE-787). Confirm every offset and length is bounded and trusted; prefer
|
|
401
|
+
`encoding/binary` for request-derived byte layouts, and avoid `unsafe` entirely unless a benchmarked hot path requires it.'
|
|
402
|
+
severity: INFO
|
|
403
|
+
languages:
|
|
404
|
+
- go
|
|
405
|
+
metadata:
|
|
406
|
+
category: security
|
|
407
|
+
cwe:
|
|
408
|
+
- 'CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer'
|
|
409
|
+
owasp:
|
|
410
|
+
- A06:2021 - Vulnerable and Outdated Components
|
|
411
|
+
subcategory:
|
|
412
|
+
- audit
|
|
413
|
+
likelihood: LOW
|
|
414
|
+
impact: MEDIUM
|
|
415
|
+
confidence: LOW
|
|
416
|
+
technology:
|
|
417
|
+
- go
|
|
418
|
+
paths:
|
|
419
|
+
exclude:
|
|
420
|
+
- '*.pb.go'
|
|
421
|
+
- '*_generated.go'
|
|
422
|
+
- '*.gen.go'
|
|
423
|
+
- zz_generated*.go
|
|
424
|
+
- zsyscall_*.go
|
|
425
|
+
- '*_string.go'
|
|
426
|
+
pattern: unsafe.$FUNC(...)
|
|
427
|
+
- id: narvy.go.cors.wildcard-allow-origin.wildcard-allow-origin
|
|
428
|
+
message: '`Access-Control-Allow-Origin` header set to `*`. This lets any origin read the response via a cross-origin XHR/fetch
|
|
429
|
+
- safe only for genuinely public, non-authenticated endpoints. If the endpoint uses cookies/sessions or returns non-public
|
|
430
|
+
data, this exposes it to any site the victim visits (CWE-942). Echo back a validated origin from an allow-list instead
|
|
431
|
+
of a wildcard.'
|
|
432
|
+
severity: WARNING
|
|
433
|
+
languages:
|
|
434
|
+
- go
|
|
435
|
+
metadata:
|
|
436
|
+
category: security
|
|
437
|
+
cwe:
|
|
438
|
+
- 'CWE-942: Permissive Cross-domain Policy with Untrusted Domains'
|
|
439
|
+
owasp:
|
|
440
|
+
- A05:2021 - Security Misconfiguration
|
|
441
|
+
subcategory:
|
|
442
|
+
- vuln
|
|
443
|
+
likelihood: MEDIUM
|
|
444
|
+
impact: MEDIUM
|
|
445
|
+
confidence: MEDIUM
|
|
446
|
+
technology:
|
|
447
|
+
- go
|
|
448
|
+
paths:
|
|
449
|
+
exclude:
|
|
450
|
+
- '**/*_test.go'
|
|
451
|
+
patterns:
|
|
452
|
+
- pattern-either:
|
|
453
|
+
- pattern: $W.Header().Set("Access-Control-Allow-Origin", "*")
|
|
454
|
+
- pattern: $W.Header().Add("Access-Control-Allow-Origin", "*")
|
|
455
|
+
- pattern: $CTX.Header("Access-Control-Allow-Origin", "*")
|
|
456
|
+
- id: narvy.go.cors.reflected-origin-header.reflected-origin-header
|
|
457
|
+
message: The incoming `Origin` request header is echoed straight back as `Access-Control-Allow-Origin` with no allow-list
|
|
458
|
+
check. This grants every origin CORS access - functionally equivalent to a wildcard but easy to miss in review because
|
|
459
|
+
there is no literal `*` (CWE-942). Validate the origin against a fixed allow-list before echoing it.
|
|
460
|
+
severity: ERROR
|
|
461
|
+
languages:
|
|
462
|
+
- go
|
|
463
|
+
metadata:
|
|
464
|
+
category: security
|
|
465
|
+
cwe:
|
|
466
|
+
- 'CWE-942: Permissive Cross-domain Policy with Untrusted Domains'
|
|
467
|
+
owasp:
|
|
468
|
+
- A05:2021 - Security Misconfiguration
|
|
469
|
+
subcategory:
|
|
470
|
+
- vuln
|
|
471
|
+
likelihood: MEDIUM
|
|
472
|
+
impact: HIGH
|
|
473
|
+
confidence: MEDIUM
|
|
474
|
+
technology:
|
|
475
|
+
- go
|
|
476
|
+
patterns:
|
|
477
|
+
- pattern-either:
|
|
478
|
+
- pattern: $W.Header().Set("Access-Control-Allow-Origin", $R.Header.Get("Origin"))
|
|
479
|
+
- pattern: $W.Header().Set("Access-Control-Allow-Origin", $ORIGIN)
|
|
480
|
+
- pattern-inside: '$ORIGIN := $R.Header.Get("Origin")
|
|
481
|
+
|
|
482
|
+
...
|
|
483
|
+
|
|
484
|
+
'
|
|
485
|
+
- id: narvy.go.cors.wildcard-with-credentials.wildcard-with-credentials
|
|
486
|
+
message: '`Access-Control-Allow-Credentials: true` set alongside a wildcard/ reflected `Access-Control-Allow-Origin`. Per
|
|
487
|
+
the Fetch spec browsers reject the literal combination of `*` with credentials, so code relying on this is usually reflecting
|
|
488
|
+
the Origin header dynamically instead - which grants every origin authenticated, cookie-bearing cross-site access (CWE-942).
|
|
489
|
+
Restrict `Allow-Origin` to a fixed allow-list when `Allow-Credentials` is `true`.'
|
|
490
|
+
severity: ERROR
|
|
491
|
+
languages:
|
|
492
|
+
- go
|
|
493
|
+
metadata:
|
|
494
|
+
category: security
|
|
495
|
+
cwe:
|
|
496
|
+
- 'CWE-942: Permissive Cross-domain Policy with Untrusted Domains'
|
|
497
|
+
owasp:
|
|
498
|
+
- A05:2021 - Security Misconfiguration
|
|
499
|
+
subcategory:
|
|
500
|
+
- vuln
|
|
501
|
+
likelihood: LOW
|
|
502
|
+
impact: HIGH
|
|
503
|
+
confidence: LOW
|
|
504
|
+
technology:
|
|
505
|
+
- go
|
|
506
|
+
patterns:
|
|
507
|
+
- pattern-either:
|
|
508
|
+
- pattern: '$W.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
509
|
+
|
|
510
|
+
...
|
|
511
|
+
|
|
512
|
+
$W.Header().Set("Access-Control-Allow-Origin", $R.Header.Get("Origin"))
|
|
513
|
+
|
|
514
|
+
'
|
|
515
|
+
- pattern: '$W.Header().Set("Access-Control-Allow-Origin", $R.Header.Get("Origin"))
|
|
516
|
+
|
|
517
|
+
...
|
|
518
|
+
|
|
519
|
+
$W.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
520
|
+
|
|
521
|
+
'
|
|
522
|
+
- id: narvy.go.cors.gin-permissive-config.gin-permissive-config
|
|
523
|
+
message: '`cors.Config{AllowAllOrigins: true}` (gin-contrib/cors) combined with `AllowCredentials: true`. This grants any
|
|
524
|
+
origin authenticated, cookie-bearing cross-site access to the API - a full CORS bypass (CWE-942). Set `AllowOrigins` to
|
|
525
|
+
a fixed list of trusted origins instead of allowing all.'
|
|
526
|
+
severity: ERROR
|
|
527
|
+
languages:
|
|
528
|
+
- go
|
|
529
|
+
metadata:
|
|
530
|
+
category: security
|
|
531
|
+
cwe:
|
|
532
|
+
- 'CWE-942: Permissive Cross-domain Policy with Untrusted Domains'
|
|
533
|
+
owasp:
|
|
534
|
+
- A05:2021 - Security Misconfiguration
|
|
535
|
+
subcategory:
|
|
536
|
+
- vuln
|
|
537
|
+
likelihood: LOW
|
|
538
|
+
impact: HIGH
|
|
539
|
+
confidence: MEDIUM
|
|
540
|
+
technology:
|
|
541
|
+
- go
|
|
542
|
+
pattern: 'cors.Config{..., AllowAllOrigins: true, ..., AllowCredentials: true, ...}
|
|
543
|
+
|
|
544
|
+
'
|
|
545
|
+
- id: narvy.go.crypto.hardcoded-env-fallback-to-crypto.hardcoded-env-fallback-to-crypto
|
|
546
|
+
message: 'Hardcoded fallback secret ''$LITERAL'' is used when the environment variable is unset, and is then fed into a
|
|
547
|
+
cryptographic primitive (HMAC / AES / JWT signing). If the env var is missing in any deployment, the key reduces to a
|
|
548
|
+
public constant. Fix: fail fast at startup with `log.Fatal("$ENV must be set")` if the env var is empty - never silently
|
|
549
|
+
fall back to a literal.'
|
|
550
|
+
severity: ERROR
|
|
551
|
+
languages:
|
|
552
|
+
- go
|
|
553
|
+
metadata:
|
|
554
|
+
cwe:
|
|
555
|
+
- 'CWE-321: Use of Hard-coded Cryptographic Key'
|
|
556
|
+
- 'CWE-798: Use of Hard-coded Credentials'
|
|
557
|
+
owasp:
|
|
558
|
+
- A02:2021 - Cryptographic Failures
|
|
559
|
+
- A07:2021 - Identification and Authentication Failures
|
|
560
|
+
category: security
|
|
561
|
+
subcategory:
|
|
562
|
+
- vuln
|
|
563
|
+
technology:
|
|
564
|
+
- go
|
|
565
|
+
- golang
|
|
566
|
+
likelihood: HIGH
|
|
567
|
+
impact: HIGH
|
|
568
|
+
confidence: HIGH
|
|
569
|
+
vulnerability_class:
|
|
570
|
+
- Cryptographic Issues
|
|
571
|
+
- Hard-coded Credentials
|
|
572
|
+
patterns:
|
|
573
|
+
- pattern-either:
|
|
574
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif $K == \"\" {\n $K = \"$LITERAL\"\n}\n...\nhmac.New($H, []byte($K))\n"
|
|
575
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif $K == \"\" {\n $K = \"$LITERAL\"\n}\n...\naes.NewCipher([]byte($K))\n"
|
|
576
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif len($K) == 0 {\n $K = \"$LITERAL\"\n}\n...\nhmac.New($H, []byte($K))\n"
|
|
577
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif len($K) == 0 {\n $K = \"$LITERAL\"\n}\n...\naes.NewCipher([]byte($K))\n"
|
|
578
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif $K == \"\" {\n $K = \"$LITERAL\"\n}\n...\n$TOKEN.SignedString([]byte($K))\n"
|
|
579
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif len($K) == 0 {\n $K = \"$LITERAL\"\n}\n...\n$TOKEN.SignedString([]byte($K))\n"
|
|
580
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif \"\" == $K {\n $K = \"$LITERAL\"\n}\n...\nhmac.New($H, []byte($K))\n"
|
|
581
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif $K == \"\" {\n $K = \"$LITERAL\"\n}\n...\nargon2.IDKey([]byte($K), ...)\n"
|
|
582
|
+
- pattern: "$K := os.Getenv($ENV)\n...\nif $K == \"\" {\n $K = \"$LITERAL\"\n}\n...\nargon2.Key([]byte($K), ...)\n"
|
|
583
|
+
- metavariable-regex:
|
|
584
|
+
metavariable: $LITERAL
|
|
585
|
+
regex: ^[A-Za-z0-9 _!@#$%^&*()+=,.:?<>\[\]{}|/\\-]{1,64}$
|
|
586
|
+
- id: narvy.go.crypto.helper-env-fallback-to-crypto.helper-env-fallback-to-crypto
|
|
587
|
+
message: 'Helper-function fallback (e.g. `getEnvOrDefault("$ENV", "$LITERAL")`) is used to read a secret with a hardcoded
|
|
588
|
+
default, and the result is fed into a crypto primitive. If the env var is unset the key is a public constant. Fix: fail
|
|
589
|
+
fast at startup instead of silently defaulting.'
|
|
590
|
+
severity: ERROR
|
|
591
|
+
languages:
|
|
592
|
+
- go
|
|
593
|
+
metadata:
|
|
594
|
+
cwe:
|
|
595
|
+
- 'CWE-321: Use of Hard-coded Cryptographic Key'
|
|
596
|
+
- 'CWE-798: Use of Hard-coded Credentials'
|
|
597
|
+
owasp:
|
|
598
|
+
- A02:2021 - Cryptographic Failures
|
|
599
|
+
category: security
|
|
600
|
+
subcategory:
|
|
601
|
+
- vuln
|
|
602
|
+
technology:
|
|
603
|
+
- go
|
|
604
|
+
- golang
|
|
605
|
+
likelihood: HIGH
|
|
606
|
+
impact: HIGH
|
|
607
|
+
confidence: MEDIUM
|
|
608
|
+
vulnerability_class:
|
|
609
|
+
- Cryptographic Issues
|
|
610
|
+
- Hard-coded Credentials
|
|
611
|
+
patterns:
|
|
612
|
+
- pattern-either:
|
|
613
|
+
- pattern: 'hmac.New($H, []byte(getEnvOrDefault($ENV, "$LITERAL")))
|
|
614
|
+
|
|
615
|
+
'
|
|
616
|
+
- pattern: 'hmac.New($H, []byte(GetEnvOrDefault($ENV, "$LITERAL")))
|
|
617
|
+
|
|
618
|
+
'
|
|
619
|
+
- pattern: 'hmac.New($H, []byte(getEnv($ENV, "$LITERAL")))
|
|
620
|
+
|
|
621
|
+
'
|
|
622
|
+
- pattern: 'aes.NewCipher([]byte(getEnvOrDefault($ENV, "$LITERAL")))
|
|
623
|
+
|
|
624
|
+
'
|
|
625
|
+
- pattern: '$TOKEN.SignedString([]byte(getEnvOrDefault($ENV, "$LITERAL")))
|
|
626
|
+
|
|
627
|
+
'
|
|
628
|
+
- pattern: '$K := getEnvOrDefault($ENV, "$LITERAL")
|
|
629
|
+
|
|
630
|
+
...
|
|
631
|
+
|
|
632
|
+
hmac.New($H, []byte($K))
|
|
633
|
+
|
|
634
|
+
'
|
|
635
|
+
- pattern: '$K := getEnvOrDefault($ENV, "$LITERAL")
|
|
636
|
+
|
|
637
|
+
...
|
|
638
|
+
|
|
639
|
+
$TOKEN.SignedString([]byte($K))
|
|
640
|
+
|
|
641
|
+
'
|
|
642
|
+
- pattern: '$K := getEnv($ENV, "$LITERAL")
|
|
643
|
+
|
|
644
|
+
...
|
|
645
|
+
|
|
646
|
+
hmac.New($H, []byte($K))
|
|
647
|
+
|
|
648
|
+
'
|
|
649
|
+
- metavariable-regex:
|
|
650
|
+
metavariable: $LITERAL
|
|
651
|
+
regex: ^[A-Za-z0-9 _!@#$%^&*()+=,.:?<>\[\]{}|/\\-]{1,64}$
|
|
652
|
+
- id: narvy.go.misc.pprof-registered-on-public-mux.pprof-registered-on-public-mux
|
|
653
|
+
message: '`net/http/pprof` imported for its side-effecting `init()` (which registers `/debug/pprof/*` on `http.DefaultServeMux`)
|
|
654
|
+
in a binary that also serves that mux to the public internet. `/debug/pprof/*` exposes goroutine stacks, heap dumps, and
|
|
655
|
+
command-line arguments, and its CPU profile endpoint is a trivial DoS lever (CWE-200). Register pprof only on a separate
|
|
656
|
+
listener bound to localhost, or behind auth.'
|
|
657
|
+
severity: WARNING
|
|
658
|
+
languages:
|
|
659
|
+
- go
|
|
660
|
+
metadata:
|
|
661
|
+
category: security
|
|
662
|
+
cwe:
|
|
663
|
+
- 'CWE-200: Exposure of Sensitive Information to an Unauthorized Actor'
|
|
664
|
+
owasp:
|
|
665
|
+
- A05:2021 - Security Misconfiguration
|
|
666
|
+
subcategory:
|
|
667
|
+
- vuln
|
|
668
|
+
likelihood: LOW
|
|
669
|
+
impact: MEDIUM
|
|
670
|
+
confidence: LOW
|
|
671
|
+
technology:
|
|
672
|
+
- go
|
|
673
|
+
patterns:
|
|
674
|
+
- pattern: 'import _ "net/http/pprof"
|
|
675
|
+
|
|
676
|
+
'
|
|
677
|
+
- pattern-inside: '...
|
|
678
|
+
|
|
679
|
+
http.ListenAndServe($ADDR, nil)
|
|
680
|
+
|
|
681
|
+
'
|
|
682
|
+
- id: narvy.go.misc.listen-bind-all-interfaces.listen-bind-all-interfaces
|
|
683
|
+
message: Server bound to `0.0.0.0` (or an empty host, e.g. `":8080"` combined with an explicit all-interfaces comment/config)
|
|
684
|
+
instead of a specific interface. For anything not meant to be internet-facing (internal admin APIs, debug/metrics endpoints,
|
|
685
|
+
databases), binding to all interfaces is an unintended external-exposure risk if the host also has a public NIC (CWE-1327
|
|
686
|
+
class). Bind to `127.0.0.1`/a specific internal IP unless the service is deliberately public.
|
|
687
|
+
severity: INFO
|
|
688
|
+
languages:
|
|
689
|
+
- go
|
|
690
|
+
metadata:
|
|
691
|
+
category: security
|
|
692
|
+
cwe:
|
|
693
|
+
- 'CWE-668: Exposure of Resource to Wrong Sphere'
|
|
694
|
+
owasp:
|
|
695
|
+
- A05:2021 - Security Misconfiguration
|
|
696
|
+
subcategory:
|
|
697
|
+
- audit
|
|
698
|
+
likelihood: LOW
|
|
699
|
+
impact: MEDIUM
|
|
700
|
+
confidence: LOW
|
|
701
|
+
technology:
|
|
702
|
+
- go
|
|
703
|
+
patterns:
|
|
704
|
+
- pattern-either:
|
|
705
|
+
- pattern: net.Listen("tcp", "0.0.0.0:...")
|
|
706
|
+
- pattern: http.ListenAndServe("0.0.0.0:...", ...)
|
|
707
|
+
- id: narvy.go.misc.fileserver-directory-listing-unguarded.fileserver-directory-listing-unguarded
|
|
708
|
+
message: '`http.FileServer(http.Dir($DIR))` mounted directly with no directory- listing guard. Without an `index.html` in
|
|
709
|
+
every directory, Go''s default file server returns a browsable directory listing for any path with no index file, potentially
|
|
710
|
+
exposing source files, config, or backups that were only meant to be served by direct link (CWE-548). Wrap the `http.FileSystem`
|
|
711
|
+
to return 404 on directory requests missing an index, or serve from an explicit allow-list of files.'
|
|
712
|
+
severity: INFO
|
|
713
|
+
languages:
|
|
714
|
+
- go
|
|
715
|
+
metadata:
|
|
716
|
+
category: security
|
|
717
|
+
cwe:
|
|
718
|
+
- 'CWE-548: Exposure of Information Through Directory Listing'
|
|
719
|
+
owasp:
|
|
720
|
+
- A05:2021 - Security Misconfiguration
|
|
721
|
+
subcategory:
|
|
722
|
+
- audit
|
|
723
|
+
likelihood: LOW
|
|
724
|
+
impact: LOW
|
|
725
|
+
confidence: LOW
|
|
726
|
+
technology:
|
|
727
|
+
- go
|
|
728
|
+
pattern: http.FileServer(http.Dir($DIR))
|
|
729
|
+
- id: narvy.go.misc.websocket-checkorigin-always-true.websocket-checkorigin-always-true
|
|
730
|
+
message: '`gorilla/websocket.Upgrader` constructed with `CheckOrigin` left unset (nil) or hardcoded to always return `true`.
|
|
731
|
+
The default/permissive behavior accepts a WebSocket upgrade from any origin, enabling cross-site WebSocket hijacking against
|
|
732
|
+
cookie-authenticated endpoints (CWE-346). Set `CheckOrigin` to validate the `Origin` header against a fixed allow-list.'
|
|
733
|
+
severity: WARNING
|
|
734
|
+
languages:
|
|
735
|
+
- go
|
|
736
|
+
metadata:
|
|
737
|
+
category: security
|
|
738
|
+
cwe:
|
|
739
|
+
- 'CWE-346: Origin Validation Error'
|
|
740
|
+
owasp:
|
|
741
|
+
- A01:2021 - Broken Access Control
|
|
742
|
+
subcategory:
|
|
743
|
+
- vuln
|
|
744
|
+
likelihood: LOW
|
|
745
|
+
impact: MEDIUM
|
|
746
|
+
confidence: LOW
|
|
747
|
+
technology:
|
|
748
|
+
- go
|
|
749
|
+
patterns:
|
|
750
|
+
- pattern-either:
|
|
751
|
+
- pattern: 'websocket.Upgrader{..., CheckOrigin: func(r *http.Request) bool { return true }, ...}
|
|
752
|
+
|
|
753
|
+
'
|
|
754
|
+
- id: narvy.go.misc.predictable-tmp-path-not-createtemp.predictable-tmp-path-not-createtemp
|
|
755
|
+
message: '`os.Create()` / `os.MkdirAll()` / `os.WriteFile()` used on a path under `/tmp` built with a predictable name (fixed
|
|
756
|
+
string, PID, timestamp with no random component, or a format-string with no random component) instead of `os.CreateTemp()`/`ioutil.TempFile()`.
|
|
757
|
+
A predictable temp-file or temp-directory name in a world-writable directory is a classic symlink-race / TOCTOU target
|
|
758
|
+
(CWE-377). Use `os.CreateTemp()` for files (unpredictable name, opens with `O_EXCL`) or `os.MkdirTemp()` for directories.
|
|
759
|
+
'
|
|
760
|
+
severity: INFO
|
|
761
|
+
languages:
|
|
762
|
+
- go
|
|
763
|
+
metadata:
|
|
764
|
+
category: security
|
|
765
|
+
cwe:
|
|
766
|
+
- 'CWE-377: Insecure Temporary File'
|
|
767
|
+
owasp:
|
|
768
|
+
- A01:2021 - Broken Access Control
|
|
769
|
+
subcategory:
|
|
770
|
+
- audit
|
|
771
|
+
likelihood: LOW
|
|
772
|
+
impact: LOW
|
|
773
|
+
confidence: LOW
|
|
774
|
+
technology:
|
|
775
|
+
- go
|
|
776
|
+
patterns:
|
|
777
|
+
- pattern-either:
|
|
778
|
+
- patterns:
|
|
779
|
+
- pattern: os.Create($PATH)
|
|
780
|
+
- metavariable-regex:
|
|
781
|
+
metavariable: $PATH
|
|
782
|
+
regex: ^"/tmp/
|
|
783
|
+
- pattern: os.Create("/tmp/" + ...)
|
|
784
|
+
- patterns:
|
|
785
|
+
- pattern: os.Create(fmt.Sprintf($FMT, ...))
|
|
786
|
+
- metavariable-regex:
|
|
787
|
+
metavariable: $FMT
|
|
788
|
+
regex: ^"/tmp/
|
|
789
|
+
- patterns:
|
|
790
|
+
- pattern: os.MkdirAll($PATH, ...)
|
|
791
|
+
- metavariable-regex:
|
|
792
|
+
metavariable: $PATH
|
|
793
|
+
regex: ^"/tmp/
|
|
794
|
+
- pattern: os.MkdirAll("/tmp/" + ..., ...)
|
|
795
|
+
- patterns:
|
|
796
|
+
- pattern: os.MkdirAll(fmt.Sprintf($FMT, ...), ...)
|
|
797
|
+
- metavariable-regex:
|
|
798
|
+
metavariable: $FMT
|
|
799
|
+
regex: ^"/tmp/
|
|
800
|
+
- patterns:
|
|
801
|
+
- pattern: os.WriteFile($PATH, ...)
|
|
802
|
+
- metavariable-regex:
|
|
803
|
+
metavariable: $PATH
|
|
804
|
+
regex: ^"/tmp/
|
|
805
|
+
- pattern: os.WriteFile("/tmp/" + ..., ...)
|
|
806
|
+
- patterns:
|
|
807
|
+
- pattern: os.WriteFile(fmt.Sprintf($FMT, ...), ...)
|
|
808
|
+
- metavariable-regex:
|
|
809
|
+
metavariable: $FMT
|
|
810
|
+
regex: ^"/tmp/
|
|
811
|
+
- id: narvy.go.misc.insecure-file-permission.insecure-file-permission
|
|
812
|
+
message: File permission bits are set to world-writable (0777/0666) via `os.Chmod` / `os.OpenFile` / `os.WriteFile` / `ioutil.WriteFile`.
|
|
813
|
+
Any local user or process can then modify or read this file, which is dangerous for config files, key material, or scripts
|
|
814
|
+
that get executed later (CWE-732). Use the narrowest mode that works, e.g. 0600 for secrets or 0644 for regular files.
|
|
815
|
+
severity: WARNING
|
|
816
|
+
languages:
|
|
817
|
+
- go
|
|
818
|
+
metadata:
|
|
819
|
+
cwe:
|
|
820
|
+
- 'CWE-732: Incorrect Permission Assignment for Critical Resource'
|
|
821
|
+
owasp:
|
|
822
|
+
- A01:2021 - Broken Access Control
|
|
823
|
+
category: security
|
|
824
|
+
subcategory:
|
|
825
|
+
- audit
|
|
826
|
+
technology:
|
|
827
|
+
- go
|
|
828
|
+
likelihood: LOW
|
|
829
|
+
impact: MEDIUM
|
|
830
|
+
confidence: HIGH
|
|
831
|
+
vulnerability_class:
|
|
832
|
+
- Improper Access Control
|
|
833
|
+
patterns:
|
|
834
|
+
- pattern-either:
|
|
835
|
+
- pattern: os.Chmod($PATH, 0777)
|
|
836
|
+
- pattern: os.Chmod($PATH, 0666)
|
|
837
|
+
- pattern: os.OpenFile($PATH, $FLAG, 0777)
|
|
838
|
+
- pattern: os.OpenFile($PATH, $FLAG, 0666)
|
|
839
|
+
- pattern: os.WriteFile($PATH, $DATA, 0777)
|
|
840
|
+
- pattern: os.WriteFile($PATH, $DATA, 0666)
|
|
841
|
+
- pattern: ioutil.WriteFile($PATH, $DATA, 0777)
|
|
842
|
+
- pattern: ioutil.WriteFile($PATH, $DATA, 0666)
|
|
843
|
+
- id: narvy.go.misc.pprof-blank-import-exposure.pprof-blank-import-exposure
|
|
844
|
+
message: '`net/http/pprof` is blank-imported, which registers profiling handlers (`/debug/pprof/*`, including goroutine
|
|
845
|
+
dumps, heap profiles, and a CPU-profile trigger) onto `http.DefaultServeMux` with zero authentication. If that mux is
|
|
846
|
+
served on a publicly-reachable listener, this leaks internal application state and provides a CPU-exhaustion knob to anyone
|
|
847
|
+
who can reach it (CWE-200). Serve pprof on a separate listener bound to localhost, or behind authentication middleware.'
|
|
848
|
+
severity: WARNING
|
|
849
|
+
languages:
|
|
850
|
+
- go
|
|
851
|
+
metadata:
|
|
852
|
+
cwe:
|
|
853
|
+
- 'CWE-200: Exposure of Sensitive Information to an Unauthorized Actor'
|
|
854
|
+
owasp:
|
|
855
|
+
- A05:2021 - Security Misconfiguration
|
|
856
|
+
category: security
|
|
857
|
+
subcategory:
|
|
858
|
+
- audit
|
|
859
|
+
technology:
|
|
860
|
+
- go
|
|
861
|
+
likelihood: LOW
|
|
862
|
+
impact: MEDIUM
|
|
863
|
+
confidence: LOW
|
|
864
|
+
vulnerability_class:
|
|
865
|
+
- Information Exposure
|
|
866
|
+
patterns:
|
|
867
|
+
- pattern: import _ "net/http/pprof"
|
|
868
|
+
- id: narvy.go.ssh.insecure-hostkey-callback.insecure-hostkey-callback
|
|
869
|
+
message: 'golang.org/x/crypto/ssh.InsecureIgnoreHostKey() accepts whatever host key the remote end presents, with no verification
|
|
870
|
+
at all. Anyone able to sit on the network path between this client and the SSH server can present their own key and the
|
|
871
|
+
client will treat the connection as trusted, defeating the entire point of the SSH handshake (CWE-322: Key Exchange without
|
|
872
|
+
Entity Authentication). Verify against a pinned key with ssh.FixedHostKey(), or check the remote key against a known_hosts
|
|
873
|
+
file with golang.org/x/crypto/ssh/knownhosts instead.'
|
|
874
|
+
severity: ERROR
|
|
875
|
+
languages:
|
|
876
|
+
- go
|
|
877
|
+
metadata:
|
|
878
|
+
category: security
|
|
879
|
+
cwe:
|
|
880
|
+
- 'CWE-322: Key Exchange without Entity Authentication'
|
|
881
|
+
owasp:
|
|
882
|
+
- A02:2021 - Cryptographic Failures
|
|
883
|
+
subcategory:
|
|
884
|
+
- vuln
|
|
885
|
+
likelihood: LOW
|
|
886
|
+
impact: HIGH
|
|
887
|
+
confidence: HIGH
|
|
888
|
+
technology:
|
|
889
|
+
- go
|
|
890
|
+
paths:
|
|
891
|
+
exclude:
|
|
892
|
+
- '**/*_test.go'
|
|
893
|
+
- '**/testdata/**'
|
|
894
|
+
pattern: ssh.InsecureIgnoreHostKey()
|
|
895
|
+
- id: narvy.go.http.plaintext-server-no-tls-anywhere.plaintext-server-no-tls-anywhere
|
|
896
|
+
message: 'An HTTP server is started with no TLS involved at all - either http.ListenAndServe() (the plaintext entry point,
|
|
897
|
+
as opposed to http.ListenAndServeTLS()) or an *http.Server started via .ListenAndServe() on a Server value that never
|
|
898
|
+
had a TLSConfig set. Every request and response on this listener, including any auth cookie, bearer token, or session
|
|
899
|
+
id, crosses the wire unencrypted and can be read or tampered with by anyone on the network path (CWE-319: Cleartext Transmission
|
|
900
|
+
of Sensitive Information). Switch to ListenAndServeTLS()/set TLSConfig, or if TLS is deliberately terminated in front
|
|
901
|
+
of this listener (a reverse proxy, a service mesh sidecar, a Unix socket only reachable locally), suppress this finding
|
|
902
|
+
with a comment explaining that.'
|
|
903
|
+
severity: WARNING
|
|
904
|
+
languages:
|
|
905
|
+
- go
|
|
906
|
+
metadata:
|
|
907
|
+
category: security
|
|
908
|
+
cwe:
|
|
909
|
+
- 'CWE-319: Cleartext Transmission of Sensitive Information'
|
|
910
|
+
owasp:
|
|
911
|
+
- A02:2021 - Cryptographic Failures
|
|
912
|
+
subcategory:
|
|
913
|
+
- audit
|
|
914
|
+
likelihood: LOW
|
|
915
|
+
impact: MEDIUM
|
|
916
|
+
confidence: LOW
|
|
917
|
+
technology:
|
|
918
|
+
- go
|
|
919
|
+
paths:
|
|
920
|
+
exclude:
|
|
921
|
+
- '**/*_test.go'
|
|
922
|
+
- '**/testdata/**'
|
|
923
|
+
- '**/fixtures/**'
|
|
924
|
+
- '**/examples/**'
|
|
925
|
+
patterns:
|
|
926
|
+
- pattern-either:
|
|
927
|
+
- pattern: http.ListenAndServe($ADDR, $HANDLER)
|
|
928
|
+
- patterns:
|
|
929
|
+
- pattern: $SRV.ListenAndServe()
|
|
930
|
+
- pattern-not-inside: '$SRV := &http.Server{..., TLSConfig: $CFG, ...}
|
|
931
|
+
|
|
932
|
+
...
|
|
933
|
+
|
|
934
|
+
'
|
|
935
|
+
- pattern-not-inside: '$SRV.TLSConfig = $CFG
|
|
936
|
+
|
|
937
|
+
...
|
|
938
|
+
|
|
939
|
+
'
|
|
940
|
+
- id: narvy.go.reflect.makefunc-dynamic-code.makefunc-dynamic-code
|
|
941
|
+
message: 'reflect.MakeFunc() builds a function value at runtime from a reflect.Type and a Go closure, bypassing the normal
|
|
942
|
+
compile-time type system. If any part of what gets wired into that closure (which argument gets used, what it does with
|
|
943
|
+
it, which downstream call it makes) is influenced by untrusted input, this is a code-generation-adjacent sink and a much
|
|
944
|
+
larger attack surface than a normal function call (CWE-913: Improper Control of Dynamically-Managed Code Resources). Confirm
|
|
945
|
+
the reflect.Type and the closure body are both fully static (no request-derived data feeding either), or replace this
|
|
946
|
+
with a plain typed function / a small static dispatch table.'
|
|
947
|
+
severity: WARNING
|
|
948
|
+
languages:
|
|
949
|
+
- go
|
|
950
|
+
metadata:
|
|
951
|
+
category: security
|
|
952
|
+
cwe:
|
|
953
|
+
- 'CWE-913: Improper Control of Dynamically-Managed Code Resources'
|
|
954
|
+
owasp:
|
|
955
|
+
- A08:2021 - Software and Data Integrity Failures
|
|
956
|
+
subcategory:
|
|
957
|
+
- audit
|
|
958
|
+
likelihood: LOW
|
|
959
|
+
impact: MEDIUM
|
|
960
|
+
confidence: LOW
|
|
961
|
+
technology:
|
|
962
|
+
- go
|
|
963
|
+
paths:
|
|
964
|
+
exclude:
|
|
965
|
+
- '**/*_test.go'
|
|
966
|
+
- '**/testdata/**'
|
|
967
|
+
pattern: reflect.MakeFunc(...)
|
|
968
|
+
- id: narvy.go.httptrace.trace-not-literal-at-callsite.trace-not-literal-at-callsite
|
|
969
|
+
message: 'httptrace.WithClientTrace() is handed a trace value that is not a struct literal written directly at the call
|
|
970
|
+
site (it is a variable, a function return value, or otherwise assembled elsewhere). A *httptrace.ClientTrace carries hook
|
|
971
|
+
functions that run automatically for connection/DNS/TLS events on every request using this context; if the trace (or any
|
|
972
|
+
hook inside it) can be influenced by request data or config an attacker controls, code runs that the reviewer cannot see
|
|
973
|
+
just by reading this call (CWE-913: Improper Control of Dynamically-Managed Code Resources). Either inline the &httptrace.ClientTrace{...}
|
|
974
|
+
literal here so it is auditable at the call site, or confirm the variable is assigned exactly once, from a static literal,
|
|
975
|
+
with no request-derived input anywhere in it.'
|
|
976
|
+
severity: INFO
|
|
977
|
+
languages:
|
|
978
|
+
- go
|
|
979
|
+
metadata:
|
|
980
|
+
category: security
|
|
981
|
+
cwe:
|
|
982
|
+
- 'CWE-913: Improper Control of Dynamically-Managed Code Resources'
|
|
983
|
+
owasp:
|
|
984
|
+
- A08:2021 - Software and Data Integrity Failures
|
|
985
|
+
subcategory:
|
|
986
|
+
- audit
|
|
987
|
+
likelihood: LOW
|
|
988
|
+
impact: LOW
|
|
989
|
+
confidence: LOW
|
|
990
|
+
technology:
|
|
991
|
+
- go
|
|
992
|
+
paths:
|
|
993
|
+
exclude:
|
|
994
|
+
- '**/*_test.go'
|
|
995
|
+
- '**/testdata/**'
|
|
996
|
+
patterns:
|
|
997
|
+
- pattern: httptrace.WithClientTrace($CTX, $TRACE)
|
|
998
|
+
- pattern-not: httptrace.WithClientTrace($CTX, &httptrace.ClientTrace{...})
|
|
999
|
+
- id: narvy.go.open-redirect.request-param-to-http-redirect.request-param-to-http-redirect
|
|
1000
|
+
message: A value read directly from a request query parameter, form value, or path variable flows into `http.Redirect`'s
|
|
1001
|
+
target URL. An attacker can craft a link that redirects victims to an attacker-controlled site (open redirect, CWE-601),
|
|
1002
|
+
a common phishing / OAuth-token-theft primitive. Validate the target against an allow-list of known paths or hosts before
|
|
1003
|
+
redirecting.
|
|
1004
|
+
severity: WARNING
|
|
1005
|
+
languages:
|
|
1006
|
+
- go
|
|
1007
|
+
mode: taint
|
|
1008
|
+
metadata:
|
|
1009
|
+
cwe:
|
|
1010
|
+
- 'CWE-601: URL Redirection to Untrusted Site (''Open Redirect'')'
|
|
1011
|
+
owasp:
|
|
1012
|
+
- A01:2021 - Broken Access Control
|
|
1013
|
+
category: security
|
|
1014
|
+
subcategory:
|
|
1015
|
+
- vuln
|
|
1016
|
+
technology:
|
|
1017
|
+
- go
|
|
1018
|
+
likelihood: MEDIUM
|
|
1019
|
+
impact: MEDIUM
|
|
1020
|
+
confidence: MEDIUM
|
|
1021
|
+
vulnerability_class:
|
|
1022
|
+
- Open Redirect
|
|
1023
|
+
references:
|
|
1024
|
+
- https://cwe.mitre.org/data/definitions/601.html
|
|
1025
|
+
paths:
|
|
1026
|
+
exclude:
|
|
1027
|
+
- '**/*_test.go'
|
|
1028
|
+
pattern-sources:
|
|
1029
|
+
- pattern: $R.URL.Query().Get(...)
|
|
1030
|
+
- pattern: $R.FormValue(...)
|
|
1031
|
+
- pattern: $R.URL.Query()[...]
|
|
1032
|
+
pattern-sanitizers:
|
|
1033
|
+
- patterns:
|
|
1034
|
+
- pattern: $V
|
|
1035
|
+
- pattern-inside: 'if (<... strings.HasPrefix($V, "/") ...>) { ... }
|
|
1036
|
+
|
|
1037
|
+
'
|
|
1038
|
+
- pattern: url.Parse(...)
|
|
1039
|
+
pattern-sinks:
|
|
1040
|
+
- pattern: http.Redirect($W, $R, $SINK, ...)
|
|
1041
|
+
- id: narvy-go-pathtraversal-os-open
|
|
1042
|
+
patterns:
|
|
1043
|
+
- pattern-either:
|
|
1044
|
+
- pattern: os.Open($PATH)
|
|
1045
|
+
- pattern: os.OpenFile($PATH, ...)
|
|
1046
|
+
- pattern-not: os.Open("...")
|
|
1047
|
+
- pattern-not: os.OpenFile("...", ...)
|
|
1048
|
+
- pattern-not-inside: '$PATH = "..."
|
|
1049
|
+
|
|
1050
|
+
...
|
|
1051
|
+
|
|
1052
|
+
'
|
|
1053
|
+
- pattern-not: os.Open(filepath.Join("...", "..."))
|
|
1054
|
+
- pattern-either:
|
|
1055
|
+
- pattern-inside: "func $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1056
|
+
- pattern-inside: "func $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1057
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1058
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1059
|
+
- pattern-inside: "func $FN(..., $C echo.Context, ...) $RET {\n ...\n}\n"
|
|
1060
|
+
- pattern-inside: "func $FN(..., $C *gin.Context, ...) {\n ...\n}\n"
|
|
1061
|
+
- pattern-inside: "func $FN($X interface{}, $PAYLOAD string) (data string, raw bool, err error) {\n ...\n}\n"
|
|
1062
|
+
message: 'Path traversal: `os.Open` is called with a non-literal path inside an HTTP handler. If the path comes from a request
|
|
1063
|
+
parameter an attacker can submit `../../../etc/passwd` and read arbitrary files. Validate the path with `filepath.Clean`
|
|
1064
|
+
AND restrict it to a safe base directory via `strings.HasPrefix(cleanedPath, baseDir)`.'
|
|
1065
|
+
metadata:
|
|
1066
|
+
cwe:
|
|
1067
|
+
- 'CWE-22: Improper Limitation of a Pathname to a Restricted Directory (''Path Traversal'')'
|
|
1068
|
+
owasp:
|
|
1069
|
+
- A01:2021 - Broken Access Control
|
|
1070
|
+
category: security
|
|
1071
|
+
technology:
|
|
1072
|
+
- go
|
|
1073
|
+
confidence: HIGH
|
|
1074
|
+
subcategory:
|
|
1075
|
+
- vuln
|
|
1076
|
+
likelihood: HIGH
|
|
1077
|
+
impact: HIGH
|
|
1078
|
+
severity: ERROR
|
|
1079
|
+
languages:
|
|
1080
|
+
- go
|
|
1081
|
+
- id: narvy-go-pathtraversal-readfile
|
|
1082
|
+
patterns:
|
|
1083
|
+
- pattern-either:
|
|
1084
|
+
- pattern: os.ReadFile($PATH)
|
|
1085
|
+
- pattern: ioutil.ReadFile($PATH)
|
|
1086
|
+
- pattern-not: os.ReadFile("...")
|
|
1087
|
+
- pattern-not: ioutil.ReadFile("...")
|
|
1088
|
+
- pattern-not-inside: '$PATH = "..."
|
|
1089
|
+
|
|
1090
|
+
...
|
|
1091
|
+
|
|
1092
|
+
'
|
|
1093
|
+
- pattern-not: os.ReadFile(filepath.Join("...", "..."))
|
|
1094
|
+
- pattern-either:
|
|
1095
|
+
- pattern-inside: "func $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1096
|
+
- pattern-inside: "func $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1097
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1098
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1099
|
+
- pattern-inside: "func $FN(..., $C echo.Context, ...) $RET {\n ...\n}\n"
|
|
1100
|
+
- pattern-inside: "func $FN(..., $C *gin.Context, ...) {\n ...\n}\n"
|
|
1101
|
+
- pattern-inside: "func $FN($X interface{}, $PAYLOAD string) (data string, raw bool, err error) {\n ...\n}\n"
|
|
1102
|
+
message: 'Path traversal: `os.ReadFile` / `ioutil.ReadFile` is called with a non-literal path inside an HTTP handler. Same
|
|
1103
|
+
risk as `os.Open` - file disclosure. Validate with `filepath.Clean` + base-prefix check.'
|
|
1104
|
+
metadata:
|
|
1105
|
+
cwe:
|
|
1106
|
+
- 'CWE-22: Improper Limitation of a Pathname to a Restricted Directory (''Path Traversal'')'
|
|
1107
|
+
owasp:
|
|
1108
|
+
- A01:2021 - Broken Access Control
|
|
1109
|
+
category: security
|
|
1110
|
+
technology:
|
|
1111
|
+
- go
|
|
1112
|
+
confidence: HIGH
|
|
1113
|
+
subcategory:
|
|
1114
|
+
- vuln
|
|
1115
|
+
likelihood: HIGH
|
|
1116
|
+
impact: HIGH
|
|
1117
|
+
severity: ERROR
|
|
1118
|
+
languages:
|
|
1119
|
+
- go
|
|
1120
|
+
- id: narvy-go-pathtraversal-writefile
|
|
1121
|
+
patterns:
|
|
1122
|
+
- pattern-either:
|
|
1123
|
+
- pattern: os.WriteFile($PATH, ...)
|
|
1124
|
+
- pattern: ioutil.WriteFile($PATH, ...)
|
|
1125
|
+
- pattern: os.Create($PATH)
|
|
1126
|
+
- pattern-not: os.WriteFile("...", ...)
|
|
1127
|
+
- pattern-not: ioutil.WriteFile("...", ...)
|
|
1128
|
+
- pattern-not: os.Create("...")
|
|
1129
|
+
- pattern-not-inside: '$PATH = "..."
|
|
1130
|
+
|
|
1131
|
+
...
|
|
1132
|
+
|
|
1133
|
+
'
|
|
1134
|
+
- pattern-not: os.Create(filepath.Join("...", "..."))
|
|
1135
|
+
- pattern-either:
|
|
1136
|
+
- pattern-inside: "func $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1137
|
+
- pattern-inside: "func $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1138
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1139
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1140
|
+
- pattern-inside: "func $FN(..., $C echo.Context, ...) $RET {\n ...\n}\n"
|
|
1141
|
+
- pattern-inside: "func $FN(..., $C *gin.Context, ...) {\n ...\n}\n"
|
|
1142
|
+
- pattern-inside: "func $FN($X interface{}, $PAYLOAD string) (data string, raw bool, err error) {\n ...\n}\n"
|
|
1143
|
+
message: 'Path traversal (write): `os.WriteFile` / `os.Create` is called with a non-literal path inside an HTTP handler.
|
|
1144
|
+
An attacker can overwrite arbitrary files (e.g. /root/.ssh/authorized_keys). Validate the path with `filepath.Clean` +
|
|
1145
|
+
base-prefix check before writing.'
|
|
1146
|
+
metadata:
|
|
1147
|
+
cwe:
|
|
1148
|
+
- 'CWE-22: Improper Limitation of a Pathname to a Restricted Directory (''Path Traversal'')'
|
|
1149
|
+
owasp:
|
|
1150
|
+
- A01:2021 - Broken Access Control
|
|
1151
|
+
category: security
|
|
1152
|
+
technology:
|
|
1153
|
+
- go
|
|
1154
|
+
confidence: HIGH
|
|
1155
|
+
subcategory:
|
|
1156
|
+
- vuln
|
|
1157
|
+
likelihood: HIGH
|
|
1158
|
+
impact: HIGH
|
|
1159
|
+
severity: ERROR
|
|
1160
|
+
languages:
|
|
1161
|
+
- go
|
|
1162
|
+
- id: narvy-go-pathtraversal-filepath-join-tainted
|
|
1163
|
+
patterns:
|
|
1164
|
+
- pattern: filepath.Join($BASE, $UNTRUSTED)
|
|
1165
|
+
- pattern-not: filepath.Join("...", "...")
|
|
1166
|
+
- pattern-not: filepath.Join($X, "...")
|
|
1167
|
+
- pattern-either:
|
|
1168
|
+
- pattern: '$P := filepath.Join($BASE, $UNTRUSTED)
|
|
1169
|
+
|
|
1170
|
+
...
|
|
1171
|
+
|
|
1172
|
+
os.Open($P)
|
|
1173
|
+
|
|
1174
|
+
'
|
|
1175
|
+
- pattern: '$P := filepath.Join($BASE, $UNTRUSTED)
|
|
1176
|
+
|
|
1177
|
+
...
|
|
1178
|
+
|
|
1179
|
+
os.ReadFile($P)
|
|
1180
|
+
|
|
1181
|
+
'
|
|
1182
|
+
- pattern: '$P := filepath.Join($BASE, $UNTRUSTED)
|
|
1183
|
+
|
|
1184
|
+
...
|
|
1185
|
+
|
|
1186
|
+
os.WriteFile($P, ...)
|
|
1187
|
+
|
|
1188
|
+
'
|
|
1189
|
+
- pattern: '$P := filepath.Join($BASE, $UNTRUSTED)
|
|
1190
|
+
|
|
1191
|
+
...
|
|
1192
|
+
|
|
1193
|
+
os.Create($P)
|
|
1194
|
+
|
|
1195
|
+
'
|
|
1196
|
+
- pattern: '$P := filepath.Join($BASE, $UNTRUSTED)
|
|
1197
|
+
|
|
1198
|
+
...
|
|
1199
|
+
|
|
1200
|
+
os.OpenFile($P, ...)
|
|
1201
|
+
|
|
1202
|
+
'
|
|
1203
|
+
- pattern-not: '$P := filepath.Join($BASE, $UNTRUSTED)
|
|
1204
|
+
|
|
1205
|
+
...
|
|
1206
|
+
|
|
1207
|
+
$P = filepath.Clean($P)
|
|
1208
|
+
|
|
1209
|
+
...
|
|
1210
|
+
|
|
1211
|
+
'
|
|
1212
|
+
- pattern-either:
|
|
1213
|
+
- pattern-inside: "func $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1214
|
+
- pattern-inside: "func $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1215
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1216
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1217
|
+
- pattern-inside: "func $FN(..., $C echo.Context, ...) $RET {\n ...\n}\n"
|
|
1218
|
+
- pattern-inside: "func $FN(..., $C *gin.Context, ...) {\n ...\n}\n"
|
|
1219
|
+
message: 'Path traversal: `filepath.Join` accepts a variable then flows to a file I/O sink without intermediate `filepath.Clean`
|
|
1220
|
+
validation, inside an HTTP handler. `Join` normalises but does NOT prevent `../` escape past the base; you must `Clean`
|
|
1221
|
+
and then verify `strings.HasPrefix(cleaned, baseDir)`.'
|
|
1222
|
+
metadata:
|
|
1223
|
+
cwe:
|
|
1224
|
+
- 'CWE-22: Improper Limitation of a Pathname to a Restricted Directory (''Path Traversal'')'
|
|
1225
|
+
owasp:
|
|
1226
|
+
- A01:2021 - Broken Access Control
|
|
1227
|
+
category: security
|
|
1228
|
+
technology:
|
|
1229
|
+
- go
|
|
1230
|
+
confidence: MEDIUM
|
|
1231
|
+
subcategory:
|
|
1232
|
+
- audit
|
|
1233
|
+
likelihood: MEDIUM
|
|
1234
|
+
impact: HIGH
|
|
1235
|
+
severity: WARNING
|
|
1236
|
+
languages:
|
|
1237
|
+
- go
|
|
1238
|
+
- id: narvy.go.pathtraversal.zip-slip-extraction.zip-slip-extraction
|
|
1239
|
+
message: A file's path is taken from a `zip.Reader`/`tar.Reader` entry name and joined onto a destination directory with
|
|
1240
|
+
no check that the result stays inside it. A malicious archive entry named `../../etc/cron.d/x` escapes the extraction
|
|
1241
|
+
directory and writes anywhere the process can (`zip-slip`, CWE-22). After `filepath.Join(destDir, entry.Name)`, verify
|
|
1242
|
+
the result is still prefixed by `destDir` (e.g. via `filepath.Rel` + reject any leading `..`) before writing.
|
|
1243
|
+
severity: ERROR
|
|
1244
|
+
languages:
|
|
1245
|
+
- go
|
|
1246
|
+
metadata:
|
|
1247
|
+
category: security
|
|
1248
|
+
cwe:
|
|
1249
|
+
- 'CWE-22: Improper Limitation of a Pathname to a Restricted Directory (''Path Traversal'')'
|
|
1250
|
+
owasp:
|
|
1251
|
+
- A01:2021 - Broken Access Control
|
|
1252
|
+
subcategory:
|
|
1253
|
+
- vuln
|
|
1254
|
+
likelihood: MEDIUM
|
|
1255
|
+
impact: HIGH
|
|
1256
|
+
confidence: MEDIUM
|
|
1257
|
+
technology:
|
|
1258
|
+
- go
|
|
1259
|
+
patterns:
|
|
1260
|
+
- pattern-either:
|
|
1261
|
+
- pattern: '$DST := filepath.Join($DESTDIR, $ENTRY.Name)
|
|
1262
|
+
|
|
1263
|
+
...
|
|
1264
|
+
|
|
1265
|
+
os.Create($DST)
|
|
1266
|
+
|
|
1267
|
+
'
|
|
1268
|
+
- pattern: '$DST := filepath.Join($DESTDIR, $HDR.Name)
|
|
1269
|
+
|
|
1270
|
+
...
|
|
1271
|
+
|
|
1272
|
+
os.OpenFile($DST, ...)
|
|
1273
|
+
|
|
1274
|
+
'
|
|
1275
|
+
- pattern-not-inside: "...\nif !strings.HasPrefix($DST, ...) {\n ...\n}\n...\n"
|
|
1276
|
+
- id: narvy.go.pathtraversal.serve-file-tainted.serve-file-tainted
|
|
1277
|
+
message: '`http.ServeFile()` called with a filesystem path built directly from the request URL/query. `ServeFile` has its
|
|
1278
|
+
own `../` guard for the exact `r.URL.Path` case, but once the path is rebuilt via concatenation or `filepath.Join` with
|
|
1279
|
+
a query-parameter value, that guard no longer applies - path traversal to any file the process can read (CWE-22). Confine
|
|
1280
|
+
the served root and reject `..` segments explicitly, or use `http.FileServer` with `http.Dir` on a fixed root.'
|
|
1281
|
+
severity: ERROR
|
|
1282
|
+
languages:
|
|
1283
|
+
- go
|
|
1284
|
+
metadata:
|
|
1285
|
+
category: security
|
|
1286
|
+
cwe:
|
|
1287
|
+
- 'CWE-22: Improper Limitation of a Pathname to a Restricted Directory (''Path Traversal'')'
|
|
1288
|
+
owasp:
|
|
1289
|
+
- A01:2021 - Broken Access Control
|
|
1290
|
+
subcategory:
|
|
1291
|
+
- vuln
|
|
1292
|
+
likelihood: MEDIUM
|
|
1293
|
+
impact: HIGH
|
|
1294
|
+
confidence: MEDIUM
|
|
1295
|
+
technology:
|
|
1296
|
+
- go
|
|
1297
|
+
patterns:
|
|
1298
|
+
- pattern-either:
|
|
1299
|
+
- pattern: http.ServeFile($W, $R, filepath.Join($ROOT, $R.URL.Query().Get(...)))
|
|
1300
|
+
- pattern: http.ServeFile($W, $R, "..." + $R.URL.Query().Get(...))
|
|
1301
|
+
- pattern: http.ServeFile($W, $R, filepath.Join($ROOT, $R.FormValue(...)))
|
|
1302
|
+
- id: narvy.go.pathtraversal.remove-tainted-path.remove-tainted-path
|
|
1303
|
+
message: '`os.Remove()` / `os.RemoveAll()` called with a path built directly from request data. An attacker who controls
|
|
1304
|
+
the path (or a `../` segment within it) can delete files outside the intended directory - path traversal with a destructive
|
|
1305
|
+
sink (CWE-22). Confine to a fixed base directory and reject any resolved path that escapes it.'
|
|
1306
|
+
severity: ERROR
|
|
1307
|
+
languages:
|
|
1308
|
+
- go
|
|
1309
|
+
metadata:
|
|
1310
|
+
category: security
|
|
1311
|
+
cwe:
|
|
1312
|
+
- 'CWE-22: Improper Limitation of a Pathname to a Restricted Directory (''Path Traversal'')'
|
|
1313
|
+
owasp:
|
|
1314
|
+
- A01:2021 - Broken Access Control
|
|
1315
|
+
subcategory:
|
|
1316
|
+
- vuln
|
|
1317
|
+
likelihood: LOW
|
|
1318
|
+
impact: HIGH
|
|
1319
|
+
confidence: MEDIUM
|
|
1320
|
+
technology:
|
|
1321
|
+
- go
|
|
1322
|
+
patterns:
|
|
1323
|
+
- pattern-either:
|
|
1324
|
+
- pattern: os.Remove(filepath.Join($ROOT, $R.URL.Query().Get(...)))
|
|
1325
|
+
- pattern: os.RemoveAll(filepath.Join($ROOT, $R.URL.Query().Get(...)))
|
|
1326
|
+
- pattern: os.Remove($R.FormValue(...))
|
|
1327
|
+
- pattern: os.RemoveAll($R.FormValue(...))
|
|
1328
|
+
- id: narvy.go.secrets.hardcoded-auth-header-value.hardcoded-auth-header-value
|
|
1329
|
+
message: An `Authorization` (or `X-Api-Key`) header is set to a hardcoded string literal that looks like a credential (contains
|
|
1330
|
+
`Bearer `, `Basic `, or is a long opaque token). Anyone with source or binary access recovers the live credential (CWE-798).
|
|
1331
|
+
Load it from an environment variable or secrets manager at startup.
|
|
1332
|
+
severity: WARNING
|
|
1333
|
+
languages:
|
|
1334
|
+
- go
|
|
1335
|
+
metadata:
|
|
1336
|
+
category: security
|
|
1337
|
+
cwe:
|
|
1338
|
+
- 'CWE-798: Use of Hard-coded Credentials'
|
|
1339
|
+
owasp:
|
|
1340
|
+
- A07:2021 - Identification and Authentication Failures
|
|
1341
|
+
subcategory:
|
|
1342
|
+
- vuln
|
|
1343
|
+
likelihood: LOW
|
|
1344
|
+
impact: HIGH
|
|
1345
|
+
confidence: MEDIUM
|
|
1346
|
+
technology:
|
|
1347
|
+
- go
|
|
1348
|
+
patterns:
|
|
1349
|
+
- pattern-either:
|
|
1350
|
+
- pattern: $REQ.Header.Set("Authorization", "Bearer ...")
|
|
1351
|
+
- pattern: $REQ.Header.Set("Authorization", "Basic ...")
|
|
1352
|
+
- pattern: $REQ.Header.Set("X-Api-Key", "...")
|
|
1353
|
+
- id: narvy.go.secrets.hardcoded-dsn-password.hardcoded-dsn-password
|
|
1354
|
+
message: A database connection string (DSN) literal contains an embedded password (`user:password@host` / `password=...`).
|
|
1355
|
+
This ships the live database credential in source control and in the compiled binary (CWE-798). Build the DSN from environment
|
|
1356
|
+
variables / a secrets manager at startup, never a literal.
|
|
1357
|
+
severity: ERROR
|
|
1358
|
+
languages:
|
|
1359
|
+
- go
|
|
1360
|
+
metadata:
|
|
1361
|
+
category: security
|
|
1362
|
+
cwe:
|
|
1363
|
+
- 'CWE-798: Use of Hard-coded Credentials'
|
|
1364
|
+
- 'CWE-259: Use of Hard-coded Password'
|
|
1365
|
+
owasp:
|
|
1366
|
+
- A07:2021 - Identification and Authentication Failures
|
|
1367
|
+
subcategory:
|
|
1368
|
+
- vuln
|
|
1369
|
+
likelihood: LOW
|
|
1370
|
+
impact: HIGH
|
|
1371
|
+
confidence: MEDIUM
|
|
1372
|
+
technology:
|
|
1373
|
+
- go
|
|
1374
|
+
patterns:
|
|
1375
|
+
- pattern-either:
|
|
1376
|
+
- pattern: sql.Open("...", "...:...@...")
|
|
1377
|
+
- pattern: sql.Open("...", "...password=...")
|
|
1378
|
+
- id: narvy.go.secrets.hardcoded-private-key-pem.hardcoded-private-key-pem
|
|
1379
|
+
message: A PEM-formatted private key block (`-----BEGIN ... PRIVATE KEY-----`) is embedded as a Go string literal. This
|
|
1380
|
+
ships the live key in source control and in the compiled binary - anyone with either can decrypt traffic or forge signatures
|
|
1381
|
+
made with it (CWE-798/CWE-321). Load the key from a file/secrets manager at startup, outside the repository.
|
|
1382
|
+
severity: ERROR
|
|
1383
|
+
languages:
|
|
1384
|
+
- go
|
|
1385
|
+
metadata:
|
|
1386
|
+
category: security
|
|
1387
|
+
cwe:
|
|
1388
|
+
- 'CWE-798: Use of Hard-coded Credentials'
|
|
1389
|
+
- 'CWE-321: Use of Hard-coded Cryptographic Key'
|
|
1390
|
+
owasp:
|
|
1391
|
+
- A02:2021 - Cryptographic Failures
|
|
1392
|
+
subcategory:
|
|
1393
|
+
- vuln
|
|
1394
|
+
likelihood: LOW
|
|
1395
|
+
impact: HIGH
|
|
1396
|
+
confidence: HIGH
|
|
1397
|
+
technology:
|
|
1398
|
+
- go
|
|
1399
|
+
patterns:
|
|
1400
|
+
- pattern-regex: (?s)-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----.*-----END (RSA |EC |OPENSSH )?PRIVATE KEY-----
|
|
1401
|
+
- id: narvy.go.session.cookie-secure-explicitly-false.cookie-secure-explicitly-false
|
|
1402
|
+
message: '`http.Cookie{Secure: false}` explicitly disables the Secure flag, allowing this cookie to be sent over plain HTTP.
|
|
1403
|
+
If it carries a session token, an on-path attacker on an unencrypted network segment can capture it (CWE-614). Set `Secure:
|
|
1404
|
+
true` unless this cookie is provably non-sensitive.'
|
|
1405
|
+
severity: WARNING
|
|
1406
|
+
languages:
|
|
1407
|
+
- go
|
|
1408
|
+
metadata:
|
|
1409
|
+
cwe:
|
|
1410
|
+
- 'CWE-614: Sensitive Cookie in HTTPS Session Without ''Secure'' Attribute'
|
|
1411
|
+
owasp:
|
|
1412
|
+
- A05:2021 - Security Misconfiguration
|
|
1413
|
+
category: security
|
|
1414
|
+
subcategory:
|
|
1415
|
+
- vuln
|
|
1416
|
+
technology:
|
|
1417
|
+
- go
|
|
1418
|
+
likelihood: LOW
|
|
1419
|
+
impact: MEDIUM
|
|
1420
|
+
confidence: HIGH
|
|
1421
|
+
vulnerability_class:
|
|
1422
|
+
- Insecure Communication
|
|
1423
|
+
references:
|
|
1424
|
+
- https://cwe.mitre.org/data/definitions/614.html
|
|
1425
|
+
paths:
|
|
1426
|
+
exclude:
|
|
1427
|
+
- '**/*_test.go'
|
|
1428
|
+
patterns:
|
|
1429
|
+
- pattern: "http.Cookie{\n ...,\n Secure: false,\n ...\n}\n"
|
|
1430
|
+
- id: narvy.go.session.cookie-httponly-explicitly-false.cookie-httponly-explicitly-false
|
|
1431
|
+
message: '`http.Cookie{HttpOnly: false}` explicitly disables the HttpOnly flag, allowing client-side JavaScript to read
|
|
1432
|
+
this cookie. If it carries a session token, any XSS on the page can exfiltrate it (CWE-1004). Set `HttpOnly: true` unless
|
|
1433
|
+
client-side JS provably needs to read this cookie.'
|
|
1434
|
+
severity: WARNING
|
|
1435
|
+
languages:
|
|
1436
|
+
- go
|
|
1437
|
+
metadata:
|
|
1438
|
+
cwe:
|
|
1439
|
+
- 'CWE-1004: Sensitive Cookie Without ''HttpOnly'' Flag'
|
|
1440
|
+
owasp:
|
|
1441
|
+
- A05:2021 - Security Misconfiguration
|
|
1442
|
+
category: security
|
|
1443
|
+
subcategory:
|
|
1444
|
+
- vuln
|
|
1445
|
+
technology:
|
|
1446
|
+
- go
|
|
1447
|
+
likelihood: LOW
|
|
1448
|
+
impact: MEDIUM
|
|
1449
|
+
confidence: HIGH
|
|
1450
|
+
vulnerability_class:
|
|
1451
|
+
- Security Misconfiguration
|
|
1452
|
+
references:
|
|
1453
|
+
- https://cwe.mitre.org/data/definitions/1004.html
|
|
1454
|
+
paths:
|
|
1455
|
+
exclude:
|
|
1456
|
+
- '**/*_test.go'
|
|
1457
|
+
patterns:
|
|
1458
|
+
- pattern: "http.Cookie{\n ...,\n HttpOnly: false,\n ...\n}\n"
|
|
1459
|
+
- id: narvy-go-sqli-concat
|
|
1460
|
+
patterns:
|
|
1461
|
+
- pattern-either:
|
|
1462
|
+
- pattern: $DB.Query($A + $B)
|
|
1463
|
+
- pattern: $DB.QueryContext($CTX, $A + $B)
|
|
1464
|
+
- pattern: $DB.QueryRow($A + $B)
|
|
1465
|
+
- pattern: $DB.QueryRowContext($CTX, $A + $B)
|
|
1466
|
+
- pattern: $DB.Exec($A + $B)
|
|
1467
|
+
- pattern: $DB.ExecContext($CTX, $A + $B)
|
|
1468
|
+
- pattern-not: $DB.Query("..." + "...")
|
|
1469
|
+
- pattern-not: $DB.QueryContext($CTX, "..." + "...")
|
|
1470
|
+
- pattern-not: $DB.QueryRow("..." + "...")
|
|
1471
|
+
- pattern-not: $DB.QueryRowContext($CTX, "..." + "...")
|
|
1472
|
+
- pattern-not: $DB.Exec("..." + "...")
|
|
1473
|
+
- pattern-not: $DB.ExecContext($CTX, "..." + "...")
|
|
1474
|
+
message: 'Dynamic SQL: query string is built with the Go concat operator (`+`) rather than a bound placeholder. This is
|
|
1475
|
+
a code-smell audit signal (HIGH), not a proven CRITICAL: without data-flow proof the concatenated operand may be an
|
|
1476
|
+
internal constant (e.g. a table name in a migration) rather than user input. IF the operand is request-derived this is
|
|
1477
|
+
SQL injection (CWE-89) - see the CRITICAL taint rule narvy-go-sqli-request-taint. Prefer placeholders regardless:
|
|
1478
|
+
`db.Query("SELECT ... WHERE id = ?", userID)`.'
|
|
1479
|
+
metadata:
|
|
1480
|
+
cwe:
|
|
1481
|
+
- 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command (''SQL Injection'')'
|
|
1482
|
+
owasp:
|
|
1483
|
+
- A03:2021 - Injection
|
|
1484
|
+
category: security
|
|
1485
|
+
technology:
|
|
1486
|
+
- go
|
|
1487
|
+
confidence: MEDIUM
|
|
1488
|
+
subcategory:
|
|
1489
|
+
- audit
|
|
1490
|
+
likelihood: MEDIUM
|
|
1491
|
+
impact: HIGH
|
|
1492
|
+
severity: WARNING
|
|
1493
|
+
languages:
|
|
1494
|
+
- go
|
|
1495
|
+
- id: narvy-go-sqli-sprintf-via-var
|
|
1496
|
+
patterns:
|
|
1497
|
+
- pattern-either:
|
|
1498
|
+
- pattern: '$QUERY := fmt.Sprintf($FMT, ...)
|
|
1499
|
+
|
|
1500
|
+
...
|
|
1501
|
+
|
|
1502
|
+
$DB.Query($QUERY)
|
|
1503
|
+
|
|
1504
|
+
'
|
|
1505
|
+
- pattern: '$QUERY := fmt.Sprintf($FMT, ...)
|
|
1506
|
+
|
|
1507
|
+
...
|
|
1508
|
+
|
|
1509
|
+
$DB.QueryContext($CTX, $QUERY)
|
|
1510
|
+
|
|
1511
|
+
'
|
|
1512
|
+
- pattern: '$QUERY := fmt.Sprintf($FMT, ...)
|
|
1513
|
+
|
|
1514
|
+
...
|
|
1515
|
+
|
|
1516
|
+
$DB.QueryRow($QUERY)
|
|
1517
|
+
|
|
1518
|
+
'
|
|
1519
|
+
- pattern: '$QUERY := fmt.Sprintf($FMT, ...)
|
|
1520
|
+
|
|
1521
|
+
...
|
|
1522
|
+
|
|
1523
|
+
$DB.Exec($QUERY)
|
|
1524
|
+
|
|
1525
|
+
'
|
|
1526
|
+
- pattern: '$QUERY := fmt.Sprintf($FMT, ...)
|
|
1527
|
+
|
|
1528
|
+
...
|
|
1529
|
+
|
|
1530
|
+
$DB.ExecContext($CTX, $QUERY)
|
|
1531
|
+
|
|
1532
|
+
'
|
|
1533
|
+
- pattern: '$QUERY = fmt.Sprintf($FMT, ...)
|
|
1534
|
+
|
|
1535
|
+
...
|
|
1536
|
+
|
|
1537
|
+
$DB.Exec($QUERY)
|
|
1538
|
+
|
|
1539
|
+
'
|
|
1540
|
+
- pattern: '$QUERY = fmt.Sprintf($FMT, ...)
|
|
1541
|
+
|
|
1542
|
+
...
|
|
1543
|
+
|
|
1544
|
+
$DB.Query($QUERY)
|
|
1545
|
+
|
|
1546
|
+
'
|
|
1547
|
+
message: 'Dynamic SQL: `fmt.Sprintf` builds the query, then the result is passed to `db.Query`/`db.Exec`. Format-string
|
|
1548
|
+
quoting is not driver escaping. This is a code-smell audit signal (HIGH), not a proven CRITICAL: the interpolated
|
|
1549
|
+
args may be internal constants (e.g. a migration table name) rather than user input. IF an arg is request-derived
|
|
1550
|
+
this is SQL injection (CWE-89) - the taint-proven case is reported at CRITICAL by narvy-go-sqli-request-taint.
|
|
1551
|
+
Use parameterised queries with placeholders regardless.'
|
|
1552
|
+
metadata:
|
|
1553
|
+
cwe:
|
|
1554
|
+
- 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command (''SQL Injection'')'
|
|
1555
|
+
owasp:
|
|
1556
|
+
- A03:2021 - Injection
|
|
1557
|
+
category: security
|
|
1558
|
+
technology:
|
|
1559
|
+
- go
|
|
1560
|
+
confidence: MEDIUM
|
|
1561
|
+
subcategory:
|
|
1562
|
+
- audit
|
|
1563
|
+
likelihood: MEDIUM
|
|
1564
|
+
impact: HIGH
|
|
1565
|
+
severity: WARNING
|
|
1566
|
+
languages:
|
|
1567
|
+
- go
|
|
1568
|
+
- id: narvy-go-sqlx-tainted-query
|
|
1569
|
+
patterns:
|
|
1570
|
+
- pattern-inside: "import (\n ...\n $X \"github.com/jmoiron/sqlx\"\n ...\n)\n...\n"
|
|
1571
|
+
- pattern-either:
|
|
1572
|
+
- pattern: $DB.Queryx(fmt.Sprintf("...", ...))
|
|
1573
|
+
- pattern: $DB.MustExec(fmt.Sprintf("...", ...))
|
|
1574
|
+
- pattern: $DB.Queryx($A + $B)
|
|
1575
|
+
- pattern: $DB.QueryxContext($CTX, fmt.Sprintf("...", ...))
|
|
1576
|
+
- pattern: $DB.QueryxContext($CTX, $A + $B)
|
|
1577
|
+
- pattern-not: $DB.Queryx("..." + "...")
|
|
1578
|
+
- pattern-not: $DB.MustExec("..." + "...")
|
|
1579
|
+
- pattern-not: $DB.QueryxContext($CTX, "..." + "...")
|
|
1580
|
+
message: 'Dynamic SQL via sqlx: query built with `fmt.Sprintf` or concatenation. Code-smell audit signal (HIGH), not a
|
|
1581
|
+
proven CRITICAL - without data-flow proof the operand may be an internal constant. IF request-derived it is SQL
|
|
1582
|
+
injection (CWE-89); the taint-proven case is at CRITICAL in narvy-go-sqli-request-taint. sqlx supports named
|
|
1583
|
+
parameters and `?` placeholders - use those instead.'
|
|
1584
|
+
metadata:
|
|
1585
|
+
cwe:
|
|
1586
|
+
- 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command (''SQL Injection'')'
|
|
1587
|
+
owasp:
|
|
1588
|
+
- A03:2021 - Injection
|
|
1589
|
+
category: security
|
|
1590
|
+
technology:
|
|
1591
|
+
- go
|
|
1592
|
+
- sqlx
|
|
1593
|
+
confidence: MEDIUM
|
|
1594
|
+
subcategory:
|
|
1595
|
+
- audit
|
|
1596
|
+
likelihood: MEDIUM
|
|
1597
|
+
impact: HIGH
|
|
1598
|
+
severity: WARNING
|
|
1599
|
+
languages:
|
|
1600
|
+
- go
|
|
1601
|
+
- id: narvy.go.sqli.queryrow-exec-concat.queryrow-exec-concat
|
|
1602
|
+
message: 'Dynamic SQL: `db.QueryRow()` / `db.Exec()` called with a query string built by concatenation or `fmt.Sprintf`
|
|
1603
|
+
instead of using a `?`/`$1` placeholder with a separate argument. Code-smell audit signal (HIGH), not a proven
|
|
1604
|
+
CRITICAL - without data-flow proof the interpolated operand may be an internal constant (e.g. a migration table
|
|
1605
|
+
name) rather than user input. IF request-derived the operand is interpreted as SQL syntax, not data - SQL injection
|
|
1606
|
+
(CWE-89), reported at CRITICAL by narvy-go-sqli-request-taint. Move the value to a bound parameter regardless:
|
|
1607
|
+
`db.QueryRow("... WHERE id = ?", id)`.'
|
|
1608
|
+
severity: WARNING
|
|
1609
|
+
languages:
|
|
1610
|
+
- go
|
|
1611
|
+
metadata:
|
|
1612
|
+
category: security
|
|
1613
|
+
cwe:
|
|
1614
|
+
- 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command (''SQL Injection'')'
|
|
1615
|
+
owasp:
|
|
1616
|
+
- A03:2021 - Injection
|
|
1617
|
+
subcategory:
|
|
1618
|
+
- audit
|
|
1619
|
+
likelihood: MEDIUM
|
|
1620
|
+
impact: HIGH
|
|
1621
|
+
confidence: MEDIUM
|
|
1622
|
+
technology:
|
|
1623
|
+
- go
|
|
1624
|
+
patterns:
|
|
1625
|
+
- pattern-either:
|
|
1626
|
+
- pattern: $DB.QueryRow("..." + $X)
|
|
1627
|
+
- pattern: $DB.QueryRow("..." + $X + "...")
|
|
1628
|
+
- pattern: $DB.QueryRow(fmt.Sprintf("...%s...", $X))
|
|
1629
|
+
- pattern: $DB.Exec("..." + $X)
|
|
1630
|
+
- pattern: $DB.Exec("..." + $X + "...")
|
|
1631
|
+
- pattern: $DB.Exec(fmt.Sprintf("...%s...", $X))
|
|
1632
|
+
# Taint-proven CRITICAL tier: the two rules below use mode:taint to fire only when a request-derived value reaches the sink.
|
|
1633
|
+
- id: narvy-go-sqli-request-taint
|
|
1634
|
+
mode: taint
|
|
1635
|
+
message: 'SQL injection (taint-proven): a value read from the HTTP request reaches a `db.Query`/`Exec`/`QueryRow`
|
|
1636
|
+
(or sqlx) call as part of a dynamically-built query string, not as a bound `?`/`$1` parameter. The attacker
|
|
1637
|
+
controls SQL syntax (CWE-89). Bind the value: `db.Query("... WHERE id = ?", id)`.'
|
|
1638
|
+
severity: ERROR
|
|
1639
|
+
languages:
|
|
1640
|
+
- go
|
|
1641
|
+
metadata:
|
|
1642
|
+
category: security
|
|
1643
|
+
cwe:
|
|
1644
|
+
- 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command (''SQL Injection'')'
|
|
1645
|
+
owasp:
|
|
1646
|
+
- A03:2021 - Injection
|
|
1647
|
+
subcategory:
|
|
1648
|
+
- vuln
|
|
1649
|
+
likelihood: HIGH
|
|
1650
|
+
impact: HIGH
|
|
1651
|
+
confidence: HIGH
|
|
1652
|
+
technology:
|
|
1653
|
+
- go
|
|
1654
|
+
pattern-sources:
|
|
1655
|
+
- patterns:
|
|
1656
|
+
- pattern-either:
|
|
1657
|
+
- pattern: $R.URL.Query().Get(...)
|
|
1658
|
+
- pattern: $R.URL.Query()
|
|
1659
|
+
- pattern: $R.FormValue(...)
|
|
1660
|
+
- pattern: $R.PostFormValue(...)
|
|
1661
|
+
- pattern: $R.Form.Get(...)
|
|
1662
|
+
- pattern: $R.PostForm.Get(...)
|
|
1663
|
+
- pattern: $R.Header.Get(...)
|
|
1664
|
+
- pattern: $C.Param(...)
|
|
1665
|
+
- pattern: $C.PostForm(...)
|
|
1666
|
+
- pattern: $C.QueryParam(...)
|
|
1667
|
+
- pattern: $C.DefaultQuery(...)
|
|
1668
|
+
- pattern: $C.GetHeader(...)
|
|
1669
|
+
- pattern: $C.Params(...)
|
|
1670
|
+
- pattern: mux.Vars($R)[...]
|
|
1671
|
+
- pattern: chi.URLParam(...)
|
|
1672
|
+
pattern-sinks:
|
|
1673
|
+
- patterns:
|
|
1674
|
+
- pattern-either:
|
|
1675
|
+
- pattern: $DB.Query($X)
|
|
1676
|
+
- pattern: $DB.QueryContext($C, $X)
|
|
1677
|
+
- pattern: $DB.QueryRow($X)
|
|
1678
|
+
- pattern: $DB.QueryRowContext($C, $X)
|
|
1679
|
+
- pattern: $DB.Exec($X)
|
|
1680
|
+
- pattern: $DB.ExecContext($C, $X)
|
|
1681
|
+
- pattern: $DB.Queryx($X)
|
|
1682
|
+
- pattern: $DB.QueryxContext($C, $X)
|
|
1683
|
+
- pattern: $DB.MustExec($X)
|
|
1684
|
+
- pattern-not: $DB.Query("...")
|
|
1685
|
+
- pattern-not: $DB.QueryContext($C, "...")
|
|
1686
|
+
- pattern-not: $DB.QueryRow("...")
|
|
1687
|
+
- pattern-not: $DB.QueryRowContext($C, "...")
|
|
1688
|
+
- pattern-not: $DB.Exec("...")
|
|
1689
|
+
- pattern-not: $DB.ExecContext($C, "...")
|
|
1690
|
+
- pattern-not: $DB.Queryx("...")
|
|
1691
|
+
- pattern-not: $DB.QueryxContext($C, "...")
|
|
1692
|
+
- pattern-not: $DB.MustExec("...")
|
|
1693
|
+
- id: narvy-go-xss-template-html-request-taint
|
|
1694
|
+
mode: taint
|
|
1695
|
+
message: 'Reflected/stored XSS (taint-proven): a value read from the HTTP request is cast to `template.HTML` (or
|
|
1696
|
+
`JS` / `URL` / `HTMLAttr` / `CSS`), suppressing `html/template` auto-escaping and emitting attacker input verbatim
|
|
1697
|
+
(CWE-79). Sanitise with `bluemonday` before casting, or drop the cast and let `html/template` escape.'
|
|
1698
|
+
severity: ERROR
|
|
1699
|
+
languages:
|
|
1700
|
+
- go
|
|
1701
|
+
metadata:
|
|
1702
|
+
category: security
|
|
1703
|
+
cwe:
|
|
1704
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
1705
|
+
owasp:
|
|
1706
|
+
- A03:2021 - Injection
|
|
1707
|
+
subcategory:
|
|
1708
|
+
- vuln
|
|
1709
|
+
likelihood: HIGH
|
|
1710
|
+
impact: HIGH
|
|
1711
|
+
confidence: HIGH
|
|
1712
|
+
technology:
|
|
1713
|
+
- go
|
|
1714
|
+
- html/template
|
|
1715
|
+
pattern-sources:
|
|
1716
|
+
- patterns:
|
|
1717
|
+
- pattern-either:
|
|
1718
|
+
- pattern: $R.URL.Query().Get(...)
|
|
1719
|
+
- pattern: $R.URL.Query()
|
|
1720
|
+
- pattern: $R.FormValue(...)
|
|
1721
|
+
- pattern: $R.PostFormValue(...)
|
|
1722
|
+
- pattern: $R.Form.Get(...)
|
|
1723
|
+
- pattern: $R.PostForm.Get(...)
|
|
1724
|
+
- pattern: $R.Header.Get(...)
|
|
1725
|
+
- pattern: $C.Param(...)
|
|
1726
|
+
- pattern: $C.PostForm(...)
|
|
1727
|
+
- pattern: $C.QueryParam(...)
|
|
1728
|
+
- pattern: $C.DefaultQuery(...)
|
|
1729
|
+
- pattern: $C.GetHeader(...)
|
|
1730
|
+
- pattern: $C.Params(...)
|
|
1731
|
+
- pattern: mux.Vars($R)[...]
|
|
1732
|
+
- pattern: chi.URLParam(...)
|
|
1733
|
+
pattern-sinks:
|
|
1734
|
+
- patterns:
|
|
1735
|
+
- pattern-either:
|
|
1736
|
+
- pattern: template.HTML($X)
|
|
1737
|
+
- pattern: template.JS($X)
|
|
1738
|
+
- pattern: template.URL($X)
|
|
1739
|
+
- pattern: template.HTMLAttr($X)
|
|
1740
|
+
- pattern: template.CSS($X)
|
|
1741
|
+
- id: narvy-go-ssrf-http-get
|
|
1742
|
+
patterns:
|
|
1743
|
+
- pattern-either:
|
|
1744
|
+
- pattern: http.Get($URL)
|
|
1745
|
+
- pattern: http.Head($URL)
|
|
1746
|
+
- pattern: http.Post($URL, $CT, $BODY)
|
|
1747
|
+
- pattern: http.PostForm($URL, $DATA)
|
|
1748
|
+
- pattern-not: http.Get("...")
|
|
1749
|
+
- pattern-not: http.Head("...")
|
|
1750
|
+
- pattern-not: http.Post("...", $CT, $BODY)
|
|
1751
|
+
- pattern-not: http.PostForm("...", $DATA)
|
|
1752
|
+
- pattern-not: http.Get(os.Getenv($X))
|
|
1753
|
+
- pattern-not: http.Get($X + "/...")
|
|
1754
|
+
- pattern-either:
|
|
1755
|
+
- pattern-inside: "func $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1756
|
+
- pattern-inside: "func $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1757
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1758
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1759
|
+
- pattern-inside: "func $FN(..., $C echo.Context, ...) $RET {\n ...\n}\n"
|
|
1760
|
+
- pattern-inside: "func $FN(..., $C *gin.Context, ...) {\n ...\n}\n"
|
|
1761
|
+
- pattern-inside: "func $FN($SAFETY common.Safety, $PAYLOAD string, $X interface{}) ($A, $B, $C) {\n ...\n}\n"
|
|
1762
|
+
message: 'SSRF risk: `net/http` request to a non-literal URL inside an HTTP handler. If `$URL` comes from a request parameter
|
|
1763
|
+
the attacker can scan internal services, hit cloud-metadata endpoints (169.254.169.254), or trigger arbitrary outbound
|
|
1764
|
+
traffic. Validate the URL against an allow-list of hosts before requesting.'
|
|
1765
|
+
metadata:
|
|
1766
|
+
cwe:
|
|
1767
|
+
- 'CWE-918: Server-Side Request Forgery (SSRF)'
|
|
1768
|
+
owasp:
|
|
1769
|
+
- A10:2021 - Server-Side Request Forgery (SSRF)
|
|
1770
|
+
category: security
|
|
1771
|
+
technology:
|
|
1772
|
+
- go
|
|
1773
|
+
confidence: HIGH
|
|
1774
|
+
subcategory:
|
|
1775
|
+
- vuln
|
|
1776
|
+
likelihood: HIGH
|
|
1777
|
+
impact: HIGH
|
|
1778
|
+
severity: ERROR
|
|
1779
|
+
languages:
|
|
1780
|
+
- go
|
|
1781
|
+
- id: narvy-go-ssrf-newrequest-tainted
|
|
1782
|
+
patterns:
|
|
1783
|
+
- pattern-either:
|
|
1784
|
+
- pattern: http.NewRequest($METHOD, $URL, $BODY)
|
|
1785
|
+
- pattern: http.NewRequestWithContext($CTX, $METHOD, $URL, $BODY)
|
|
1786
|
+
- pattern-not: http.NewRequest($METHOD, "...", $BODY)
|
|
1787
|
+
- pattern-not: http.NewRequestWithContext($CTX, $METHOD, "...", $BODY)
|
|
1788
|
+
- pattern-not: http.NewRequest($METHOD, os.Getenv($X), $BODY)
|
|
1789
|
+
- pattern-not: http.NewRequestWithContext($CTX, $METHOD, os.Getenv($X), $BODY)
|
|
1790
|
+
- pattern-either:
|
|
1791
|
+
- pattern-inside: "func $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1792
|
+
- pattern-inside: "func $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1793
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $R *http.Request, ...) {\n ...\n}\n"
|
|
1794
|
+
- pattern-inside: "func ($RECV $T) $FN(..., $W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
1795
|
+
- pattern-inside: "func $FN(..., $C echo.Context, ...) $RET {\n ...\n}\n"
|
|
1796
|
+
- pattern-inside: "func $FN(..., $C *gin.Context, ...) {\n ...\n}\n"
|
|
1797
|
+
message: 'SSRF risk: `http.NewRequest` URL is a non-literal expression inside an HTTP handler. Confirm the URL is validated
|
|
1798
|
+
against an allow-list before this request is sent via `client.Do(req)`.'
|
|
1799
|
+
metadata:
|
|
1800
|
+
cwe:
|
|
1801
|
+
- 'CWE-918: Server-Side Request Forgery (SSRF)'
|
|
1802
|
+
owasp:
|
|
1803
|
+
- A10:2021 - Server-Side Request Forgery (SSRF)
|
|
1804
|
+
category: security
|
|
1805
|
+
technology:
|
|
1806
|
+
- go
|
|
1807
|
+
confidence: MEDIUM
|
|
1808
|
+
subcategory:
|
|
1809
|
+
- audit
|
|
1810
|
+
likelihood: MEDIUM
|
|
1811
|
+
impact: HIGH
|
|
1812
|
+
severity: WARNING
|
|
1813
|
+
languages:
|
|
1814
|
+
- go
|
|
1815
|
+
- id: narvy-go-ssrf-client-get
|
|
1816
|
+
patterns:
|
|
1817
|
+
- pattern-either:
|
|
1818
|
+
- pattern: $CLIENT.Get($URL)
|
|
1819
|
+
- pattern: $CLIENT.Post($URL, $CT, $BODY)
|
|
1820
|
+
- pattern: $CLIENT.PostForm($URL, $DATA)
|
|
1821
|
+
- pattern-inside: '$CLIENT := &http.Client{...}
|
|
1822
|
+
|
|
1823
|
+
...
|
|
1824
|
+
|
|
1825
|
+
'
|
|
1826
|
+
- pattern-not: $CLIENT.Get("...")
|
|
1827
|
+
- pattern-not: $CLIENT.Post("...", $CT, $BODY)
|
|
1828
|
+
- pattern-not: $CLIENT.PostForm("...", $DATA)
|
|
1829
|
+
message: 'SSRF risk: custom `http.Client` is invoked with a non-literal URL. Same risk as `http.Get` - validate against
|
|
1830
|
+
an allow-list of hosts.'
|
|
1831
|
+
metadata:
|
|
1832
|
+
cwe:
|
|
1833
|
+
- 'CWE-918: Server-Side Request Forgery (SSRF)'
|
|
1834
|
+
owasp:
|
|
1835
|
+
- A10:2021 - Server-Side Request Forgery (SSRF)
|
|
1836
|
+
category: security
|
|
1837
|
+
technology:
|
|
1838
|
+
- go
|
|
1839
|
+
confidence: MEDIUM
|
|
1840
|
+
subcategory:
|
|
1841
|
+
- audit
|
|
1842
|
+
likelihood: MEDIUM
|
|
1843
|
+
impact: HIGH
|
|
1844
|
+
severity: WARNING
|
|
1845
|
+
languages:
|
|
1846
|
+
- go
|
|
1847
|
+
- id: narvy.go.ssrf.net-dial-tainted-host.net-dial-tainted-host
|
|
1848
|
+
message: '`net.Dial()` / `net.DialTimeout()` called with a host/address built from request data. This lets an attacker make
|
|
1849
|
+
the server open a raw TCP connection to any internal host/port it can reach (cloud metadata endpoints, internal admin
|
|
1850
|
+
ports, redis/memcache with no auth) - SSRF at the socket level (CWE-918). Validate the target against a strict allow-list,
|
|
1851
|
+
and resolve+re-check the IP is not in a private/link-local range before connecting.'
|
|
1852
|
+
severity: ERROR
|
|
1853
|
+
languages:
|
|
1854
|
+
- go
|
|
1855
|
+
metadata:
|
|
1856
|
+
category: security
|
|
1857
|
+
cwe:
|
|
1858
|
+
- 'CWE-918: Server-Side Request Forgery (SSRF)'
|
|
1859
|
+
owasp:
|
|
1860
|
+
- A10:2021 - Server-Side Request Forgery (SSRF)
|
|
1861
|
+
subcategory:
|
|
1862
|
+
- vuln
|
|
1863
|
+
likelihood: MEDIUM
|
|
1864
|
+
impact: HIGH
|
|
1865
|
+
confidence: MEDIUM
|
|
1866
|
+
technology:
|
|
1867
|
+
- go
|
|
1868
|
+
patterns:
|
|
1869
|
+
- pattern-either:
|
|
1870
|
+
- pattern: net.Dial("tcp", $R.URL.Query().Get(...))
|
|
1871
|
+
- pattern: net.Dial("tcp", $R.FormValue(...))
|
|
1872
|
+
- pattern: net.DialTimeout("tcp", $R.URL.Query().Get(...), ...)
|
|
1873
|
+
- id: narvy.go.ssrf.outbound-url-host-from-request-concat.outbound-url-host-from-request-concat
|
|
1874
|
+
message: An outbound URL is assembled by concatenating a fixed scheme onto a host taken directly from request data, then
|
|
1875
|
+
handed to an HTTP client. Same SSRF risk as passing the tainted value straight to `http.Get` (CWE-918) - the concatenation
|
|
1876
|
+
doesn't add any validation. Resolve and check the host against an allow-list before building the request.
|
|
1877
|
+
severity: ERROR
|
|
1878
|
+
languages:
|
|
1879
|
+
- go
|
|
1880
|
+
metadata:
|
|
1881
|
+
category: security
|
|
1882
|
+
cwe:
|
|
1883
|
+
- 'CWE-918: Server-Side Request Forgery (SSRF)'
|
|
1884
|
+
owasp:
|
|
1885
|
+
- A10:2021 - Server-Side Request Forgery (SSRF)
|
|
1886
|
+
subcategory:
|
|
1887
|
+
- vuln
|
|
1888
|
+
likelihood: MEDIUM
|
|
1889
|
+
impact: HIGH
|
|
1890
|
+
confidence: MEDIUM
|
|
1891
|
+
technology:
|
|
1892
|
+
- go
|
|
1893
|
+
patterns:
|
|
1894
|
+
- pattern-either:
|
|
1895
|
+
- pattern: '$URL := "http://" + $R.URL.Query().Get(...)
|
|
1896
|
+
|
|
1897
|
+
...
|
|
1898
|
+
|
|
1899
|
+
http.Get($URL)
|
|
1900
|
+
|
|
1901
|
+
'
|
|
1902
|
+
- pattern: '$URL := "https://" + $R.FormValue(...)
|
|
1903
|
+
|
|
1904
|
+
...
|
|
1905
|
+
|
|
1906
|
+
http.Get($URL)
|
|
1907
|
+
|
|
1908
|
+
'
|
|
1909
|
+
- id: narvy.go.transport.insecure-skip-verify.insecure-skip-verify
|
|
1910
|
+
message: '`InsecureSkipVerify: true` in a TLS (or TLS-forwarding) config struct literal disables TLS certificate validation
|
|
1911
|
+
entirely. Any certificate - including one presented by an attacker-in-the-middle - will be accepted, defeating the point
|
|
1912
|
+
of TLS (CWE-295). Remove the field (defaults to verifying) or, for pinning use cases, implement `VerifyConnection`/`VerifyPeerCertificate`
|
|
1913
|
+
instead.'
|
|
1914
|
+
severity: ERROR
|
|
1915
|
+
languages:
|
|
1916
|
+
- go
|
|
1917
|
+
metadata:
|
|
1918
|
+
category: security
|
|
1919
|
+
cwe:
|
|
1920
|
+
- 'CWE-295: Improper Certificate Validation'
|
|
1921
|
+
owasp:
|
|
1922
|
+
- A02:2021 - Cryptographic Failures
|
|
1923
|
+
subcategory:
|
|
1924
|
+
- vuln
|
|
1925
|
+
likelihood: MEDIUM
|
|
1926
|
+
impact: HIGH
|
|
1927
|
+
confidence: HIGH
|
|
1928
|
+
technology:
|
|
1929
|
+
- go
|
|
1930
|
+
paths:
|
|
1931
|
+
exclude:
|
|
1932
|
+
- '**/*_test.go'
|
|
1933
|
+
- '**/testdata/**'
|
|
1934
|
+
- '**/protocoltest/**'
|
|
1935
|
+
patterns:
|
|
1936
|
+
- pattern: '$T{..., InsecureSkipVerify: true, ...}
|
|
1937
|
+
|
|
1938
|
+
'
|
|
1939
|
+
- id: narvy.go.transport.tls-insecure-skip-verify.tls-insecure-skip-verify
|
|
1940
|
+
message: '`InsecureSkipVerify` field on a TLS config is set to `true` via field assignment (not the struct-literal form).
|
|
1941
|
+
This disables certificate validation on that connection - any certificate is accepted, defeating TLS (CWE-295). Remove
|
|
1942
|
+
the assignment (defaults to `false`).'
|
|
1943
|
+
severity: ERROR
|
|
1944
|
+
languages:
|
|
1945
|
+
- go
|
|
1946
|
+
metadata:
|
|
1947
|
+
category: security
|
|
1948
|
+
cwe:
|
|
1949
|
+
- 'CWE-295: Improper Certificate Validation'
|
|
1950
|
+
owasp:
|
|
1951
|
+
- A02:2021 - Cryptographic Failures
|
|
1952
|
+
subcategory:
|
|
1953
|
+
- vuln
|
|
1954
|
+
likelihood: MEDIUM
|
|
1955
|
+
impact: HIGH
|
|
1956
|
+
confidence: HIGH
|
|
1957
|
+
technology:
|
|
1958
|
+
- go
|
|
1959
|
+
paths:
|
|
1960
|
+
exclude:
|
|
1961
|
+
- '**/*_test.go'
|
|
1962
|
+
- '**/testdata/**'
|
|
1963
|
+
- '**/protocoltest/**'
|
|
1964
|
+
pattern: $CFG.InsecureSkipVerify = true
|
|
1965
|
+
- id: narvy.go.tls.missing-ssl-minversion.missing-ssl-minversion
|
|
1966
|
+
message: '`tls.Config{}` constructed with no `MinVersion` field. Go 1.18+ defaults to TLS 1.2 in the absence of this field,
|
|
1967
|
+
so this is a hardening advisory rather than a live vuln by itself - set `MinVersion: tls.VersionTLS12` (or 1.3) explicitly
|
|
1968
|
+
so the floor cannot silently drop on an older Go toolchain or be overridden elsewhere in the struct literal.'
|
|
1969
|
+
severity: INFO
|
|
1970
|
+
languages:
|
|
1971
|
+
- go
|
|
1972
|
+
metadata:
|
|
1973
|
+
category: security
|
|
1974
|
+
cwe:
|
|
1975
|
+
- 'CWE-326: Inadequate Encryption Strength'
|
|
1976
|
+
owasp:
|
|
1977
|
+
- A02:2021 - Cryptographic Failures
|
|
1978
|
+
subcategory:
|
|
1979
|
+
- audit
|
|
1980
|
+
likelihood: LOW
|
|
1981
|
+
impact: MEDIUM
|
|
1982
|
+
confidence: LOW
|
|
1983
|
+
technology:
|
|
1984
|
+
- go
|
|
1985
|
+
patterns:
|
|
1986
|
+
- pattern: 'tls.Config{...}
|
|
1987
|
+
|
|
1988
|
+
'
|
|
1989
|
+
- pattern-not: 'tls.Config{..., MinVersion: $V, ...}
|
|
1990
|
+
|
|
1991
|
+
'
|
|
1992
|
+
- id: narvy.go.tls.explicit-weak-min-version.explicit-weak-min-version
|
|
1993
|
+
message: '`tls.Config.MinVersion` explicitly set to SSLv3/TLS1.0/TLS1.1. All three have known practical attacks (POODLE,
|
|
1994
|
+
BEAST) and are disallowed by PCI-DSS; explicitly pinning the floor there (rather than merely omitting it) is a real, exploitable
|
|
1995
|
+
defect (CWE-326). Set `MinVersion: tls.VersionTLS12` or higher.'
|
|
1996
|
+
severity: ERROR
|
|
1997
|
+
languages:
|
|
1998
|
+
- go
|
|
1999
|
+
metadata:
|
|
2000
|
+
category: security
|
|
2001
|
+
cwe:
|
|
2002
|
+
- 'CWE-326: Inadequate Encryption Strength'
|
|
2003
|
+
owasp:
|
|
2004
|
+
- A02:2021 - Cryptographic Failures
|
|
2005
|
+
subcategory:
|
|
2006
|
+
- vuln
|
|
2007
|
+
likelihood: MEDIUM
|
|
2008
|
+
impact: HIGH
|
|
2009
|
+
confidence: HIGH
|
|
2010
|
+
technology:
|
|
2011
|
+
- go
|
|
2012
|
+
patterns:
|
|
2013
|
+
- pattern-either:
|
|
2014
|
+
- pattern: 'tls.Config{..., MinVersion: tls.VersionSSL30, ...}
|
|
2015
|
+
|
|
2016
|
+
'
|
|
2017
|
+
- pattern: 'tls.Config{..., MinVersion: tls.VersionTLS10, ...}
|
|
2018
|
+
|
|
2019
|
+
'
|
|
2020
|
+
- pattern: 'tls.Config{..., MinVersion: tls.VersionTLS11, ...}
|
|
2021
|
+
|
|
2022
|
+
'
|
|
2023
|
+
- id: narvy.go.tls.weak-cipher-suite-allowed.weak-cipher-suite-allowed
|
|
2024
|
+
message: '`tls.Config.CipherSuites` explicitly includes a CBC-mode or RC4 cipher suite. Including these re-enables ciphers
|
|
2025
|
+
modern TLS stacks disable by default because of padding-oracle (Lucky13) and keystream-bias attacks (CWE-327). Stick to
|
|
2026
|
+
the Go 1.18+ default cipher suite list (leave `CipherSuites` unset) or select only AEAD suites (`TLS_*_WITH_AES_*_GCM_*`,
|
|
2027
|
+
`TLS_*_CHACHA20_POLY1305_*`).'
|
|
2028
|
+
severity: WARNING
|
|
2029
|
+
languages:
|
|
2030
|
+
- go
|
|
2031
|
+
metadata:
|
|
2032
|
+
category: security
|
|
2033
|
+
cwe:
|
|
2034
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
2035
|
+
owasp:
|
|
2036
|
+
- A02:2021 - Cryptographic Failures
|
|
2037
|
+
subcategory:
|
|
2038
|
+
- vuln
|
|
2039
|
+
likelihood: LOW
|
|
2040
|
+
impact: MEDIUM
|
|
2041
|
+
confidence: MEDIUM
|
|
2042
|
+
technology:
|
|
2043
|
+
- go
|
|
2044
|
+
patterns:
|
|
2045
|
+
- pattern-either:
|
|
2046
|
+
- pattern: tls.TLS_RSA_WITH_RC4_128_SHA
|
|
2047
|
+
- pattern: tls.TLS_RSA_WITH_AES_128_CBC_SHA
|
|
2048
|
+
- pattern: tls.TLS_RSA_WITH_AES_256_CBC_SHA
|
|
2049
|
+
- id: narvy.go.transport.grpc-dial-insecure-credentials.grpc-dial-insecure-credentials
|
|
2050
|
+
message: '`grpc.Dial()` (or `grpc.NewClient()`) called with `grpc.WithInsecure()`/`insecure.NewCredentials()`, disabling
|
|
2051
|
+
transport encryption on the gRPC connection entirely - every request/response (including any auth token in metadata) crosses
|
|
2052
|
+
the wire in plaintext (CWE-319). Use `grpc.WithTransportCredentials(credentials.NewTLS(...))` for any connection that
|
|
2053
|
+
leaves the local host.'
|
|
2054
|
+
severity: WARNING
|
|
2055
|
+
languages:
|
|
2056
|
+
- go
|
|
2057
|
+
metadata:
|
|
2058
|
+
category: security
|
|
2059
|
+
cwe:
|
|
2060
|
+
- 'CWE-319: Cleartext Transmission of Sensitive Information'
|
|
2061
|
+
owasp:
|
|
2062
|
+
- A02:2021 - Cryptographic Failures
|
|
2063
|
+
subcategory:
|
|
2064
|
+
- vuln
|
|
2065
|
+
likelihood: LOW
|
|
2066
|
+
impact: HIGH
|
|
2067
|
+
confidence: MEDIUM
|
|
2068
|
+
technology:
|
|
2069
|
+
- go
|
|
2070
|
+
patterns:
|
|
2071
|
+
- pattern-either:
|
|
2072
|
+
- pattern: grpc.Dial($ADDR, ..., grpc.WithInsecure(), ...)
|
|
2073
|
+
- pattern: grpc.Dial($ADDR, ..., grpc.WithTransportCredentials(insecure.NewCredentials()), ...)
|
|
2074
|
+
- pattern: grpc.NewClient($ADDR, ..., grpc.WithTransportCredentials(insecure.NewCredentials()), ...)
|
|
2075
|
+
- id: narvy.go.transport.grpc-serve-no-tls-credentials.grpc-serve-no-tls-credentials
|
|
2076
|
+
message: '`grpc.NewServer()` constructed with no transport credentials, so the server accepts plaintext connections. Any
|
|
2077
|
+
auth metadata or payload sent to it crosses the wire unencrypted (CWE-319). Pass `grpc.Creds(credentials.NewTLS(...))`
|
|
2078
|
+
unless the server is deliberately scoped to a trusted local/mTLS-terminated network.'
|
|
2079
|
+
severity: INFO
|
|
2080
|
+
languages:
|
|
2081
|
+
- go
|
|
2082
|
+
metadata:
|
|
2083
|
+
category: security
|
|
2084
|
+
cwe:
|
|
2085
|
+
- 'CWE-319: Cleartext Transmission of Sensitive Information'
|
|
2086
|
+
owasp:
|
|
2087
|
+
- A02:2021 - Cryptographic Failures
|
|
2088
|
+
subcategory:
|
|
2089
|
+
- audit
|
|
2090
|
+
likelihood: LOW
|
|
2091
|
+
impact: MEDIUM
|
|
2092
|
+
confidence: LOW
|
|
2093
|
+
technology:
|
|
2094
|
+
- go
|
|
2095
|
+
patterns:
|
|
2096
|
+
- pattern: grpc.NewServer()
|
|
2097
|
+
- id: narvy.go.open-redirect.shared-url-struct-mutation.shared-url-struct-mutation
|
|
2098
|
+
message: A `url.URL` struct's `Host` or `Scheme` field is mutated using a value that traces back to request data (query
|
|
2099
|
+
param, header, form value). Building a proxy/redirect target this way lets an attacker redirect the request to an arbitrary
|
|
2100
|
+
external host by controlling that value (CWE-601 / SSRF-adjacent when the mutated URL is then fetched server-side rather
|
|
2101
|
+
than redirected to). Validate the host against a fixed allow-list before assigning it.
|
|
2102
|
+
severity: WARNING
|
|
2103
|
+
languages:
|
|
2104
|
+
- go
|
|
2105
|
+
metadata:
|
|
2106
|
+
category: security
|
|
2107
|
+
cwe:
|
|
2108
|
+
- 'CWE-601: URL Redirection to Untrusted Site (''Open Redirect'')'
|
|
2109
|
+
owasp:
|
|
2110
|
+
- A01:2021 - Broken Access Control
|
|
2111
|
+
subcategory:
|
|
2112
|
+
- vuln
|
|
2113
|
+
likelihood: LOW
|
|
2114
|
+
impact: MEDIUM
|
|
2115
|
+
confidence: LOW
|
|
2116
|
+
technology:
|
|
2117
|
+
- go
|
|
2118
|
+
patterns:
|
|
2119
|
+
- pattern-either:
|
|
2120
|
+
- pattern: $U.Host = $R.URL.Query().Get(...)
|
|
2121
|
+
- pattern: $U.Host = $R.FormValue(...)
|
|
2122
|
+
- pattern: $U.Host = $R.Header.Get(...)
|
|
2123
|
+
- pattern: $U.Scheme = $R.URL.Query().Get(...)
|
|
2124
|
+
- pattern: $U.Scheme = $R.FormValue(...)
|
|
2125
|
+
- id: narvy.go.open-redirect.location-header-tainted.location-header-tainted
|
|
2126
|
+
message: '`Location` response header set directly from request data via `Header().Set()`, bypassing `http.Redirect()`''s
|
|
2127
|
+
handling entirely. Same open-redirect risk as `http.Redirect()` with a tainted target (CWE-601): validate against a fixed
|
|
2128
|
+
allow-list before setting the header, or only allow relative paths.'
|
|
2129
|
+
severity: WARNING
|
|
2130
|
+
languages:
|
|
2131
|
+
- go
|
|
2132
|
+
metadata:
|
|
2133
|
+
category: security
|
|
2134
|
+
cwe:
|
|
2135
|
+
- 'CWE-601: URL Redirection to Untrusted Site (''Open Redirect'')'
|
|
2136
|
+
owasp:
|
|
2137
|
+
- A01:2021 - Broken Access Control
|
|
2138
|
+
subcategory:
|
|
2139
|
+
- vuln
|
|
2140
|
+
likelihood: MEDIUM
|
|
2141
|
+
impact: MEDIUM
|
|
2142
|
+
confidence: MEDIUM
|
|
2143
|
+
technology:
|
|
2144
|
+
- go
|
|
2145
|
+
patterns:
|
|
2146
|
+
- pattern-either:
|
|
2147
|
+
- pattern: $W.Header().Set("Location", $R.URL.Query().Get(...))
|
|
2148
|
+
- pattern: $W.Header().Set("Location", $R.FormValue(...))
|
|
2149
|
+
- id: narvy.go.crypto.weak-hash-password.weak-hash-password
|
|
2150
|
+
message: MD5/SHA1 applied to a value whose name indicates a password or credential. Both are fast, unsalted digests, brute-forceable
|
|
2151
|
+
with commodity GPUs (MD5 is also collision-broken). Use `golang.org/x/crypto/bcrypt` or `golang.org/x/crypto/argon2` for
|
|
2152
|
+
credential storage. CWE-916.
|
|
2153
|
+
severity: ERROR
|
|
2154
|
+
languages:
|
|
2155
|
+
- go
|
|
2156
|
+
metadata:
|
|
2157
|
+
cwe:
|
|
2158
|
+
- 'CWE-916: Use of Password Hash With Insufficient Computational Effort'
|
|
2159
|
+
owasp:
|
|
2160
|
+
- A02:2021 - Cryptographic Failures
|
|
2161
|
+
category: security
|
|
2162
|
+
subcategory:
|
|
2163
|
+
- vuln
|
|
2164
|
+
technology:
|
|
2165
|
+
- go
|
|
2166
|
+
likelihood: MEDIUM
|
|
2167
|
+
impact: HIGH
|
|
2168
|
+
confidence: MEDIUM
|
|
2169
|
+
vulnerability_class:
|
|
2170
|
+
- Cryptographic Issues
|
|
2171
|
+
patterns:
|
|
2172
|
+
- pattern-either:
|
|
2173
|
+
- pattern: md5.Sum([]byte($PW))
|
|
2174
|
+
- pattern: sha1.Sum([]byte($PW))
|
|
2175
|
+
- metavariable-regex:
|
|
2176
|
+
metavariable: $PW
|
|
2177
|
+
regex: (?i).*(pass|pwd|secret|credential).*
|
|
2178
|
+
- id: narvy.go.crypto.weak-des-cipher.weak-des-cipher
|
|
2179
|
+
message: '`crypto/des` used to construct a cipher. DES has a brute-forceable 56-bit effective key, and TripleDES (168-bit
|
|
2180
|
+
nominal, ~112-bit effective) is deprecated by NIST for new use and vulnerable to SWEET32 birthday attacks on its 64-bit
|
|
2181
|
+
block size. Use `crypto/aes` with GCM instead. CWE-327.'
|
|
2182
|
+
severity: ERROR
|
|
2183
|
+
languages:
|
|
2184
|
+
- go
|
|
2185
|
+
metadata:
|
|
2186
|
+
cwe:
|
|
2187
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
2188
|
+
owasp:
|
|
2189
|
+
- A02:2021 - Cryptographic Failures
|
|
2190
|
+
category: security
|
|
2191
|
+
subcategory:
|
|
2192
|
+
- vuln
|
|
2193
|
+
technology:
|
|
2194
|
+
- go
|
|
2195
|
+
likelihood: LOW
|
|
2196
|
+
impact: HIGH
|
|
2197
|
+
confidence: HIGH
|
|
2198
|
+
vulnerability_class:
|
|
2199
|
+
- Cryptographic Issues
|
|
2200
|
+
patterns:
|
|
2201
|
+
- pattern-either:
|
|
2202
|
+
- pattern: des.NewCipher(...)
|
|
2203
|
+
- pattern: des.NewTripleDESCipher(...)
|
|
2204
|
+
- id: narvy.go.crypto.math-rand-security-token.math-rand-security-token
|
|
2205
|
+
message: '`math/rand` (a deterministic PRNG, not cryptographically secure) is used to produce a value assigned to a variable
|
|
2206
|
+
whose name indicates security-sensitive use (token, secret, password, session, nonce, apikey, csrf). Its internal state
|
|
2207
|
+
can be recovered from observed outputs, making future values predictable. Use `crypto/rand` (`rand.Read` / a helper that
|
|
2208
|
+
base64/hex-encodes its bytes) for anything security-relevant. CWE-338.'
|
|
2209
|
+
severity: WARNING
|
|
2210
|
+
languages:
|
|
2211
|
+
- go
|
|
2212
|
+
metadata:
|
|
2213
|
+
cwe:
|
|
2214
|
+
- 'CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)'
|
|
2215
|
+
- 'CWE-330: Use of Insufficiently Random Values'
|
|
2216
|
+
owasp:
|
|
2217
|
+
- A02:2021 - Cryptographic Failures
|
|
2218
|
+
category: security
|
|
2219
|
+
subcategory:
|
|
2220
|
+
- audit
|
|
2221
|
+
technology:
|
|
2222
|
+
- go
|
|
2223
|
+
likelihood: MEDIUM
|
|
2224
|
+
impact: HIGH
|
|
2225
|
+
confidence: MEDIUM
|
|
2226
|
+
vulnerability_class:
|
|
2227
|
+
- Insufficient Entropy
|
|
2228
|
+
patterns:
|
|
2229
|
+
- pattern-either:
|
|
2230
|
+
- pattern: $TOKEN := rand.Int(...)
|
|
2231
|
+
- pattern: $TOKEN := rand.Intn(...)
|
|
2232
|
+
- pattern: $TOKEN := rand.Int63(...)
|
|
2233
|
+
- pattern: $TOKEN = rand.Intn(...)
|
|
2234
|
+
- metavariable-regex:
|
|
2235
|
+
metavariable: $TOKEN
|
|
2236
|
+
regex: (?i).*(token|secret|password|passwd|pwd|session|nonce|apikey|api_key|csrf|auth).*
|
|
2237
|
+
- pattern-not-inside: 'import "crypto/rand"
|
|
2238
|
+
|
|
2239
|
+
...
|
|
2240
|
+
|
|
2241
|
+
'
|
|
2242
|
+
- id: narvy.go.crypto.use-of-md5.use-of-md5
|
|
2243
|
+
message: '`md5.Sum()` / `md5.New()` used to hash a value. MD5 is cryptographically broken (collision-forgeable) and must
|
|
2244
|
+
not be used for integrity checks, signatures, or password hashing (CWE-327 / CWE-328). Use SHA-256+ for integrity/signing,
|
|
2245
|
+
or `bcrypt`/`argon2`/`scrypt` for passwords.'
|
|
2246
|
+
severity: WARNING
|
|
2247
|
+
languages:
|
|
2248
|
+
- go
|
|
2249
|
+
metadata:
|
|
2250
|
+
category: security
|
|
2251
|
+
cwe:
|
|
2252
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
2253
|
+
- 'CWE-328: Use of Weak Hash'
|
|
2254
|
+
owasp:
|
|
2255
|
+
- A02:2021 - Cryptographic Failures
|
|
2256
|
+
subcategory:
|
|
2257
|
+
- vuln
|
|
2258
|
+
likelihood: LOW
|
|
2259
|
+
impact: MEDIUM
|
|
2260
|
+
confidence: MEDIUM
|
|
2261
|
+
technology:
|
|
2262
|
+
- go
|
|
2263
|
+
patterns:
|
|
2264
|
+
- pattern-either:
|
|
2265
|
+
- pattern: md5.Sum(...)
|
|
2266
|
+
- pattern: md5.New()
|
|
2267
|
+
- id: narvy.go.crypto.use-of-sha1.use-of-sha1
|
|
2268
|
+
message: '`sha1.Sum()` / `sha1.New()` used to hash a value. SHA-1 has practical collision attacks and should not be used
|
|
2269
|
+
for integrity checks or signatures (CWE-327 / CWE-328). Use SHA-256 or better.'
|
|
2270
|
+
severity: WARNING
|
|
2271
|
+
languages:
|
|
2272
|
+
- go
|
|
2273
|
+
metadata:
|
|
2274
|
+
category: security
|
|
2275
|
+
cwe:
|
|
2276
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
2277
|
+
- 'CWE-328: Use of Weak Hash'
|
|
2278
|
+
owasp:
|
|
2279
|
+
- A02:2021 - Cryptographic Failures
|
|
2280
|
+
subcategory:
|
|
2281
|
+
- vuln
|
|
2282
|
+
likelihood: LOW
|
|
2283
|
+
impact: LOW
|
|
2284
|
+
confidence: MEDIUM
|
|
2285
|
+
technology:
|
|
2286
|
+
- go
|
|
2287
|
+
patterns:
|
|
2288
|
+
- pattern-either:
|
|
2289
|
+
- pattern: sha1.Sum(...)
|
|
2290
|
+
- pattern: sha1.New()
|
|
2291
|
+
- id: narvy.go.crypto.math-random-used.math-random-used
|
|
2292
|
+
message: '`math/rand` used to generate a value. `math/rand`''s default source is not cryptographically secure and is predictable
|
|
2293
|
+
once seeded - using it for anything security-sensitive (tokens, session IDs, password reset codes, nonces, keys) lets
|
|
2294
|
+
an attacker predict or brute-force the value (CWE-338). Use `crypto/rand` for anything security-sensitive; this broad
|
|
2295
|
+
detector deliberately also fires on non-sensitive uses (jitter, load-balancing, retry backoff), which you can treat
|
|
2296
|
+
as advisory. Covers both the classic `math/rand` API
|
|
2297
|
+
(`rand.Intn`/`.Int63`/`.Int31`/`.Float64`/`.Int`) and `math/rand/v2`''s generic form (`rand.N`/`.IntN`/`.Int32N`/ `.Int64N`/`.Uint32N`/`.Uint64N`/...)
|
|
2298
|
+
via a `$FUNC` wildcard instead of a fixed identifier list, and matches through an import alias (`mathrand "math/rand"`
|
|
2299
|
+
then `mathrand.Int63()`) by binding the alias from the import statement itself rather than assuming the package is always
|
|
2300
|
+
referenced as literal `rand`.'
|
|
2301
|
+
severity: INFO
|
|
2302
|
+
languages:
|
|
2303
|
+
- go
|
|
2304
|
+
metadata:
|
|
2305
|
+
category: security
|
|
2306
|
+
cwe:
|
|
2307
|
+
- 'CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)'
|
|
2308
|
+
owasp:
|
|
2309
|
+
- A02:2021 - Cryptographic Failures
|
|
2310
|
+
subcategory:
|
|
2311
|
+
- audit
|
|
2312
|
+
likelihood: LOW
|
|
2313
|
+
impact: MEDIUM
|
|
2314
|
+
confidence: LOW
|
|
2315
|
+
technology:
|
|
2316
|
+
- go
|
|
2317
|
+
patterns:
|
|
2318
|
+
- pattern-either:
|
|
2319
|
+
- patterns:
|
|
2320
|
+
- pattern: rand.$FUNC(...)
|
|
2321
|
+
- pattern-not-inside: 'import "crypto/rand"
|
|
2322
|
+
|
|
2323
|
+
...
|
|
2324
|
+
|
|
2325
|
+
'
|
|
2326
|
+
- patterns:
|
|
2327
|
+
- pattern: $ALIAS.$FUNC(...)
|
|
2328
|
+
- pattern-inside: 'import $ALIAS "$MODPATH"
|
|
2329
|
+
|
|
2330
|
+
...
|
|
2331
|
+
|
|
2332
|
+
'
|
|
2333
|
+
- metavariable-regex:
|
|
2334
|
+
metavariable: $MODPATH
|
|
2335
|
+
regex: ^math/rand(/v[0-9]+)?$
|
|
2336
|
+
- id: narvy.go.crypto.rc4-cipher-constructed.rc4-cipher-constructed
|
|
2337
|
+
message: '`rc4.NewCipher()` used. RC4 has known keystream biases that break confidentiality in practice and is disabled
|
|
2338
|
+
by default in modern TLS stacks for that reason (CWE-327). Use AES-GCM or ChaCha20-Poly1305.'
|
|
2339
|
+
severity: ERROR
|
|
2340
|
+
languages:
|
|
2341
|
+
- go
|
|
2342
|
+
metadata:
|
|
2343
|
+
category: security
|
|
2344
|
+
cwe:
|
|
2345
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
2346
|
+
owasp:
|
|
2347
|
+
- A02:2021 - Cryptographic Failures
|
|
2348
|
+
subcategory:
|
|
2349
|
+
- vuln
|
|
2350
|
+
likelihood: LOW
|
|
2351
|
+
impact: HIGH
|
|
2352
|
+
confidence: HIGH
|
|
2353
|
+
technology:
|
|
2354
|
+
- go
|
|
2355
|
+
pattern: rc4.NewCipher(...)
|
|
2356
|
+
- id: narvy.go.crypto.rsa-key-undersized-modulus.rsa-key-undersized-modulus
|
|
2357
|
+
message: '`rsa.GenerateKey()` called with a key size below 2048 bits. RSA keys under 2048 bits are within reach of modern
|
|
2358
|
+
factoring attacks (CWE-326). Generate at least a 2048-bit key (3072+ recommended for new systems).'
|
|
2359
|
+
severity: WARNING
|
|
2360
|
+
languages:
|
|
2361
|
+
- go
|
|
2362
|
+
metadata:
|
|
2363
|
+
category: security
|
|
2364
|
+
cwe:
|
|
2365
|
+
- 'CWE-326: Inadequate Encryption Strength'
|
|
2366
|
+
owasp:
|
|
2367
|
+
- A02:2021 - Cryptographic Failures
|
|
2368
|
+
subcategory:
|
|
2369
|
+
- vuln
|
|
2370
|
+
likelihood: LOW
|
|
2371
|
+
impact: HIGH
|
|
2372
|
+
confidence: HIGH
|
|
2373
|
+
technology:
|
|
2374
|
+
- go
|
|
2375
|
+
patterns:
|
|
2376
|
+
- pattern: rsa.GenerateKey($RAND, $BITS)
|
|
2377
|
+
- metavariable-comparison:
|
|
2378
|
+
metavariable: $BITS
|
|
2379
|
+
comparison: $BITS < 2048
|
|
2380
|
+
- id: narvy.go.crypto.aes-cbc-static-iv.aes-cbc-static-iv
|
|
2381
|
+
message: '`cipher.NewCBCEncrypter()` called with an IV that is a hardcoded literal byte-array instead of a freshly generated
|
|
2382
|
+
random value. A reused/predictable IV breaks CBC''s semantic-security guarantee and leaks information about the plaintext
|
|
2383
|
+
across messages (CWE-329). Draw the IV from `crypto/rand` for every encryption.'
|
|
2384
|
+
severity: ERROR
|
|
2385
|
+
languages:
|
|
2386
|
+
- go
|
|
2387
|
+
metadata:
|
|
2388
|
+
category: security
|
|
2389
|
+
cwe:
|
|
2390
|
+
- 'CWE-329: Generation of Predictable IV with CBC Mode'
|
|
2391
|
+
owasp:
|
|
2392
|
+
- A02:2021 - Cryptographic Failures
|
|
2393
|
+
subcategory:
|
|
2394
|
+
- vuln
|
|
2395
|
+
likelihood: MEDIUM
|
|
2396
|
+
impact: HIGH
|
|
2397
|
+
confidence: MEDIUM
|
|
2398
|
+
technology:
|
|
2399
|
+
- go
|
|
2400
|
+
patterns:
|
|
2401
|
+
- pattern: cipher.NewCBCEncrypter($BLOCK, $IV)
|
|
2402
|
+
- pattern-inside: 'var $IV = [...]byte{...}
|
|
2403
|
+
|
|
2404
|
+
...
|
|
2405
|
+
|
|
2406
|
+
'
|
|
2407
|
+
- id: narvy.go.crypto.sha224-checksum-used.sha224-checksum-used
|
|
2408
|
+
message: '`sha256.Sum224()` / `sha256.New224()` used. SHA-224 is not broken, but it is a truncated-output variant with no
|
|
2409
|
+
benefit over SHA-256 on 64-bit hardware and is easy to confuse with the weaker SHA-1/MD5 family in review (CWE-327 advisory,
|
|
2410
|
+
not exploitable by itself). Use SHA-256 unless you have a specific length-constrained wire-format requirement.'
|
|
2411
|
+
severity: INFO
|
|
2412
|
+
languages:
|
|
2413
|
+
- go
|
|
2414
|
+
metadata:
|
|
2415
|
+
category: security
|
|
2416
|
+
cwe:
|
|
2417
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
2418
|
+
owasp:
|
|
2419
|
+
- A02:2021 - Cryptographic Failures
|
|
2420
|
+
subcategory:
|
|
2421
|
+
- audit
|
|
2422
|
+
likelihood: LOW
|
|
2423
|
+
impact: LOW
|
|
2424
|
+
confidence: LOW
|
|
2425
|
+
technology:
|
|
2426
|
+
- go
|
|
2427
|
+
patterns:
|
|
2428
|
+
- pattern-either:
|
|
2429
|
+
- pattern: sha256.Sum224(...)
|
|
2430
|
+
- pattern: sha256.New224()
|
|
2431
|
+
- id: narvy-go-xss-template-html-cast
|
|
2432
|
+
patterns:
|
|
2433
|
+
- pattern-either:
|
|
2434
|
+
- pattern: template.HTML($X)
|
|
2435
|
+
- pattern: template.JS($X)
|
|
2436
|
+
- pattern: template.URL($X)
|
|
2437
|
+
- pattern: template.HTMLAttr($X)
|
|
2438
|
+
- pattern: template.CSS($X)
|
|
2439
|
+
- pattern-not: template.HTML("...")
|
|
2440
|
+
- pattern-not: template.JS("...")
|
|
2441
|
+
- pattern-not: template.URL("...")
|
|
2442
|
+
- pattern-not: template.HTMLAttr("...")
|
|
2443
|
+
- pattern-not: template.CSS("...")
|
|
2444
|
+
# Excludes provably-safe sources: just-built strings.Builder/bytes.Buffer `.String()` and escaper output (html.EscapeString / template.HTMLEscapeString / url.QueryEscape).
|
|
2445
|
+
- pattern-not: template.HTML($SB.String())
|
|
2446
|
+
- pattern-not: template.JS($SB.String())
|
|
2447
|
+
- pattern-not: template.URL($SB.String())
|
|
2448
|
+
- pattern-not: template.HTMLAttr($SB.String())
|
|
2449
|
+
- pattern-not: template.CSS($SB.String())
|
|
2450
|
+
- pattern-not: template.HTML(html.EscapeString(...))
|
|
2451
|
+
- pattern-not: template.HTML(template.HTMLEscapeString(...))
|
|
2452
|
+
- pattern-not: template.HTMLAttr(html.EscapeString(...))
|
|
2453
|
+
- pattern-not: template.HTMLAttr(template.HTMLEscapeString(...))
|
|
2454
|
+
- pattern-not: template.JS(template.JSEscapeString(...))
|
|
2455
|
+
- pattern-not: template.URL(url.QueryEscape(...))
|
|
2456
|
+
- pattern-not: template.URL(html.EscapeString(...))
|
|
2457
|
+
message: 'Non-literal value cast to `template.HTML` (or `JS` / `URL` / `HTMLAttr` / `CSS`), which suppresses Go''s
|
|
2458
|
+
auto-escaping in `html/template`. This is a HEURISTIC audit signal, not a proven exploit: without data-flow proof
|
|
2459
|
+
we cannot tell a safe internal string from attacker input. IF the value is user-controlled it is stored/reflected
|
|
2460
|
+
XSS (CWE-79) - sanitise with `bluemonday` (or equivalent) before casting, or drop the cast and let `html/template`
|
|
2461
|
+
escape. The taint-proven case is reported separately at CRITICAL by narvy-go-xss-template-html-request-taint.'
|
|
2462
|
+
metadata:
|
|
2463
|
+
cwe:
|
|
2464
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2465
|
+
owasp:
|
|
2466
|
+
- A03:2021 - Injection
|
|
2467
|
+
category: security
|
|
2468
|
+
technology:
|
|
2469
|
+
- go
|
|
2470
|
+
- html/template
|
|
2471
|
+
confidence: LOW
|
|
2472
|
+
subcategory:
|
|
2473
|
+
- audit
|
|
2474
|
+
likelihood: LOW
|
|
2475
|
+
impact: HIGH
|
|
2476
|
+
severity: INFO
|
|
2477
|
+
languages:
|
|
2478
|
+
- go
|
|
2479
|
+
- id: narvy-go-xss-responsewriter-bytes
|
|
2480
|
+
patterns:
|
|
2481
|
+
- pattern-either:
|
|
2482
|
+
- pattern: $W.Write([]byte($X))
|
|
2483
|
+
- pattern-not: $W.Write([]byte("..."))
|
|
2484
|
+
- pattern-either:
|
|
2485
|
+
- pattern-inside: "func $FN($W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
2486
|
+
- pattern-inside: "func ($RECV $T) $FN($W http.ResponseWriter, ...) {\n ...\n}\n"
|
|
2487
|
+
message: 'XSS risk: `ResponseWriter.Write([]byte(x))` with a non-literal value `x`. The response body is written verbatim
|
|
2488
|
+
to the browser without escaping. If `x` originates from a request parameter this is reflected XSS. Use `html/template`
|
|
2489
|
+
to render dynamic content.'
|
|
2490
|
+
metadata:
|
|
2491
|
+
cwe:
|
|
2492
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2493
|
+
owasp:
|
|
2494
|
+
- A03:2021 - Injection
|
|
2495
|
+
category: security
|
|
2496
|
+
technology:
|
|
2497
|
+
- go
|
|
2498
|
+
confidence: MEDIUM
|
|
2499
|
+
subcategory:
|
|
2500
|
+
- audit
|
|
2501
|
+
likelihood: MEDIUM
|
|
2502
|
+
impact: MEDIUM
|
|
2503
|
+
severity: WARNING
|
|
2504
|
+
languages:
|
|
2505
|
+
- go
|
|
2506
|
+
- id: narvy.go.xss.no-direct-write-to-responsewriter.no-direct-write-to-responsewriter
|
|
2507
|
+
message: '`w.Write(...)` writes raw bytes to the `http.ResponseWriter`. This is safe for JSON/binary responses and is
|
|
2508
|
+
idiomatic Go; it is only XSS when the bytes carry attacker-controlled data into an HTML response without escaping (CWE-79).
|
|
2509
|
+
We cannot prove taint here, so this is a review pointer, not a confirmed finding: if the value is request-derived and the
|
|
2510
|
+
response is HTML, render through `html/template` (auto-escapes) instead. Ignore for JSON/`application/json` handlers.'
|
|
2511
|
+
severity: INFO
|
|
2512
|
+
languages:
|
|
2513
|
+
- go
|
|
2514
|
+
metadata:
|
|
2515
|
+
category: security
|
|
2516
|
+
cwe:
|
|
2517
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2518
|
+
owasp:
|
|
2519
|
+
- A03:2021 - Injection
|
|
2520
|
+
subcategory:
|
|
2521
|
+
- vuln
|
|
2522
|
+
likelihood: MEDIUM
|
|
2523
|
+
impact: MEDIUM
|
|
2524
|
+
confidence: MEDIUM
|
|
2525
|
+
technology:
|
|
2526
|
+
- go
|
|
2527
|
+
patterns:
|
|
2528
|
+
- pattern-either:
|
|
2529
|
+
- pattern: $W.Write([]byte($X))
|
|
2530
|
+
- pattern: $W.Write($X)
|
|
2531
|
+
- pattern-not: $W.Write([]byte("..."))
|
|
2532
|
+
- pattern-either:
|
|
2533
|
+
- pattern-inside: 'func $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2534
|
+
|
|
2535
|
+
'
|
|
2536
|
+
- pattern-inside: 'func ($RECV) $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2537
|
+
|
|
2538
|
+
'
|
|
2539
|
+
- id: narvy.go.xss.no-fprintf-to-responsewriter.no-fprintf-to-responsewriter
|
|
2540
|
+
message: '`fmt.Fprintf(w, ...)` formats a tainted value directly into the HTTP response body. `Fprintf` does not HTML-escape
|
|
2541
|
+
its arguments, so a request-derived value reaching the format arguments is reflected XSS (CWE-79). Use `html/template`
|
|
2542
|
+
for anything written to an HTML response.'
|
|
2543
|
+
severity: WARNING
|
|
2544
|
+
languages:
|
|
2545
|
+
- go
|
|
2546
|
+
metadata:
|
|
2547
|
+
category: security
|
|
2548
|
+
cwe:
|
|
2549
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2550
|
+
owasp:
|
|
2551
|
+
- A03:2021 - Injection
|
|
2552
|
+
subcategory:
|
|
2553
|
+
- vuln
|
|
2554
|
+
likelihood: MEDIUM
|
|
2555
|
+
impact: MEDIUM
|
|
2556
|
+
confidence: MEDIUM
|
|
2557
|
+
technology:
|
|
2558
|
+
- go
|
|
2559
|
+
patterns:
|
|
2560
|
+
- pattern: fmt.Fprintf($W, "...", ...)
|
|
2561
|
+
- pattern-either:
|
|
2562
|
+
- pattern-inside: 'func $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2563
|
+
|
|
2564
|
+
'
|
|
2565
|
+
- pattern-inside: 'func ($RECV) $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2566
|
+
|
|
2567
|
+
'
|
|
2568
|
+
- id: narvy.go.xss.no-io-writestring-to-responsewriter.no-io-writestring-to-responsewriter
|
|
2569
|
+
message: '`io.WriteString(w, ...)` writes a tainted string directly to the HTTP response body with no HTML escaping - reflected
|
|
2570
|
+
XSS if the string contains request-derived data (CWE-79). Use `html/template` instead.'
|
|
2571
|
+
severity: WARNING
|
|
2572
|
+
languages:
|
|
2573
|
+
- go
|
|
2574
|
+
metadata:
|
|
2575
|
+
category: security
|
|
2576
|
+
cwe:
|
|
2577
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2578
|
+
owasp:
|
|
2579
|
+
- A03:2021 - Injection
|
|
2580
|
+
subcategory:
|
|
2581
|
+
- vuln
|
|
2582
|
+
likelihood: MEDIUM
|
|
2583
|
+
impact: MEDIUM
|
|
2584
|
+
confidence: MEDIUM
|
|
2585
|
+
technology:
|
|
2586
|
+
- go
|
|
2587
|
+
patterns:
|
|
2588
|
+
- pattern: io.WriteString($W, $X)
|
|
2589
|
+
- pattern-either:
|
|
2590
|
+
- pattern-inside: 'func $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2591
|
+
|
|
2592
|
+
'
|
|
2593
|
+
- pattern-inside: 'func ($RECV) $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2594
|
+
|
|
2595
|
+
'
|
|
2596
|
+
- id: narvy.go.xss.no-printf-in-responsewriter.no-printf-in-responsewriter
|
|
2597
|
+
message: A formatted/concatenated string is passed to a `ResponseWriter` write call. If any operand is request-derived,
|
|
2598
|
+
this is a reflected-XSS sink (CWE-79) - the response body is not passed through an HTML escaper. Render through `html/template`.
|
|
2599
|
+
severity: WARNING
|
|
2600
|
+
languages:
|
|
2601
|
+
- go
|
|
2602
|
+
metadata:
|
|
2603
|
+
category: security
|
|
2604
|
+
cwe:
|
|
2605
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2606
|
+
owasp:
|
|
2607
|
+
- A03:2021 - Injection
|
|
2608
|
+
subcategory:
|
|
2609
|
+
- vuln
|
|
2610
|
+
likelihood: LOW
|
|
2611
|
+
impact: MEDIUM
|
|
2612
|
+
confidence: MEDIUM
|
|
2613
|
+
technology:
|
|
2614
|
+
- go
|
|
2615
|
+
patterns:
|
|
2616
|
+
- pattern: $W.Write([]byte(fmt.Sprintf("...", ...)))
|
|
2617
|
+
- pattern-either:
|
|
2618
|
+
- pattern-inside: 'func $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2619
|
+
|
|
2620
|
+
'
|
|
2621
|
+
- pattern-inside: 'func ($RECV) $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2622
|
+
|
|
2623
|
+
'
|
|
2624
|
+
- id: narvy.go.xss.wip-xss-using-responsewriter-and-printf.wip-xss-using-responsewriter-and-printf
|
|
2625
|
+
message: '`fmt.Fprint(w, ...)` / `fmt.Fprintln(w, ...)` writes concatenated, request-derived data straight to the response
|
|
2626
|
+
body with no escaping - reflected XSS (CWE-79). Render through `html/template` instead of hand-formatting the body.'
|
|
2627
|
+
severity: WARNING
|
|
2628
|
+
languages:
|
|
2629
|
+
- go
|
|
2630
|
+
metadata:
|
|
2631
|
+
category: security
|
|
2632
|
+
cwe:
|
|
2633
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2634
|
+
owasp:
|
|
2635
|
+
- A03:2021 - Injection
|
|
2636
|
+
subcategory:
|
|
2637
|
+
- vuln
|
|
2638
|
+
likelihood: LOW
|
|
2639
|
+
impact: MEDIUM
|
|
2640
|
+
confidence: MEDIUM
|
|
2641
|
+
technology:
|
|
2642
|
+
- go
|
|
2643
|
+
patterns:
|
|
2644
|
+
- pattern-either:
|
|
2645
|
+
- pattern: fmt.Fprint($W, ...)
|
|
2646
|
+
- pattern: fmt.Fprintln($W, ...)
|
|
2647
|
+
- pattern-not: fmt.Fprint($W, "...")
|
|
2648
|
+
- pattern-not: fmt.Fprintln($W, "...")
|
|
2649
|
+
- pattern-either:
|
|
2650
|
+
- pattern-inside: 'func $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2651
|
+
|
|
2652
|
+
'
|
|
2653
|
+
- pattern-inside: 'func ($RECV) $FUNC(..., $W http.ResponseWriter, ...) { ... }
|
|
2654
|
+
|
|
2655
|
+
'
|
|
2656
|
+
- id: narvy.go.xss.text-template-attr-context-unescaped.text-template-attr-context-unescaped
|
|
2657
|
+
message: A `text/template` (not `html/template`) template renders a value inside an HTML attribute. `text/template` performs
|
|
2658
|
+
no contextual escaping, so a request-derived value here can break out of the attribute and inject markup/script - XSS
|
|
2659
|
+
(CWE-79). Switch the template engine to `html/template`.
|
|
2660
|
+
severity: WARNING
|
|
2661
|
+
languages:
|
|
2662
|
+
- go
|
|
2663
|
+
metadata:
|
|
2664
|
+
category: security
|
|
2665
|
+
cwe:
|
|
2666
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2667
|
+
owasp:
|
|
2668
|
+
- A03:2021 - Injection
|
|
2669
|
+
subcategory:
|
|
2670
|
+
- vuln
|
|
2671
|
+
likelihood: LOW
|
|
2672
|
+
impact: MEDIUM
|
|
2673
|
+
confidence: LOW
|
|
2674
|
+
technology:
|
|
2675
|
+
- go
|
|
2676
|
+
patterns:
|
|
2677
|
+
- pattern: text/template.Must(text/template.New($NAME).Parse($SRC))
|
|
2678
|
+
- pattern-not: text/template.Must(text/template.New($NAME).Parse("..."))
|
|
2679
|
+
- id: narvy.go.xss.href-src-concat-unescaped.href-src-concat-unescaped
|
|
2680
|
+
message: A request-derived value is concatenated directly into an `href`/`src` attribute string that is then written to
|
|
2681
|
+
the response without going through `html/template`'s URL-context escaping. A `javascript:` URL or quote-breakout here
|
|
2682
|
+
is XSS (CWE-79). Use `html/template`, which escapes URL attribute context correctly.
|
|
2683
|
+
severity: WARNING
|
|
2684
|
+
languages:
|
|
2685
|
+
- go
|
|
2686
|
+
metadata:
|
|
2687
|
+
category: security
|
|
2688
|
+
cwe:
|
|
2689
|
+
- 'CWE-79: Improper Neutralization of Input During Web Page Generation (''Cross-site Scripting'')'
|
|
2690
|
+
owasp:
|
|
2691
|
+
- A03:2021 - Injection
|
|
2692
|
+
subcategory:
|
|
2693
|
+
- vuln
|
|
2694
|
+
likelihood: LOW
|
|
2695
|
+
impact: MEDIUM
|
|
2696
|
+
confidence: LOW
|
|
2697
|
+
technology:
|
|
2698
|
+
- go
|
|
2699
|
+
patterns:
|
|
2700
|
+
- pattern-either:
|
|
2701
|
+
- pattern: fmt.Sprintf("...href=\"%s\"...", $X)
|
|
2702
|
+
- pattern: fmt.Sprintf("...src=\"%s\"...", $X)
|
|
2703
|
+
- pattern: '"<a href=\"" + $X + "\">"'
|
|
2704
|
+
- id: narvy.go.deserialization.tar-entry-unbounded-copy.tar-entry-unbounded-copy
|
|
2705
|
+
message: A `tar.Reader` entry is copied out with `io.Copy()` and no size limit anywhere in the copy path. `header.Size`
|
|
2706
|
+
from the tar header is attacker-controlled and is not enforced by `tar.Reader.Read()` in any way - a crafted tar stream
|
|
2707
|
+
can present a small on-disk archive that unpacks to gigabytes on this entry alone, exhausting disk/memory (decompression
|
|
2708
|
+
bomb, CWE-409). Cap the copy with `io.CopyN($DST, tarReader, maxEntrySize)` or wrap the destination/source in `io.LimitReader`
|
|
2709
|
+
sized off a fixed maximum before copying.
|
|
2710
|
+
severity: WARNING
|
|
2711
|
+
languages:
|
|
2712
|
+
- go
|
|
2713
|
+
metadata:
|
|
2714
|
+
category: security
|
|
2715
|
+
cwe:
|
|
2716
|
+
- 'CWE-409: Improper Handling of Highly Compressed Data (Data Amplification)'
|
|
2717
|
+
owasp:
|
|
2718
|
+
- A05:2021 - Security Misconfiguration
|
|
2719
|
+
subcategory:
|
|
2720
|
+
- vuln
|
|
2721
|
+
likelihood: LOW
|
|
2722
|
+
impact: MEDIUM
|
|
2723
|
+
confidence: LOW
|
|
2724
|
+
technology:
|
|
2725
|
+
- go
|
|
2726
|
+
patterns:
|
|
2727
|
+
- pattern: '$TR := tar.NewReader(...)
|
|
2728
|
+
|
|
2729
|
+
...
|
|
2730
|
+
|
|
2731
|
+
io.Copy($DST, $TR)
|
|
2732
|
+
|
|
2733
|
+
'
|
|
2734
|
+
- pattern-not: '$TR := tar.NewReader(...)
|
|
2735
|
+
|
|
2736
|
+
...
|
|
2737
|
+
|
|
2738
|
+
io.Copy($DST, io.LimitReader($TR, ...))
|
|
2739
|
+
|
|
2740
|
+
'
|
|
2741
|
+
- pattern-not: '$TR := tar.NewReader(...)
|
|
2742
|
+
|
|
2743
|
+
...
|
|
2744
|
+
|
|
2745
|
+
io.CopyN($DST, $TR, ...)
|
|
2746
|
+
|
|
2747
|
+
'
|
|
2748
|
+
- id: narvy.go.deserialization.zip-entry-unbounded-copy.zip-entry-unbounded-copy
|
|
2749
|
+
message: A `*zip.File` entry is opened and its content copied out with `io.Copy()` with no size limit enforced during the
|
|
2750
|
+
copy itself. The entry's declared `UncompressedSize64` in the zip central directory is just a header field an attacker
|
|
2751
|
+
fully controls - it is not checked by `zip.File.Open()`/`Read()`, so even code that pre-checks the declared size against
|
|
2752
|
+
free disk space is still exposed to a stream that decompresses to far more bytes than it claims (decompression bomb, CWE-409).
|
|
2753
|
+
Cap the copy with `io.CopyN()` or wrap the entry reader in `io.LimitReader(entryReader, maxEntrySize)` before copying,
|
|
2754
|
+
and treat a truncated/limited read as an error, not a success.
|
|
2755
|
+
severity: WARNING
|
|
2756
|
+
languages:
|
|
2757
|
+
- go
|
|
2758
|
+
metadata:
|
|
2759
|
+
category: security
|
|
2760
|
+
cwe:
|
|
2761
|
+
- 'CWE-409: Improper Handling of Highly Compressed Data (Data Amplification)'
|
|
2762
|
+
owasp:
|
|
2763
|
+
- A05:2021 - Security Misconfiguration
|
|
2764
|
+
subcategory:
|
|
2765
|
+
- vuln
|
|
2766
|
+
likelihood: LOW
|
|
2767
|
+
impact: MEDIUM
|
|
2768
|
+
confidence: LOW
|
|
2769
|
+
technology:
|
|
2770
|
+
- go
|
|
2771
|
+
patterns:
|
|
2772
|
+
- pattern-either:
|
|
2773
|
+
- patterns:
|
|
2774
|
+
- pattern-inside: "for $_, $ZF := range $ZR.File {\n ...\n}\n"
|
|
2775
|
+
- pattern: '$RC, $ERR := $ZF.Open()
|
|
2776
|
+
|
|
2777
|
+
...
|
|
2778
|
+
|
|
2779
|
+
io.Copy($DST, $RC)
|
|
2780
|
+
|
|
2781
|
+
'
|
|
2782
|
+
- pattern-not: '$RC, $ERR := $ZF.Open()
|
|
2783
|
+
|
|
2784
|
+
...
|
|
2785
|
+
|
|
2786
|
+
io.Copy($DST, io.LimitReader($RC, ...))
|
|
2787
|
+
|
|
2788
|
+
'
|
|
2789
|
+
- pattern-not: '$RC, $ERR := $ZF.Open()
|
|
2790
|
+
|
|
2791
|
+
...
|
|
2792
|
+
|
|
2793
|
+
io.CopyN($DST, $RC, ...)
|
|
2794
|
+
|
|
2795
|
+
'
|
|
2796
|
+
- patterns:
|
|
2797
|
+
- pattern: "func($P *zip.File) $RET {\n ...\n $RC, $ERR := $P.Open()\n ...\n io.Copy($DST, $RC)\n ...\n}\n"
|
|
2798
|
+
- pattern-not: "func($P *zip.File) $RET {\n ...\n $RC, $ERR := $P.Open()\n ...\n io.Copy($DST, io.LimitReader($RC,\
|
|
2799
|
+
\ ...))\n ...\n}\n"
|
|
2800
|
+
- pattern-not: "func($P *zip.File) $RET {\n ...\n $RC, $ERR := $P.Open()\n ...\n io.CopyN($DST, $RC, ...)\n ...\n\
|
|
2801
|
+
}\n"
|
|
2802
|
+
- id: narvy.go.deserialization.decompression-reader-unbounded-read.decompression-reader-unbounded-read
|
|
2803
|
+
message: '`gzip.NewReader()` / `zlib.NewReader()` output is copied with `io.Copy()` and no size limit. A malicious small
|
|
2804
|
+
compressed payload can expand to gigabytes in memory/disk, exhausting resources - a decompression-bomb DoS (CWE-409).
|
|
2805
|
+
Wrap the reader with `io.LimitReader(r, maxDecompressedSize)` before copying.'
|
|
2806
|
+
severity: WARNING
|
|
2807
|
+
languages:
|
|
2808
|
+
- go
|
|
2809
|
+
metadata:
|
|
2810
|
+
category: security
|
|
2811
|
+
cwe:
|
|
2812
|
+
- 'CWE-409: Improper Handling of Highly Compressed Data (Data Amplification)'
|
|
2813
|
+
owasp:
|
|
2814
|
+
- A05:2021 - Security Misconfiguration
|
|
2815
|
+
subcategory:
|
|
2816
|
+
- vuln
|
|
2817
|
+
likelihood: LOW
|
|
2818
|
+
impact: MEDIUM
|
|
2819
|
+
confidence: LOW
|
|
2820
|
+
technology:
|
|
2821
|
+
- go
|
|
2822
|
+
patterns:
|
|
2823
|
+
- pattern-either:
|
|
2824
|
+
- pattern: '$GZ, $ERR := gzip.NewReader($R)
|
|
2825
|
+
|
|
2826
|
+
...
|
|
2827
|
+
|
|
2828
|
+
io.Copy($DST, $GZ)
|
|
2829
|
+
|
|
2830
|
+
'
|
|
2831
|
+
- pattern: '$ZR, $ERR := zlib.NewReader($R)
|
|
2832
|
+
|
|
2833
|
+
...
|
|
2834
|
+
|
|
2835
|
+
io.Copy($DST, $ZR)
|
|
2836
|
+
|
|
2837
|
+
'
|