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
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
# Kotlin security rules, authored by Narvy.
|
|
2
|
+
# String-template SQL and command injection, Ktor CORS, weak crypto.
|
|
3
|
+
|
|
4
|
+
rules:
|
|
5
|
+
- id: narvy.kotlin.auth.ldap-unauthenticated-bind
|
|
6
|
+
message: An LDAP `InitialDirContext` is opened with `SECURITY_AUTHENTICATION` set to `"none"`, i.e. an anonymous bind. Anonymous
|
|
7
|
+
binds let any caller run LDAP queries against the directory without proving identity, which typically over-exposes directory
|
|
8
|
+
contents and defeats access controls built on top of the bind (CWE-287). Bind with real credentials (simple or SASL) unless
|
|
9
|
+
anonymous read access to this directory is a deliberate, documented design choice.
|
|
10
|
+
severity: WARNING
|
|
11
|
+
languages:
|
|
12
|
+
- kotlin
|
|
13
|
+
metadata:
|
|
14
|
+
category: security
|
|
15
|
+
cwe:
|
|
16
|
+
- 'CWE-287: Improper Authentication'
|
|
17
|
+
owasp:
|
|
18
|
+
- A07:2021 - Identification and Authentication Failures
|
|
19
|
+
subcategory:
|
|
20
|
+
- vuln
|
|
21
|
+
likelihood: LOW
|
|
22
|
+
impact: MEDIUM
|
|
23
|
+
confidence: MEDIUM
|
|
24
|
+
technology:
|
|
25
|
+
- kotlin
|
|
26
|
+
patterns:
|
|
27
|
+
- pattern: '$ENV.put(Context.SECURITY_AUTHENTICATION, "none")
|
|
28
|
+
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
$DCTX = InitialDirContext($ENV, ...)
|
|
32
|
+
|
|
33
|
+
'
|
|
34
|
+
- id: narvy.kotlin.secrets.gradle-fallback-password.gradle-fallback-password
|
|
35
|
+
message: 'A Gradle Kotlin DSL build script reads a signing/repository password from the environment with a hardcoded literal
|
|
36
|
+
as the Elvis-operator fallback (`env["..."] ?: "literal"`). Build scripts are committed to source control, so this literal
|
|
37
|
+
ships to every clone of the repository; if the real environment variable is ever unset, the build silently signs or authenticates
|
|
38
|
+
with the leaked fallback (CWE-798). Fail the build instead of falling back: `env["SIGNING_PASSWORD"] ?: error("SIGNING_PASSWORD
|
|
39
|
+
not set")`.'
|
|
40
|
+
severity: WARNING
|
|
41
|
+
languages:
|
|
42
|
+
- kotlin
|
|
43
|
+
metadata:
|
|
44
|
+
category: security
|
|
45
|
+
cwe:
|
|
46
|
+
- 'CWE-798: Use of Hard-coded Credentials'
|
|
47
|
+
owasp:
|
|
48
|
+
- A07:2021 - Identification and Authentication Failures
|
|
49
|
+
subcategory:
|
|
50
|
+
- vuln
|
|
51
|
+
likelihood: LOW
|
|
52
|
+
impact: HIGH
|
|
53
|
+
confidence: MEDIUM
|
|
54
|
+
technology:
|
|
55
|
+
- kotlin
|
|
56
|
+
options:
|
|
57
|
+
symbolic_propagation: true
|
|
58
|
+
patterns:
|
|
59
|
+
- pattern: '$PASS = System.getenv($NAME) ?: $VALUE'
|
|
60
|
+
- metavariable-regex:
|
|
61
|
+
metavariable: $PASS
|
|
62
|
+
regex: (?i).*(password|passwd|secret|signingkey|apikey|token).*
|
|
63
|
+
- metavariable-regex:
|
|
64
|
+
metavariable: $VALUE
|
|
65
|
+
regex: ^"[A-Za-z0-9/+=_-]{4,}"$
|
|
66
|
+
paths:
|
|
67
|
+
include:
|
|
68
|
+
- '*build.gradle.kts'
|
|
69
|
+
- '*settings.gradle.kts'
|
|
70
|
+
- id: narvy.kotlin.auth.csrf-disabled.csrf-disabled
|
|
71
|
+
message: Spring Security's CSRF protection is explicitly disabled (`http.csrf { it.disable() }`). Without CSRF tokens, any
|
|
72
|
+
authenticated session can be driven by a malicious page to perform state-changing requests the victim never intended (CWE-352).
|
|
73
|
+
Disable CSRF only for endpoints that are genuinely stateless/token-authenticated (pure REST APIs using bearer tokens,
|
|
74
|
+
not cookies), and scope the exemption with `ignoringRequestMatchers(...)` rather than disabling it globally.
|
|
75
|
+
severity: WARNING
|
|
76
|
+
languages:
|
|
77
|
+
- kotlin
|
|
78
|
+
metadata:
|
|
79
|
+
category: security
|
|
80
|
+
cwe:
|
|
81
|
+
- 'CWE-352: Cross-Site Request Forgery (CSRF)'
|
|
82
|
+
owasp:
|
|
83
|
+
- A01:2021 - Broken Access Control
|
|
84
|
+
subcategory:
|
|
85
|
+
- audit
|
|
86
|
+
likelihood: LOW
|
|
87
|
+
impact: MEDIUM
|
|
88
|
+
confidence: MEDIUM
|
|
89
|
+
technology:
|
|
90
|
+
- kotlin
|
|
91
|
+
- spring
|
|
92
|
+
patterns:
|
|
93
|
+
- pattern: $HTTP.csrf { it.disable() }
|
|
94
|
+
- id: narvy.kotlin.cmdi.command-string-template.command-string-template
|
|
95
|
+
message: '`Runtime.getRuntime().exec(...)` is called with a single command string built via Kotlin string-template interpolation
|
|
96
|
+
(`"ping -c 1 $host"`). The JVM tokenises that single-string form itself, so an interpolated value containing spaces or
|
|
97
|
+
shell metacharacters changes how many arguments the process actually receives - a command injection vector (CWE-78). Use
|
|
98
|
+
the `exec(Array<String>)` / `ProcessBuilder(listOf(...))` overload with each argument as a separate element instead of
|
|
99
|
+
building one interpolated string.'
|
|
100
|
+
severity: ERROR
|
|
101
|
+
languages:
|
|
102
|
+
- kotlin
|
|
103
|
+
metadata:
|
|
104
|
+
category: security
|
|
105
|
+
cwe:
|
|
106
|
+
- 'CWE-78: Improper Neutralization of Special Elements used in an OS Command (''OS Command Injection'')'
|
|
107
|
+
owasp:
|
|
108
|
+
- A03:2021 - Injection
|
|
109
|
+
subcategory:
|
|
110
|
+
- vuln
|
|
111
|
+
likelihood: HIGH
|
|
112
|
+
impact: HIGH
|
|
113
|
+
confidence: MEDIUM
|
|
114
|
+
technology:
|
|
115
|
+
- kotlin
|
|
116
|
+
patterns:
|
|
117
|
+
- pattern: Runtime.getRuntime().exec("...${$X}...")
|
|
118
|
+
- id: narvy.kotlin.cors.install-cors-anyhost.install-cors-anyhost
|
|
119
|
+
message: A Ktor `install(CORS)` block calls `anyHost()` while also allowing credentials (`allowCredentials = true`). Reflecting
|
|
120
|
+
every Origin while also permitting cookies/Authorization headers on cross-origin requests means any website can make authenticated
|
|
121
|
+
requests on behalf of a logged in user and read the response (CWE-942). Restrict allowed hosts with `allowHost("app.example.com",
|
|
122
|
+
schemes = listOf("https"))` when `allowCredentials` is enabled.
|
|
123
|
+
severity: ERROR
|
|
124
|
+
languages:
|
|
125
|
+
- kotlin
|
|
126
|
+
metadata:
|
|
127
|
+
category: security
|
|
128
|
+
cwe:
|
|
129
|
+
- 'CWE-942: Permissive Cross-domain Policy with Untrusted Domains'
|
|
130
|
+
owasp:
|
|
131
|
+
- A05:2021 - Security Misconfiguration
|
|
132
|
+
subcategory:
|
|
133
|
+
- vuln
|
|
134
|
+
likelihood: MEDIUM
|
|
135
|
+
impact: HIGH
|
|
136
|
+
confidence: MEDIUM
|
|
137
|
+
technology:
|
|
138
|
+
- kotlin
|
|
139
|
+
- ktor
|
|
140
|
+
patterns:
|
|
141
|
+
- pattern: "install(CORS) {\n ...\n anyHost()\n ...\n allowCredentials = true\n ...\n}\n"
|
|
142
|
+
- id: narvy.kotlin.crypto.use-of-md5.use-of-md5
|
|
143
|
+
message: MD5 is cryptographically broken; practical collisions have been demonstrated for over a decade. Do not use it for
|
|
144
|
+
signatures, integrity checks, password storage, or any other security control (CWE-327, CWE-328). Use SHA-256 or stronger
|
|
145
|
+
for integrity, and a memory-hard KDF (Argon2id, scrypt, bcrypt) for password hashing.
|
|
146
|
+
severity: WARNING
|
|
147
|
+
languages:
|
|
148
|
+
- kotlin
|
|
149
|
+
metadata:
|
|
150
|
+
category: security
|
|
151
|
+
cwe:
|
|
152
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
153
|
+
- 'CWE-328: Use of Weak Hash'
|
|
154
|
+
owasp:
|
|
155
|
+
- A02:2021 - Cryptographic Failures
|
|
156
|
+
subcategory:
|
|
157
|
+
- vuln
|
|
158
|
+
likelihood: MEDIUM
|
|
159
|
+
impact: MEDIUM
|
|
160
|
+
confidence: HIGH
|
|
161
|
+
technology:
|
|
162
|
+
- kotlin
|
|
163
|
+
patterns:
|
|
164
|
+
- pattern-either:
|
|
165
|
+
- pattern: MessageDigest.getInstance("MD5")
|
|
166
|
+
- pattern: java.security.MessageDigest.getInstance("MD5")
|
|
167
|
+
- pattern: DigestUtils.getMd5Digest()
|
|
168
|
+
- pattern: DigestUtils.md5Hex(...)
|
|
169
|
+
- id: narvy.kotlin.crypto.use-of-sha1.use-of-sha1
|
|
170
|
+
message: SHA-1 is deprecated for security purposes; chosen-prefix collisions are practical. Do not use it for signatures,
|
|
171
|
+
certificate fingerprints, or any security-relevant integrity check (CWE-327, CWE-328). Use SHA-256 or stronger.
|
|
172
|
+
severity: WARNING
|
|
173
|
+
languages:
|
|
174
|
+
- kotlin
|
|
175
|
+
metadata:
|
|
176
|
+
category: security
|
|
177
|
+
cwe:
|
|
178
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
179
|
+
- 'CWE-328: Use of Weak Hash'
|
|
180
|
+
owasp:
|
|
181
|
+
- A02:2021 - Cryptographic Failures
|
|
182
|
+
subcategory:
|
|
183
|
+
- vuln
|
|
184
|
+
likelihood: MEDIUM
|
|
185
|
+
impact: MEDIUM
|
|
186
|
+
confidence: HIGH
|
|
187
|
+
technology:
|
|
188
|
+
- kotlin
|
|
189
|
+
patterns:
|
|
190
|
+
- pattern-either:
|
|
191
|
+
- pattern: MessageDigest.getInstance("SHA-1")
|
|
192
|
+
- pattern: MessageDigest.getInstance("SHA1")
|
|
193
|
+
- pattern: java.security.MessageDigest.getInstance("SHA-1")
|
|
194
|
+
- pattern: DigestUtils.getSha1Digest()
|
|
195
|
+
- pattern: DigestUtils.sha1Hex(...)
|
|
196
|
+
- id: narvy.kotlin.crypto.ecb-cipher.ecb-cipher
|
|
197
|
+
message: A symmetric cipher is used in ECB mode (explicitly, or implicitly via a bare algorithm name such as `Cipher.getInstance("AES")`,
|
|
198
|
+
which most JCE providers default to `AES/ECB/PKCS5Padding`). ECB encrypts each block independently, so identical plaintext
|
|
199
|
+
blocks produce identical ciphertext blocks; patterns in the plaintext leak through unencrypted (CWE-327). Use `AES/GCM/NoPadding`
|
|
200
|
+
with a unique 12-byte nonce per encryption.
|
|
201
|
+
severity: WARNING
|
|
202
|
+
languages:
|
|
203
|
+
- kotlin
|
|
204
|
+
metadata:
|
|
205
|
+
category: security
|
|
206
|
+
cwe:
|
|
207
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
208
|
+
owasp:
|
|
209
|
+
- A02:2021 - Cryptographic Failures
|
|
210
|
+
subcategory:
|
|
211
|
+
- vuln
|
|
212
|
+
likelihood: MEDIUM
|
|
213
|
+
impact: HIGH
|
|
214
|
+
confidence: MEDIUM
|
|
215
|
+
technology:
|
|
216
|
+
- kotlin
|
|
217
|
+
patterns:
|
|
218
|
+
- pattern-either:
|
|
219
|
+
- pattern: Cipher.getInstance("AES/ECB/...")
|
|
220
|
+
- pattern: Cipher.getInstance("AES")
|
|
221
|
+
- id: narvy.kotlin.crypto.null-cipher.null-cipher
|
|
222
|
+
message: '`javax.crypto.NullCipher` performs no encryption at all; every byte passes through unchanged. It exists purely
|
|
223
|
+
for testing pipelines that expect a `Cipher` object. Shipping it in a production code path that handles real data is equivalent
|
|
224
|
+
to storing/transmitting plaintext (CWE-327).'
|
|
225
|
+
severity: ERROR
|
|
226
|
+
languages:
|
|
227
|
+
- kotlin
|
|
228
|
+
metadata:
|
|
229
|
+
category: security
|
|
230
|
+
cwe:
|
|
231
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
232
|
+
owasp:
|
|
233
|
+
- A02:2021 - Cryptographic Failures
|
|
234
|
+
subcategory:
|
|
235
|
+
- vuln
|
|
236
|
+
likelihood: LOW
|
|
237
|
+
impact: HIGH
|
|
238
|
+
confidence: HIGH
|
|
239
|
+
technology:
|
|
240
|
+
- kotlin
|
|
241
|
+
patterns:
|
|
242
|
+
- pattern-either:
|
|
243
|
+
- pattern: NullCipher()
|
|
244
|
+
- pattern: javax.crypto.NullCipher()
|
|
245
|
+
- id: narvy.kotlin.crypto.weak-symmetric-cipher.weak-symmetric-cipher
|
|
246
|
+
message: 'DES / 3DES(DESede) / RC2 / RC4 are broken or insufficient for modern use: DES''s 56-bit key is brute-forceable
|
|
247
|
+
in hours, RC2/RC4 have known keystream biases, and 3DES''s 64-bit block size is vulnerable to birthday attacks (Sweet32)
|
|
248
|
+
(CWE-327). Use AES-256 in GCM mode instead.'
|
|
249
|
+
severity: WARNING
|
|
250
|
+
languages:
|
|
251
|
+
- kotlin
|
|
252
|
+
metadata:
|
|
253
|
+
category: security
|
|
254
|
+
cwe:
|
|
255
|
+
- 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm'
|
|
256
|
+
- 'CWE-326: Inadequate Encryption Strength'
|
|
257
|
+
owasp:
|
|
258
|
+
- A02:2021 - Cryptographic Failures
|
|
259
|
+
subcategory:
|
|
260
|
+
- vuln
|
|
261
|
+
likelihood: LOW
|
|
262
|
+
impact: HIGH
|
|
263
|
+
confidence: HIGH
|
|
264
|
+
technology:
|
|
265
|
+
- kotlin
|
|
266
|
+
patterns:
|
|
267
|
+
- pattern-either:
|
|
268
|
+
- pattern: Cipher.getInstance("DES")
|
|
269
|
+
- pattern: Cipher.getInstance("DESede")
|
|
270
|
+
- pattern: Cipher.getInstance("DESede/...")
|
|
271
|
+
- pattern: Cipher.getInstance("RC2")
|
|
272
|
+
- pattern: Cipher.getInstance("RC4")
|
|
273
|
+
- pattern: KeyGenerator.getInstance("DES")
|
|
274
|
+
- pattern: KeyGenerator.getInstance("DESede")
|
|
275
|
+
- id: narvy.kotlin.crypto.rsa-ecb-nopadding-cipher
|
|
276
|
+
message: RSA is used with `NoPadding` (raw textbook RSA) instead of OAEP. Textbook RSA is deterministic and malleable, and
|
|
277
|
+
an attacker who can submit chosen ciphertexts to a decryption oracle can recover the plaintext (Bleichenbacher-style attacks)
|
|
278
|
+
(CWE-780). Use `RSA/ECB/OAEPWithSHA-256AndMGF1Padding`.
|
|
279
|
+
severity: ERROR
|
|
280
|
+
languages:
|
|
281
|
+
- kotlin
|
|
282
|
+
metadata:
|
|
283
|
+
category: security
|
|
284
|
+
cwe:
|
|
285
|
+
- 'CWE-780: Use of RSA Algorithm without OAEP'
|
|
286
|
+
owasp:
|
|
287
|
+
- A02:2021 - Cryptographic Failures
|
|
288
|
+
subcategory:
|
|
289
|
+
- vuln
|
|
290
|
+
likelihood: LOW
|
|
291
|
+
impact: HIGH
|
|
292
|
+
confidence: HIGH
|
|
293
|
+
technology:
|
|
294
|
+
- kotlin
|
|
295
|
+
patterns:
|
|
296
|
+
- pattern-either:
|
|
297
|
+
- pattern: Cipher.getInstance("RSA/ECB/NoPadding")
|
|
298
|
+
- pattern: Cipher.getInstance("RSA/None/NoPadding")
|
|
299
|
+
- id: narvy.kotlin.crypto.weak-rsa-keysize.weak-rsa-keysize
|
|
300
|
+
message: An RSA `KeyPairGenerator` is initialised with a key size below 2048 bits. NIST deprecated 1024-bit RSA in 2013
|
|
301
|
+
(CWE-326). Initialise with 2048 bits minimum (3072+ for long-lived keys).
|
|
302
|
+
severity: WARNING
|
|
303
|
+
languages:
|
|
304
|
+
- kotlin
|
|
305
|
+
metadata:
|
|
306
|
+
category: security
|
|
307
|
+
cwe:
|
|
308
|
+
- 'CWE-326: Inadequate Encryption Strength'
|
|
309
|
+
owasp:
|
|
310
|
+
- A02:2021 - Cryptographic Failures
|
|
311
|
+
subcategory:
|
|
312
|
+
- vuln
|
|
313
|
+
likelihood: LOW
|
|
314
|
+
impact: HIGH
|
|
315
|
+
confidence: HIGH
|
|
316
|
+
technology:
|
|
317
|
+
- kotlin
|
|
318
|
+
patterns:
|
|
319
|
+
- pattern-either:
|
|
320
|
+
- pattern: 'val $KEY = $G.getInstance("RSA")
|
|
321
|
+
|
|
322
|
+
...
|
|
323
|
+
|
|
324
|
+
$KEY.initialize($BITS, ...)
|
|
325
|
+
|
|
326
|
+
'
|
|
327
|
+
- pattern: 'var $KEY = $G.getInstance("RSA")
|
|
328
|
+
|
|
329
|
+
...
|
|
330
|
+
|
|
331
|
+
$KEY.initialize($BITS, ...)
|
|
332
|
+
|
|
333
|
+
'
|
|
334
|
+
- pattern: 'val $KEY = $G.getInstance("RSA")
|
|
335
|
+
|
|
336
|
+
...
|
|
337
|
+
|
|
338
|
+
$KEY.initialize($BITS)
|
|
339
|
+
|
|
340
|
+
'
|
|
341
|
+
- pattern: 'var $KEY = $G.getInstance("RSA")
|
|
342
|
+
|
|
343
|
+
...
|
|
344
|
+
|
|
345
|
+
$KEY.initialize($BITS)
|
|
346
|
+
|
|
347
|
+
'
|
|
348
|
+
- metavariable-comparison:
|
|
349
|
+
metavariable: $BITS
|
|
350
|
+
comparison: $BITS < 2048
|
|
351
|
+
- id: narvy.kotlin.crypto.insecure-random.insecure-random
|
|
352
|
+
message: '`kotlin.random.Random` / `java.util.Random` / `Math.random()` are predictable PRNGs once a handful of outputs
|
|
353
|
+
are observed. Used to seed a token, password reset code, or any other security-relevant value, an attacker can reconstruct
|
|
354
|
+
past or future outputs (CWE-330, CWE-338). Use `java.security.SecureRandom` for anything that must be unpredictable.'
|
|
355
|
+
severity: WARNING
|
|
356
|
+
languages:
|
|
357
|
+
- kotlin
|
|
358
|
+
metadata:
|
|
359
|
+
category: security
|
|
360
|
+
cwe:
|
|
361
|
+
- 'CWE-330: Use of Insufficiently Random Values'
|
|
362
|
+
- 'CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)'
|
|
363
|
+
owasp:
|
|
364
|
+
- A02:2021 - Cryptographic Failures
|
|
365
|
+
subcategory:
|
|
366
|
+
- audit
|
|
367
|
+
likelihood: MEDIUM
|
|
368
|
+
impact: MEDIUM
|
|
369
|
+
confidence: MEDIUM
|
|
370
|
+
technology:
|
|
371
|
+
- kotlin
|
|
372
|
+
patterns:
|
|
373
|
+
- pattern-either:
|
|
374
|
+
- pattern: Random.nextLong()
|
|
375
|
+
- pattern: Random.nextInt(...)
|
|
376
|
+
- pattern: Random.Default.nextLong()
|
|
377
|
+
- pattern: Math.random()
|
|
378
|
+
- pattern: java.util.Random()
|
|
379
|
+
- pattern-not: SecureRandom()
|
|
380
|
+
- pattern-not: java.security.SecureRandom()
|
|
381
|
+
- id: narvy.kotlin.sqli.raw-sql-string-template.raw-sql-string-template
|
|
382
|
+
message: >-
|
|
383
|
+
A SQL string built with Kotlin string-template interpolation (`"SELECT
|
|
384
|
+
... WHERE x = $var"` or `"${expr}"`) is passed directly to a JDBC
|
|
385
|
+
`Statement`/`Connection.prepareStatement` or an Exposed
|
|
386
|
+
`TransactionManager.exec(...)` call. Interpolation happens before the
|
|
387
|
+
driver ever sees the string, so a tainted value here is spliced straight
|
|
388
|
+
into the SQL grammar - the same risk as `+` concatenation (CWE-89). Use
|
|
389
|
+
`?` placeholders with bound parameters instead of interpolating the value
|
|
390
|
+
into the query text.
|
|
391
|
+
severity: ERROR
|
|
392
|
+
languages:
|
|
393
|
+
- kotlin
|
|
394
|
+
metadata:
|
|
395
|
+
category: security
|
|
396
|
+
cwe:
|
|
397
|
+
- 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command (''SQL Injection'')'
|
|
398
|
+
owasp:
|
|
399
|
+
- A03:2021 - Injection
|
|
400
|
+
subcategory:
|
|
401
|
+
- vuln
|
|
402
|
+
likelihood: HIGH
|
|
403
|
+
impact: HIGH
|
|
404
|
+
confidence: MEDIUM
|
|
405
|
+
technology:
|
|
406
|
+
- kotlin
|
|
407
|
+
patterns:
|
|
408
|
+
- pattern-either:
|
|
409
|
+
- pattern: $CONN.prepareStatement("...${$X}...")
|
|
410
|
+
- pattern: $STMT.executeQuery("...${$X}...")
|
|
411
|
+
- pattern: $STMT.executeUpdate("...${$X}...")
|
|
412
|
+
- pattern: $TM.current().exec("...${$X}...")
|
|
413
|
+
- pattern: TransactionManager.current().exec("...${$X}...")
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# ASP.NET config hardening (web.config/attributes): request validation off, debug compilation on.
|
|
4
|
+
# Generic mode.
|
|
5
|
+
|
|
6
|
+
- id: narvy.csharp.config.request-validation-disabled.request-validation-disabled
|
|
7
|
+
message: >-
|
|
8
|
+
ASP.NET request validation is disabled (`validateRequest="false"` in
|
|
9
|
+
web.config, or `[ValidateInput(false)]` on a controller/action). Request
|
|
10
|
+
validation is the framework's built-in first line against reflected XSS
|
|
11
|
+
and script injection in posted values; turning it off removes that
|
|
12
|
+
safety net for every affected request (CWE-20, CWE-79). Leave it on and
|
|
13
|
+
encode output at the point of use instead of disabling validation
|
|
14
|
+
wholesale.
|
|
15
|
+
severity: WARNING
|
|
16
|
+
languages: [generic]
|
|
17
|
+
paths:
|
|
18
|
+
include:
|
|
19
|
+
- "*.config"
|
|
20
|
+
- "*.cs"
|
|
21
|
+
metadata:
|
|
22
|
+
category: security
|
|
23
|
+
cwe:
|
|
24
|
+
- "CWE-20: Improper Input Validation"
|
|
25
|
+
owasp:
|
|
26
|
+
- "A03:2021 - Injection"
|
|
27
|
+
subcategory: [audit]
|
|
28
|
+
likelihood: LOW
|
|
29
|
+
impact: MEDIUM
|
|
30
|
+
confidence: MEDIUM
|
|
31
|
+
technology: [csharp, dotnet, asp.net]
|
|
32
|
+
patterns:
|
|
33
|
+
- pattern-either:
|
|
34
|
+
- pattern-regex: 'validateRequest\s*=\s*"false"'
|
|
35
|
+
- pattern-regex: 'ValidateInput\s*\(\s*false\s*\)'
|
|
36
|
+
|
|
37
|
+
- id: narvy.csharp.config.debug-compilation-enabled.debug-compilation-enabled
|
|
38
|
+
message: >-
|
|
39
|
+
`<compilation debug="true">` is set in web.config. Debug compilation
|
|
40
|
+
disables request timeouts, emits verbose error pages that leak stack
|
|
41
|
+
traces and source paths, and produces non-optimized, larger binaries -
|
|
42
|
+
none of which belong in a deployed application (CWE-11, CWE-489). Set
|
|
43
|
+
`debug="false"` for anything past local development.
|
|
44
|
+
severity: WARNING
|
|
45
|
+
languages: [generic]
|
|
46
|
+
paths:
|
|
47
|
+
include:
|
|
48
|
+
- "*.config"
|
|
49
|
+
metadata:
|
|
50
|
+
category: security
|
|
51
|
+
cwe:
|
|
52
|
+
- "CWE-11: ASP.NET Misconfiguration: Creating Debug Binary"
|
|
53
|
+
owasp:
|
|
54
|
+
- "A05:2021 - Security Misconfiguration"
|
|
55
|
+
subcategory: [audit]
|
|
56
|
+
likelihood: LOW
|
|
57
|
+
impact: MEDIUM
|
|
58
|
+
confidence: HIGH
|
|
59
|
+
technology: [csharp, dotnet, asp.net]
|
|
60
|
+
patterns:
|
|
61
|
+
- pattern-regex: '<compilation[^>]*\bdebug\s*=\s*"true"'
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# C#/.NET weak crypto: broken hashes (MD5/SHA-1) and broken/legacy ciphers (DES/3DES/RC2).
|
|
4
|
+
|
|
5
|
+
- id: narvy.csharp.crypto.weak-hash.weak-hash
|
|
6
|
+
message: >-
|
|
7
|
+
A cryptographically broken hash algorithm (MD5 or SHA-1) is instantiated.
|
|
8
|
+
Both have practical collision attacks and must not be used for
|
|
9
|
+
signatures, integrity of security-relevant data, or password hashing
|
|
10
|
+
(CWE-327, CWE-328). Use SHA-256 or better for integrity; for passwords
|
|
11
|
+
use a memory-hard KDF such as PBKDF2 (`Rfc2898DeriveBytes`), bcrypt or
|
|
12
|
+
Argon2.
|
|
13
|
+
severity: WARNING
|
|
14
|
+
languages: [csharp]
|
|
15
|
+
metadata:
|
|
16
|
+
category: security
|
|
17
|
+
cwe:
|
|
18
|
+
- "CWE-327: Use of a Broken or Risky Cryptographic Algorithm"
|
|
19
|
+
- "CWE-328: Use of Weak Hash"
|
|
20
|
+
owasp:
|
|
21
|
+
- "A02:2021 - Cryptographic Failures"
|
|
22
|
+
subcategory: [vuln]
|
|
23
|
+
likelihood: MEDIUM
|
|
24
|
+
impact: MEDIUM
|
|
25
|
+
confidence: HIGH
|
|
26
|
+
technology: [csharp, dotnet]
|
|
27
|
+
patterns:
|
|
28
|
+
- pattern-either:
|
|
29
|
+
- pattern: MD5.Create(...)
|
|
30
|
+
- pattern: SHA1.Create(...)
|
|
31
|
+
- pattern: new MD5CryptoServiceProvider(...)
|
|
32
|
+
- pattern: new SHA1CryptoServiceProvider(...)
|
|
33
|
+
- pattern: new MD5Cng(...)
|
|
34
|
+
- pattern: new SHA1Managed(...)
|
|
35
|
+
- pattern: System.Security.Cryptography.MD5.Create(...)
|
|
36
|
+
- pattern: System.Security.Cryptography.SHA1.Create(...)
|
|
37
|
+
|
|
38
|
+
- id: narvy.csharp.crypto.weak-cipher.weak-cipher
|
|
39
|
+
message: >-
|
|
40
|
+
A broken or legacy symmetric cipher (DES, Triple-DES, or RC2) is
|
|
41
|
+
instantiated. DES and RC2 have inadequate key sizes and Triple-DES is
|
|
42
|
+
deprecated (SWEET32 birthday attack on its 64-bit block) (CWE-327).
|
|
43
|
+
Use AES (`Aes.Create()`) with an authenticated mode such as AES-GCM.
|
|
44
|
+
severity: WARNING
|
|
45
|
+
languages: [csharp]
|
|
46
|
+
metadata:
|
|
47
|
+
category: security
|
|
48
|
+
cwe:
|
|
49
|
+
- "CWE-327: Use of a Broken or Risky Cryptographic Algorithm"
|
|
50
|
+
owasp:
|
|
51
|
+
- "A02:2021 - Cryptographic Failures"
|
|
52
|
+
subcategory: [vuln]
|
|
53
|
+
likelihood: MEDIUM
|
|
54
|
+
impact: MEDIUM
|
|
55
|
+
confidence: HIGH
|
|
56
|
+
technology: [csharp, dotnet]
|
|
57
|
+
patterns:
|
|
58
|
+
- pattern-either:
|
|
59
|
+
- pattern: new DESCryptoServiceProvider(...)
|
|
60
|
+
- pattern: new TripleDESCryptoServiceProvider(...)
|
|
61
|
+
- pattern: new RC2CryptoServiceProvider(...)
|
|
62
|
+
- pattern: DES.Create(...)
|
|
63
|
+
- pattern: TripleDES.Create(...)
|
|
64
|
+
- pattern: RC2.Create(...)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# C#/.NET unsafe deserialization: BinaryFormatter and Json.NET polymorphic TypeNameHandling.
|
|
4
|
+
|
|
5
|
+
- id: narvy.csharp.deserialization.binary-formatter.binary-formatter
|
|
6
|
+
message: >-
|
|
7
|
+
`BinaryFormatter` is used. It deserializes the concrete .NET types named
|
|
8
|
+
in the payload, so on any attacker-influenced data it is a
|
|
9
|
+
remote-code-execution gadget - Microsoft has deprecated it and made it
|
|
10
|
+
throw by default from .NET 5+ precisely because it cannot be made safe
|
|
11
|
+
(CWE-502). Replace it with a contract-based serializer that does not
|
|
12
|
+
embed types, such as `System.Text.Json` or `DataContractSerializer` over
|
|
13
|
+
a known type.
|
|
14
|
+
severity: ERROR
|
|
15
|
+
languages: [csharp]
|
|
16
|
+
metadata:
|
|
17
|
+
category: security
|
|
18
|
+
cwe:
|
|
19
|
+
- "CWE-502: Deserialization of Untrusted Data"
|
|
20
|
+
owasp:
|
|
21
|
+
- "A08:2021 - Software and Data Integrity Failures"
|
|
22
|
+
subcategory: [vuln]
|
|
23
|
+
likelihood: MEDIUM
|
|
24
|
+
impact: HIGH
|
|
25
|
+
confidence: HIGH
|
|
26
|
+
technology: [csharp, dotnet]
|
|
27
|
+
patterns:
|
|
28
|
+
- pattern-either:
|
|
29
|
+
- pattern: new BinaryFormatter(...)
|
|
30
|
+
- pattern: new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(...)
|
|
31
|
+
|
|
32
|
+
- id: narvy.csharp.deserialization.json-net-typenamehandling.json-net-typenamehandling
|
|
33
|
+
message: >-
|
|
34
|
+
Json.NET (`Newtonsoft.Json`) is configured with a permissive
|
|
35
|
+
`TypeNameHandling` (`All`, `Auto`, `Objects`, or `Arrays`). That makes
|
|
36
|
+
the serializer honour a `$type` field in the JSON and instantiate the
|
|
37
|
+
named type, which an attacker can point at a gadget class to achieve
|
|
38
|
+
remote code execution (CWE-502). Use `TypeNameHandling.None`, or, if
|
|
39
|
+
polymorphism is genuinely required, pin a strict `SerializationBinder`
|
|
40
|
+
that allow-lists the expected types.
|
|
41
|
+
severity: ERROR
|
|
42
|
+
languages: [csharp]
|
|
43
|
+
metadata:
|
|
44
|
+
category: security
|
|
45
|
+
cwe:
|
|
46
|
+
- "CWE-502: Deserialization of Untrusted Data"
|
|
47
|
+
owasp:
|
|
48
|
+
- "A08:2021 - Software and Data Integrity Failures"
|
|
49
|
+
subcategory: [vuln]
|
|
50
|
+
likelihood: MEDIUM
|
|
51
|
+
impact: HIGH
|
|
52
|
+
confidence: MEDIUM
|
|
53
|
+
technology: [csharp, dotnet, newtonsoft]
|
|
54
|
+
patterns:
|
|
55
|
+
- pattern-either:
|
|
56
|
+
- pattern: TypeNameHandling.All
|
|
57
|
+
- pattern: TypeNameHandling.Auto
|
|
58
|
+
- pattern: TypeNameHandling.Objects
|
|
59
|
+
- pattern: TypeNameHandling.Arrays
|