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,122 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# C#/.NET injection: ADO.NET SQL concatenation, request input into filesystem APIs (path traversal) and process launch (command injection).
|
|
4
|
+
|
|
5
|
+
- id: narvy.csharp.sqli.command-text-concat.command-text-concat
|
|
6
|
+
message: >-
|
|
7
|
+
A SQL command text is built with `+` string concatenation and handed to
|
|
8
|
+
ADO.NET (`new SqlCommand(...)`, `SqlCommand.CommandText`, or the
|
|
9
|
+
equivalent `Npgsql`/`MySql`/`OleDb`/`Odbc`/`SQLite` command). Any tainted
|
|
10
|
+
value spliced into the SQL grammar this way is a SQL injection (CWE-89).
|
|
11
|
+
Keep the command text a fixed literal and pass values as parameters
|
|
12
|
+
(`cmd.Parameters.AddWithValue("@id", id)` with a `@id` placeholder).
|
|
13
|
+
severity: ERROR
|
|
14
|
+
languages: [csharp]
|
|
15
|
+
metadata:
|
|
16
|
+
category: security
|
|
17
|
+
cwe:
|
|
18
|
+
- "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')"
|
|
19
|
+
owasp:
|
|
20
|
+
- "A03:2021 - Injection"
|
|
21
|
+
subcategory: [vuln]
|
|
22
|
+
likelihood: HIGH
|
|
23
|
+
impact: HIGH
|
|
24
|
+
confidence: MEDIUM
|
|
25
|
+
technology: [csharp, dotnet, ado.net]
|
|
26
|
+
patterns:
|
|
27
|
+
- pattern-either:
|
|
28
|
+
- pattern: new $CMDTYPE($SQL, ...)
|
|
29
|
+
- pattern: new $CMDTYPE($SQL)
|
|
30
|
+
- pattern: $CMD.CommandText = $SQL;
|
|
31
|
+
- metavariable-regex:
|
|
32
|
+
metavariable: $CMDTYPE
|
|
33
|
+
regex: ^(SqlCommand|NpgsqlCommand|MySqlCommand|OleDbCommand|OdbcCommand|SQLiteCommand|SqliteCommand)$
|
|
34
|
+
- metavariable-pattern:
|
|
35
|
+
metavariable: $SQL
|
|
36
|
+
patterns:
|
|
37
|
+
# concatenation, but not a chain of only string literals joined by `+`
|
|
38
|
+
- pattern-regex: '\+'
|
|
39
|
+
- pattern-not-regex: '^\s*@?\$?"(?:[^"\\]|\\.)*"(\s*\+\s*@?\$?"(?:[^"\\]|\\.)*")*\s*$'
|
|
40
|
+
|
|
41
|
+
- id: narvy.csharp.pathtraversal.request-input-into-file-api.request-input-into-file-api
|
|
42
|
+
message: >-
|
|
43
|
+
A value read from the HTTP request (`Request.Query`/`Form`/`Headers`/
|
|
44
|
+
`Cookies`/`RouteValues`) reaches a `System.IO` file API without being
|
|
45
|
+
reduced to a bare file name first. An attacker can supply `../` segments
|
|
46
|
+
(or an absolute path) to read or write files outside the intended
|
|
47
|
+
directory (CWE-22). Strip the path with `Path.GetFileName(...)` and
|
|
48
|
+
resolve it against a fixed base directory, rejecting anything that
|
|
49
|
+
escapes it.
|
|
50
|
+
severity: ERROR
|
|
51
|
+
languages: [csharp]
|
|
52
|
+
mode: taint
|
|
53
|
+
metadata:
|
|
54
|
+
category: security
|
|
55
|
+
cwe:
|
|
56
|
+
- "CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"
|
|
57
|
+
owasp:
|
|
58
|
+
- "A01:2021 - Broken Access Control"
|
|
59
|
+
subcategory: [vuln]
|
|
60
|
+
likelihood: MEDIUM
|
|
61
|
+
impact: HIGH
|
|
62
|
+
confidence: MEDIUM
|
|
63
|
+
technology: [csharp, dotnet, asp.net]
|
|
64
|
+
pattern-sources:
|
|
65
|
+
- patterns:
|
|
66
|
+
- pattern-either:
|
|
67
|
+
- pattern: $REQ.Query[...]
|
|
68
|
+
- pattern: $REQ.Form[...]
|
|
69
|
+
- pattern: $REQ.Headers[...]
|
|
70
|
+
- pattern: $REQ.Cookies[...]
|
|
71
|
+
- pattern: $REQ.RouteValues[...]
|
|
72
|
+
pattern-sanitizers:
|
|
73
|
+
- pattern: Path.GetFileName(...)
|
|
74
|
+
pattern-sinks:
|
|
75
|
+
- patterns:
|
|
76
|
+
- pattern-either:
|
|
77
|
+
- pattern: File.ReadAllText(...)
|
|
78
|
+
- pattern: File.ReadAllBytes(...)
|
|
79
|
+
- pattern: File.ReadAllLines(...)
|
|
80
|
+
- pattern: File.OpenRead(...)
|
|
81
|
+
- pattern: File.OpenText(...)
|
|
82
|
+
- pattern: File.WriteAllText(...)
|
|
83
|
+
- pattern: File.WriteAllBytes(...)
|
|
84
|
+
- pattern: new StreamReader(...)
|
|
85
|
+
- pattern: new FileStream(...)
|
|
86
|
+
|
|
87
|
+
- id: narvy.csharp.cmdi.process-start-untrusted.process-start-untrusted
|
|
88
|
+
message: >-
|
|
89
|
+
A value read from the HTTP request is passed to `Process.Start(...)`
|
|
90
|
+
(as the file name or the arguments). Request-controlled process
|
|
91
|
+
arguments let an attacker inject extra arguments, and a
|
|
92
|
+
request-controlled file name lets them choose the program to run - both
|
|
93
|
+
are command injection (CWE-78). Never build a process invocation from
|
|
94
|
+
request input; if an external tool must run, hardcode the executable and
|
|
95
|
+
pass a strictly validated, allow-listed argument.
|
|
96
|
+
severity: ERROR
|
|
97
|
+
languages: [csharp]
|
|
98
|
+
metadata:
|
|
99
|
+
category: security
|
|
100
|
+
cwe:
|
|
101
|
+
- "CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')"
|
|
102
|
+
owasp:
|
|
103
|
+
- "A03:2021 - Injection"
|
|
104
|
+
subcategory: [vuln]
|
|
105
|
+
likelihood: HIGH
|
|
106
|
+
impact: HIGH
|
|
107
|
+
confidence: MEDIUM
|
|
108
|
+
technology: [csharp, dotnet]
|
|
109
|
+
patterns:
|
|
110
|
+
- pattern-either:
|
|
111
|
+
- pattern: System.Diagnostics.Process.Start(..., $REQ.Query[...], ...)
|
|
112
|
+
- pattern: System.Diagnostics.Process.Start(..., $REQ.Form[...], ...)
|
|
113
|
+
- pattern: System.Diagnostics.Process.Start(..., $REQ.Headers[...], ...)
|
|
114
|
+
- pattern: System.Diagnostics.Process.Start(..., $REQ.RouteValues[...], ...)
|
|
115
|
+
- pattern: System.Diagnostics.Process.Start($REQ.Query[...], ...)
|
|
116
|
+
- pattern: System.Diagnostics.Process.Start($REQ.Form[...], ...)
|
|
117
|
+
- pattern: Process.Start(..., $REQ.Query[...], ...)
|
|
118
|
+
- pattern: Process.Start(..., $REQ.Form[...], ...)
|
|
119
|
+
- pattern: Process.Start(..., $REQ.Headers[...], ...)
|
|
120
|
+
- pattern: Process.Start(..., $REQ.RouteValues[...], ...)
|
|
121
|
+
- pattern: Process.Start($REQ.Query[...], ...)
|
|
122
|
+
- pattern: Process.Start($REQ.Form[...], ...)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# C#/.NET XXE: an XmlDocument left with its default resolver still resolves external entities/DTDs.
|
|
4
|
+
|
|
5
|
+
- id: narvy.csharp.xxe.xmldocument-default-resolver.xmldocument-default-resolver
|
|
6
|
+
message: >-
|
|
7
|
+
An `XmlDocument` parses input while keeping its default `XmlResolver`.
|
|
8
|
+
On older target frameworks that resolver follows external entities and
|
|
9
|
+
DTDs, so parsing attacker-controlled XML lets it read local files or
|
|
10
|
+
reach internal network resources (XXE / SSRF, CWE-611). Set
|
|
11
|
+
`doc.XmlResolver = null;` before loading, or parse with
|
|
12
|
+
`XmlReader` configured with `DtdProcessing.Prohibit`.
|
|
13
|
+
severity: ERROR
|
|
14
|
+
languages: [csharp]
|
|
15
|
+
metadata:
|
|
16
|
+
category: security
|
|
17
|
+
cwe:
|
|
18
|
+
- "CWE-611: Improper Restriction of XML External Entity Reference"
|
|
19
|
+
owasp:
|
|
20
|
+
- "A05:2021 - Security Misconfiguration"
|
|
21
|
+
subcategory: [vuln]
|
|
22
|
+
likelihood: MEDIUM
|
|
23
|
+
impact: HIGH
|
|
24
|
+
confidence: MEDIUM
|
|
25
|
+
technology: [csharp, dotnet]
|
|
26
|
+
patterns:
|
|
27
|
+
- pattern-either:
|
|
28
|
+
- patterns:
|
|
29
|
+
- pattern-inside: |
|
|
30
|
+
var $DOC = new XmlDocument();
|
|
31
|
+
...
|
|
32
|
+
- pattern-not-inside: |
|
|
33
|
+
var $DOC = new XmlDocument();
|
|
34
|
+
...
|
|
35
|
+
$DOC.XmlResolver = null;
|
|
36
|
+
...
|
|
37
|
+
- patterns:
|
|
38
|
+
- pattern-inside: |
|
|
39
|
+
$TY $DOC = new XmlDocument();
|
|
40
|
+
...
|
|
41
|
+
- pattern-not-inside: |
|
|
42
|
+
$TY $DOC = new XmlDocument();
|
|
43
|
+
...
|
|
44
|
+
$DOC.XmlResolver = null;
|
|
45
|
+
...
|
|
46
|
+
- pattern-either:
|
|
47
|
+
- pattern: $DOC.LoadXml(...)
|
|
48
|
+
- pattern: $DOC.Load(...)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# Java JWT auth weaknesses: hardcoded signing key, decode without verification, none-algorithm.
|
|
4
|
+
|
|
5
|
+
- id: narvy.java.jwt.hardcoded-signing-key.hardcoded-signing-key
|
|
6
|
+
message: >-
|
|
7
|
+
A JWT signing/verification key is a hardcoded string literal (`jjwt`'s
|
|
8
|
+
`Keys.hmacShaKeyFor(...)`, `java-jwt`'s `Algorithm.HMAC256(...)`, or a
|
|
9
|
+
plain `.getBytes()` call on a literal). Anyone with source or
|
|
10
|
+
decompiled-binary access can forge arbitrarily privileged tokens
|
|
11
|
+
(CWE-321, CWE-798). Load the signing key from an environment variable or
|
|
12
|
+
secrets manager, generated with at least 256 bits of entropy for HMAC.
|
|
13
|
+
severity: ERROR
|
|
14
|
+
languages: [java]
|
|
15
|
+
metadata:
|
|
16
|
+
category: security
|
|
17
|
+
cwe:
|
|
18
|
+
- "CWE-321: Use of Hard-coded Cryptographic Key"
|
|
19
|
+
- "CWE-798: Use of Hard-coded Credentials"
|
|
20
|
+
owasp:
|
|
21
|
+
- "A07:2021 - Identification and Authentication Failures"
|
|
22
|
+
subcategory: [vuln]
|
|
23
|
+
likelihood: LOW
|
|
24
|
+
impact: HIGH
|
|
25
|
+
confidence: MEDIUM
|
|
26
|
+
technology: [java]
|
|
27
|
+
patterns:
|
|
28
|
+
- pattern-either:
|
|
29
|
+
- pattern: Keys.hmacShaKeyFor("...".getBytes(...))
|
|
30
|
+
- pattern: io.jsonwebtoken.security.Keys.hmacShaKeyFor("...".getBytes(...))
|
|
31
|
+
- pattern: Algorithm.HMAC256("...")
|
|
32
|
+
- pattern: Algorithm.HMAC384("...")
|
|
33
|
+
- pattern: Algorithm.HMAC512("...")
|
|
34
|
+
- pattern: com.auth0.jwt.algorithms.Algorithm.HMAC256("...")
|
|
35
|
+
|
|
36
|
+
- id: narvy.java.jwt.decode-without-verification.decode-without-verification
|
|
37
|
+
message: >-
|
|
38
|
+
`JWT.decode(...)` (auth0 java-jwt) reads and parses a token's claims
|
|
39
|
+
without verifying its signature - unlike `JWTVerifier.verify(...)`,
|
|
40
|
+
`decode` accepts a token signed with any key, or none at all. Branching
|
|
41
|
+
on claims read this way (role, user id, `exp`) is an authentication
|
|
42
|
+
bypass (CWE-347). Use a `JWTVerifier` built with the expected algorithm
|
|
43
|
+
and key, and call `verify(token)` instead of `decode(token)`.
|
|
44
|
+
severity: ERROR
|
|
45
|
+
languages: [java]
|
|
46
|
+
metadata:
|
|
47
|
+
category: security
|
|
48
|
+
cwe:
|
|
49
|
+
- "CWE-347: Improper Verification of Cryptographic Signature"
|
|
50
|
+
owasp:
|
|
51
|
+
- "A07:2021 - Identification and Authentication Failures"
|
|
52
|
+
subcategory: [vuln]
|
|
53
|
+
likelihood: MEDIUM
|
|
54
|
+
impact: HIGH
|
|
55
|
+
confidence: HIGH
|
|
56
|
+
technology: [java]
|
|
57
|
+
patterns:
|
|
58
|
+
- pattern-either:
|
|
59
|
+
- pattern: JWT.decode($TOKEN)
|
|
60
|
+
- pattern: com.auth0.jwt.JWT.decode($TOKEN)
|
|
61
|
+
|
|
62
|
+
- id: narvy.java.jwt.parser-no-signing-key.parser-no-signing-key
|
|
63
|
+
message: >-
|
|
64
|
+
A `jjwt` `Jwts.parserBuilder()` (or the deprecated `Jwts.parser()`)
|
|
65
|
+
chain calls `.build().parse(...)`/`.parseClaimsJws(...)` with no
|
|
66
|
+
`.setSigningKey(...)`/`.verifyWith(...)` configured on the builder. Some
|
|
67
|
+
jjwt versions accept an unsigned or `alg: none` token in this
|
|
68
|
+
configuration, which is a full authentication bypass (CWE-347). Always
|
|
69
|
+
set the expected signing key (and, ideally, pin the accepted algorithm)
|
|
70
|
+
on the parser builder before parsing an incoming token.
|
|
71
|
+
severity: WARNING
|
|
72
|
+
languages: [java]
|
|
73
|
+
metadata:
|
|
74
|
+
category: security
|
|
75
|
+
cwe:
|
|
76
|
+
- "CWE-347: Improper Verification of Cryptographic Signature"
|
|
77
|
+
owasp:
|
|
78
|
+
- "A07:2021 - Identification and Authentication Failures"
|
|
79
|
+
subcategory: [audit]
|
|
80
|
+
likelihood: LOW
|
|
81
|
+
impact: HIGH
|
|
82
|
+
confidence: LOW
|
|
83
|
+
technology: [java]
|
|
84
|
+
patterns:
|
|
85
|
+
- pattern: |
|
|
86
|
+
$P = Jwts.parserBuilder();
|
|
87
|
+
...
|
|
88
|
+
$P.build().parseClaimsJws($TOKEN);
|
|
89
|
+
- pattern-not: |
|
|
90
|
+
$P = Jwts.parserBuilder();
|
|
91
|
+
...
|
|
92
|
+
$P.setSigningKey(...);
|
|
93
|
+
...
|
|
94
|
+
$P.build().parseClaimsJws($TOKEN);
|
|
95
|
+
- pattern-not: |
|
|
96
|
+
$P = Jwts.parserBuilder();
|
|
97
|
+
...
|
|
98
|
+
$P.verifyWith(...);
|
|
99
|
+
...
|
|
100
|
+
$P.build().parseClaimsJws($TOKEN);
|
|
101
|
+
|
|
102
|
+
- id: narvy.java.jwt.hardcoded-fallback-secret.hardcoded-fallback-secret
|
|
103
|
+
message: >-
|
|
104
|
+
A JWT/session-signing secret is read from configuration with a
|
|
105
|
+
hardcoded string as the fallback default (`System.getProperty("...",
|
|
106
|
+
"literal")`, `env.getProperty("...", "literal")`). If the real
|
|
107
|
+
environment variable or property is ever unset - a common deployment
|
|
108
|
+
mistake - every instance silently falls back to the same publicly
|
|
109
|
+
visible secret, which lets anyone forge valid tokens (CWE-798,
|
|
110
|
+
CWE-321). Fail closed instead: throw if the property is missing rather
|
|
111
|
+
than substituting a literal.
|
|
112
|
+
severity: ERROR
|
|
113
|
+
languages: [java]
|
|
114
|
+
metadata:
|
|
115
|
+
category: security
|
|
116
|
+
cwe:
|
|
117
|
+
- "CWE-798: Use of Hard-coded Credentials"
|
|
118
|
+
- "CWE-321: Use of Hard-coded Cryptographic Key"
|
|
119
|
+
owasp:
|
|
120
|
+
- "A07:2021 - Identification and Authentication Failures"
|
|
121
|
+
subcategory: [vuln]
|
|
122
|
+
likelihood: LOW
|
|
123
|
+
impact: HIGH
|
|
124
|
+
confidence: LOW
|
|
125
|
+
technology: [java]
|
|
126
|
+
patterns:
|
|
127
|
+
- pattern-either:
|
|
128
|
+
- pattern: System.getProperty($KEY, "...")
|
|
129
|
+
- pattern: System.getenv($KEY, "...")
|
|
130
|
+
- pattern: $ENV.getProperty($KEY, "...")
|
|
131
|
+
- pattern: $ENV.getProperty($KEY, "...", ...)
|
|
132
|
+
- metavariable-regex:
|
|
133
|
+
metavariable: $KEY
|
|
134
|
+
regex: (?i)"[^"]*(secret|jwt|token|signing.?key|api.?key|password|passwd|credential)[^"]*"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# Java unsafe deserialization: ObjectInputStream, Jackson polymorphic typing, JMS ObjectMessage.
|
|
4
|
+
|
|
5
|
+
- id: narvy.java.deserialization.objectinputstream-readobject.objectinputstream-readobject
|
|
6
|
+
message: >-
|
|
7
|
+
`ObjectInputStream.readObject()` deserialises whatever class stream the
|
|
8
|
+
caller supplies. If the underlying stream can come from the network, a
|
|
9
|
+
file upload, or any other untrusted source, an attacker can smuggle a
|
|
10
|
+
gadget-chain payload that executes arbitrary code the moment it is
|
|
11
|
+
deserialised, before any application logic runs (CWE-502). Avoid native
|
|
12
|
+
Java serialization for untrusted input; use a data format with no code
|
|
13
|
+
execution surface (JSON/Protobuf), or wrap the stream in a
|
|
14
|
+
`ObjectInputFilter` allow-list of expected classes.
|
|
15
|
+
severity: ERROR
|
|
16
|
+
languages: [java]
|
|
17
|
+
metadata:
|
|
18
|
+
category: security
|
|
19
|
+
cwe:
|
|
20
|
+
- "CWE-502: Deserialization of Untrusted Data"
|
|
21
|
+
owasp:
|
|
22
|
+
- "A08:2021 - Software and Data Integrity Failures"
|
|
23
|
+
subcategory: [vuln]
|
|
24
|
+
likelihood: LOW
|
|
25
|
+
impact: HIGH
|
|
26
|
+
confidence: LOW
|
|
27
|
+
technology: [java]
|
|
28
|
+
patterns:
|
|
29
|
+
- pattern-either:
|
|
30
|
+
- pattern: new ObjectInputStream($SOCK.getInputStream()).readObject()
|
|
31
|
+
- pattern: |
|
|
32
|
+
$OIS = new ObjectInputStream($SOCK.getInputStream());
|
|
33
|
+
...
|
|
34
|
+
$OIS.readObject();
|
|
35
|
+
- pattern: |
|
|
36
|
+
$OIS = new ObjectInputStream($ANY);
|
|
37
|
+
...
|
|
38
|
+
$OIS.readObject();
|
|
39
|
+
- pattern-not: |
|
|
40
|
+
$OIS = new ObjectInputStream($ANY);
|
|
41
|
+
$OIS.setObjectInputFilter(...);
|
|
42
|
+
...
|
|
43
|
+
$OIS.readObject();
|
|
44
|
+
|
|
45
|
+
- id: narvy.java.deserialization.jackson-enable-default-typing.jackson-enable-default-typing
|
|
46
|
+
message: >-
|
|
47
|
+
Jackson's `ObjectMapper` has polymorphic default typing enabled
|
|
48
|
+
(`enableDefaultTyping`/`activateDefaultTyping`) with no restricted
|
|
49
|
+
`PolymorphicTypeValidator`. This embeds a `@class` field in the JSON that
|
|
50
|
+
tells Jackson which concrete class to instantiate, and an attacker who
|
|
51
|
+
controls the JSON can point it at a gadget class already on the
|
|
52
|
+
classpath to achieve remote code execution (CWE-502). Remove default
|
|
53
|
+
typing, or pass a `BasicPolymorphicTypeValidator` restricted to an
|
|
54
|
+
explicit allow-list of expected base types.
|
|
55
|
+
severity: ERROR
|
|
56
|
+
languages: [java]
|
|
57
|
+
metadata:
|
|
58
|
+
category: security
|
|
59
|
+
cwe:
|
|
60
|
+
- "CWE-502: Deserialization of Untrusted Data"
|
|
61
|
+
owasp:
|
|
62
|
+
- "A08:2021 - Software and Data Integrity Failures"
|
|
63
|
+
subcategory: [vuln]
|
|
64
|
+
likelihood: LOW
|
|
65
|
+
impact: HIGH
|
|
66
|
+
confidence: MEDIUM
|
|
67
|
+
technology: [java]
|
|
68
|
+
patterns:
|
|
69
|
+
- pattern-either:
|
|
70
|
+
# Bare/legacy calls carry no validator at all - always permissive.
|
|
71
|
+
- pattern: $MAPPER.enableDefaultTyping()
|
|
72
|
+
- pattern: $MAPPER.enableDefaultTyping($X)
|
|
73
|
+
# Only the laissez-faire validator (accepts every class) is flagged; a scoped validator is left alone.
|
|
74
|
+
- pattern: $MAPPER.activateDefaultTyping(LaissezFaireSubTypeValidator.instance)
|
|
75
|
+
- pattern: $MAPPER.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ...)
|
|
76
|
+
# Exclude Spring Security's SecurityJackson2Modules.enableDefaultTyping: it installs typing behind an allow-list (mitigated form).
|
|
77
|
+
- pattern-not: SecurityJackson2Modules.enableDefaultTyping(...)
|
|
78
|
+
- pattern-not: $P.SecurityJackson2Modules.enableDefaultTyping(...)
|
|
79
|
+
|
|
80
|
+
- id: narvy.java.deserialization.jms-objectmessage-getobject.jms-objectmessage-getobject
|
|
81
|
+
message: >-
|
|
82
|
+
`ObjectMessage.getObject()` deserialises the message payload with native
|
|
83
|
+
Java serialization. A JMS broker that accepts messages from outside the
|
|
84
|
+
trust boundary (or a compromised producer) can deliver a gadget-chain
|
|
85
|
+
payload that executes on `getObject()` (CWE-502). Prefer `TextMessage`
|
|
86
|
+
with an explicit JSON/Protobuf parser, or configure the JMS provider's
|
|
87
|
+
class allow-list (e.g. ActiveMQ's `trustedPackages`) if
|
|
88
|
+
`ObjectMessage` must be kept.
|
|
89
|
+
severity: WARNING
|
|
90
|
+
languages: [java]
|
|
91
|
+
metadata:
|
|
92
|
+
category: security
|
|
93
|
+
cwe:
|
|
94
|
+
- "CWE-502: Deserialization of Untrusted Data"
|
|
95
|
+
owasp:
|
|
96
|
+
- "A08:2021 - Software and Data Integrity Failures"
|
|
97
|
+
subcategory: [vuln]
|
|
98
|
+
likelihood: LOW
|
|
99
|
+
impact: HIGH
|
|
100
|
+
confidence: LOW
|
|
101
|
+
technology: [java]
|
|
102
|
+
patterns:
|
|
103
|
+
- pattern-either:
|
|
104
|
+
- pattern: (($T) $MSG).getObject()
|
|
105
|
+
- pattern: $MSG.getObject()
|
|
106
|
+
- pattern-inside: |
|
|
107
|
+
$MSG = ($T) $CONSUMER.receive(...);
|
|
108
|
+
...
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# MyBatis mapper XML: `${...}` splices into SQL text (unlike `#{...}` which binds `?`), so tainted `${...}` is SQLi. Generic mode over mapper *.xml.
|
|
4
|
+
|
|
5
|
+
- id: narvy.java.mybatis.handwritten-dollar-substitution.handwritten-dollar-substitution
|
|
6
|
+
message: >-
|
|
7
|
+
A MyBatis mapper uses `${...}` substitution in a SQL statement. MyBatis
|
|
8
|
+
inlines `${...}` into the query text verbatim (only `#{...}` becomes a
|
|
9
|
+
bound `?` placeholder), so any tainted value that reaches it is a SQL
|
|
10
|
+
injection (CWE-89). Use `#{param}` for values; a `${...}` is only
|
|
11
|
+
acceptable for a column/table identifier you have validated against a
|
|
12
|
+
fixed allow-list.
|
|
13
|
+
severity: ERROR
|
|
14
|
+
languages: [generic]
|
|
15
|
+
paths:
|
|
16
|
+
include:
|
|
17
|
+
- "*.xml"
|
|
18
|
+
metadata:
|
|
19
|
+
category: security
|
|
20
|
+
cwe:
|
|
21
|
+
- "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')"
|
|
22
|
+
owasp:
|
|
23
|
+
- "A03:2021 - Injection"
|
|
24
|
+
subcategory: [vuln]
|
|
25
|
+
likelihood: HIGH
|
|
26
|
+
impact: HIGH
|
|
27
|
+
confidence: MEDIUM
|
|
28
|
+
technology: [java, mybatis]
|
|
29
|
+
patterns:
|
|
30
|
+
- pattern-regex: '\$\{[^}]+\}'
|
|
31
|
+
# Exclude MyBatis Generator boilerplate tokens (framework-emitted, not hand-written interpolation).
|
|
32
|
+
- pattern-not-regex: '\$\{(criterion\.condition|criterion\.value|orderByClause|listItem|item\.[A-Za-z0-9_.]+)\}'
|
|
33
|
+
# Scope to MyBatis SQL statement elements, else `${...}` hits log4j2/Spring placeholders (large FP class).
|
|
34
|
+
- pattern-either:
|
|
35
|
+
- pattern-inside: "<select ...>...</select>"
|
|
36
|
+
- pattern-inside: "<insert ...>...</insert>"
|
|
37
|
+
- pattern-inside: "<update ...>...</update>"
|
|
38
|
+
- pattern-inside: "<delete ...>...</delete>"
|
|
39
|
+
- pattern-inside: "<sql ...>...</sql>"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# SnakeYAML: default `new Yaml()` uses the unrestricted `Constructor`, an RCE gadget on attacker-controlled YAML.
|
|
4
|
+
|
|
5
|
+
- id: narvy.java.deserialization.snakeyaml-unsafe-constructor.snakeyaml-unsafe-constructor
|
|
6
|
+
message: >-
|
|
7
|
+
A SnakeYAML `Yaml` built with the default constructor parses input with
|
|
8
|
+
the unrestricted `Constructor`, which will instantiate any Java type the
|
|
9
|
+
document names through a `!!package.Class` tag. On attacker-controlled
|
|
10
|
+
YAML this is a deserialization gadget that leads to remote code execution
|
|
11
|
+
(CWE-502). Construct the parser with `new Yaml(new SafeConstructor(new
|
|
12
|
+
LoaderOptions()))` (or a `Constructor` restricted to an explicit
|
|
13
|
+
allow-list of expected types) before calling `load`.
|
|
14
|
+
severity: ERROR
|
|
15
|
+
languages: [java]
|
|
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: MEDIUM
|
|
26
|
+
technology: [java, snakeyaml]
|
|
27
|
+
patterns:
|
|
28
|
+
- pattern-inside: |
|
|
29
|
+
Yaml $Y = new Yaml();
|
|
30
|
+
...
|
|
31
|
+
- pattern-either:
|
|
32
|
+
- pattern: $Y.load($SRC)
|
|
33
|
+
- pattern: $Y.loadAll($SRC)
|
|
34
|
+
- pattern: $Y.loadAs($SRC, ...)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# Spring Security authorization: a filter chain that permits every request.
|
|
4
|
+
|
|
5
|
+
- id: narvy.java.spring.permit-all-requests.permit-all-requests
|
|
6
|
+
message: >-
|
|
7
|
+
This Spring Security filter chain authorizes EVERY request
|
|
8
|
+
(`anyRequest().permitAll()`), so no endpoint behind it requires
|
|
9
|
+
authentication. If any protected resource is served by this chain, it is
|
|
10
|
+
now publicly reachable (CWE-862, Missing Authorization). Scope
|
|
11
|
+
`permitAll()` to the handful of genuinely public paths with
|
|
12
|
+
`requestMatchers(...)` and finish the chain with
|
|
13
|
+
`anyRequest().authenticated()` so anything you did not explicitly open
|
|
14
|
+
stays protected.
|
|
15
|
+
severity: ERROR
|
|
16
|
+
languages: [java]
|
|
17
|
+
metadata:
|
|
18
|
+
category: security
|
|
19
|
+
cwe:
|
|
20
|
+
- "CWE-862: Missing Authorization"
|
|
21
|
+
owasp:
|
|
22
|
+
- "A01:2021 - Broken Access Control"
|
|
23
|
+
subcategory: [vuln]
|
|
24
|
+
likelihood: MEDIUM
|
|
25
|
+
impact: HIGH
|
|
26
|
+
confidence: MEDIUM
|
|
27
|
+
technology: [java, spring]
|
|
28
|
+
patterns:
|
|
29
|
+
- pattern-either:
|
|
30
|
+
- pattern: $A.anyRequest().permitAll()
|
|
31
|
+
- pattern: $A.antMatchers("/**").permitAll()
|
|
32
|
+
- pattern: $A.requestMatchers("/**").permitAll()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
|
|
3
|
+
# Spring Boot config hardening (application.properties/.yml): actuator endpoints exposed, H2 web console on.
|
|
4
|
+
# Generic mode over *.properties/*.yml.
|
|
5
|
+
|
|
6
|
+
- id: narvy.java.spring.actuator-exposed-all.actuator-exposed-all
|
|
7
|
+
message: >-
|
|
8
|
+
`management.endpoints.web.exposure.include` is set to `*`, which exposes
|
|
9
|
+
EVERY actuator endpoint over HTTP - including `/actuator/env`,
|
|
10
|
+
`/actuator/heapdump`, `/actuator/threaddump` and, when Spring Boot Admin
|
|
11
|
+
or the loggers endpoint is present, remote configuration changes. These
|
|
12
|
+
leak environment variables, secrets and internal state, and several are
|
|
13
|
+
write-capable (CWE-200, CWE-16). Expose only the endpoints you actually
|
|
14
|
+
need (typically `health,info`) and secure the management port/context
|
|
15
|
+
behind authentication.
|
|
16
|
+
severity: WARNING
|
|
17
|
+
languages: [generic]
|
|
18
|
+
paths:
|
|
19
|
+
include:
|
|
20
|
+
- "*.properties"
|
|
21
|
+
- "*.yml"
|
|
22
|
+
- "*.yaml"
|
|
23
|
+
- "*.conf"
|
|
24
|
+
metadata:
|
|
25
|
+
category: security
|
|
26
|
+
cwe:
|
|
27
|
+
- "CWE-200: Exposure of Sensitive Information to an Unauthorized Actor"
|
|
28
|
+
owasp:
|
|
29
|
+
- "A05:2021 - Security Misconfiguration"
|
|
30
|
+
subcategory: [audit]
|
|
31
|
+
likelihood: MEDIUM
|
|
32
|
+
impact: MEDIUM
|
|
33
|
+
confidence: HIGH
|
|
34
|
+
technology: [java, spring, spring-boot]
|
|
35
|
+
patterns:
|
|
36
|
+
- pattern-regex: 'management\.endpoints\.web\.exposure\.include\s*[:=]\s*["'']?\*'
|
|
37
|
+
|
|
38
|
+
- id: narvy.java.spring.h2-console-enabled.h2-console-enabled
|
|
39
|
+
message: >-
|
|
40
|
+
The H2 database web console is enabled (`spring.h2.console.enabled=true`).
|
|
41
|
+
The console is an unauthenticated servlet by default that runs arbitrary
|
|
42
|
+
SQL - and, through H2's `CREATE ALIAS ... AS` / `RUNSCRIPT` features, can
|
|
43
|
+
reach arbitrary Java code, making an exposed console a remote-code-
|
|
44
|
+
execution path (CWE-489, CWE-16). Never enable it outside local
|
|
45
|
+
development; if it must be on in a shared environment, restrict its
|
|
46
|
+
path to localhost and put it behind authentication.
|
|
47
|
+
severity: WARNING
|
|
48
|
+
languages: [generic]
|
|
49
|
+
paths:
|
|
50
|
+
include:
|
|
51
|
+
- "*.properties"
|
|
52
|
+
- "*.yml"
|
|
53
|
+
- "*.yaml"
|
|
54
|
+
- "*.conf"
|
|
55
|
+
metadata:
|
|
56
|
+
category: security
|
|
57
|
+
cwe:
|
|
58
|
+
- "CWE-489: Active Debug Code"
|
|
59
|
+
owasp:
|
|
60
|
+
- "A05:2021 - Security Misconfiguration"
|
|
61
|
+
subcategory: [audit]
|
|
62
|
+
likelihood: MEDIUM
|
|
63
|
+
impact: HIGH
|
|
64
|
+
confidence: HIGH
|
|
65
|
+
technology: [java, spring, spring-boot, h2]
|
|
66
|
+
patterns:
|
|
67
|
+
- pattern-regex: 'spring\.h2\.console\.enabled\s*[:=]\s*true'
|