a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
203 lines
7.9 KiB
Go
203 lines
7.9 KiB
Go
package astquery
|
|
|
|
// Java SAST starter pack. The legacy `java-string-equality` +
|
|
// `empty-catch` rules in detectors.go cover language-level pitfalls;
|
|
// this file adds JVM security patterns the SAST audit looks for.
|
|
|
|
func init() {
|
|
registerJavaCommandExecution()
|
|
registerJavaWeakCrypto()
|
|
registerJavaInsecureSSL()
|
|
registerJavaXMLDecoder()
|
|
registerJavaSQLConcat()
|
|
registerJavaRandom()
|
|
registerJavaJWTNone()
|
|
registerJavaServletXSS()
|
|
registerJavaProcessBuilder()
|
|
registerJavaTrustAllCerts()
|
|
registerJavaSecretLiteralAnnotation()
|
|
}
|
|
|
|
func registerJavaCommandExecution() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-runtime-exec",
|
|
Description: "`Runtime.getRuntime().exec(cmd)` with a string argument — the JDK splits on whitespace, which silently quoting bugs become argv-injection bugs. Use the String[] overload or `ProcessBuilder`.",
|
|
Severity: "error",
|
|
CWE: "CWE-78",
|
|
OWASP: "A03:2021-Injection",
|
|
Tags: []string{"command-injection"},
|
|
Pat: map[string]string{
|
|
"java": `((method_invocation
|
|
object: (method_invocation
|
|
object: (identifier) @rt
|
|
name: (identifier) @getrt)
|
|
name: (identifier) @exec) @match
|
|
(#eq? @rt "Runtime") (#eq? @getrt "getRuntime") (#eq? @exec "exec"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaProcessBuilder() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-process-builder-shell-args",
|
|
Description: "`new ProcessBuilder(\"sh\", \"-c\", cmd).start()` — shell argv 0 with a user-controlled `cmd` arg is command injection.",
|
|
Severity: "warning",
|
|
CWE: "CWE-78",
|
|
Tags: []string{"command-injection"},
|
|
Pat: map[string]string{
|
|
"java": `((object_creation_expression
|
|
type: (type_identifier) @typ
|
|
arguments: (argument_list (string_literal) @shell)) @match
|
|
(#eq? @typ "ProcessBuilder")
|
|
(#match? @shell "\"(sh|bash|zsh|cmd|powershell)\""))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaWeakCrypto() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-message-digest-md5-sha1",
|
|
Description: "`MessageDigest.getInstance(\"MD5\")` / `\"SHA-1\")` — broken hashes. Use `\"SHA-256\"` / `\"SHA-512\"` / `\"SHA3-256\"`.",
|
|
Severity: "error",
|
|
CWE: "CWE-327",
|
|
Tags: []string{"crypto", "weak-hash"},
|
|
Pat: map[string]string{
|
|
"java": `((method_invocation
|
|
object: (identifier) @cls
|
|
name: (identifier) @fn
|
|
arguments: (argument_list (string_literal) @algo)) @match
|
|
(#eq? @cls "MessageDigest") (#eq? @fn "getInstance")
|
|
(#match? @algo "\"(MD5|MD4|MD2|SHA-1|SHA1)\""))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaInsecureSSL() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-cipher-des-ecb",
|
|
Description: "`Cipher.getInstance(\"DES\")` / `Cipher.getInstance(\"AES/ECB/...\")` — DES is broken; ECB doesn't hide plaintext patterns. Use `AES/GCM/NoPadding` or `ChaCha20-Poly1305`.",
|
|
Severity: "error",
|
|
CWE: "CWE-327",
|
|
Tags: []string{"crypto", "weak-cipher"},
|
|
Pat: map[string]string{
|
|
"java": `((method_invocation
|
|
object: (identifier) @cls
|
|
name: (identifier) @fn
|
|
arguments: (argument_list (string_literal) @algo)) @match
|
|
(#eq? @cls "Cipher") (#eq? @fn "getInstance")
|
|
(#match? @algo "\"(DES|DESede|RC2|RC4|.*/ECB/.*)\""))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaXMLDecoder() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-xml-decoder",
|
|
Description: "`new XMLDecoder(stream).readObject()` — XMLDecoder deserialises arbitrary Java objects, equivalent to `ObjectInputStream`. Untrusted input is RCE.",
|
|
Severity: "error",
|
|
CWE: "CWE-502",
|
|
Tags: []string{"deserialization"},
|
|
Pat: map[string]string{
|
|
"java": `((object_creation_expression type: (type_identifier) @typ) @match (#eq? @typ "XMLDecoder"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaSQLConcat() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-statement-execute-concat",
|
|
Description: "`statement.execute(\"SELECT ... \" + x)` / `executeQuery(...)` with `+` concat — SQL injection. Use `PreparedStatement` with `?` placeholders.",
|
|
Severity: "error",
|
|
CWE: "CWE-89",
|
|
OWASP: "A03:2021-Injection",
|
|
Tags: []string{"sqli"},
|
|
Pat: map[string]string{
|
|
"java": `((method_invocation
|
|
name: (identifier) @fn
|
|
arguments: (argument_list (binary_expression operator: "+"))) @match
|
|
(#match? @fn "^(execute|executeQuery|executeUpdate|prepareStatement)$"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaRandom() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-random-for-token",
|
|
Description: "`new Random()` — Mersenne Twister; not crypto-secure. Use `java.security.SecureRandom` for tokens / IVs / keys.",
|
|
Severity: "info",
|
|
CWE: "CWE-338",
|
|
Tags: []string{"crypto", "audit-hook"},
|
|
Pat: map[string]string{
|
|
"java": `((object_creation_expression type: (type_identifier) @typ) @match (#eq? @typ "Random"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaJWTNone() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-jwt-none-alg",
|
|
Description: "`Algorithm.none()` (auth0/java-jwt) / `\"none\"` algorithm string — accepts unsigned JWTs. Trivial impersonation.",
|
|
Severity: "error",
|
|
CWE: "CWE-347",
|
|
Tags: []string{"jwt", "broken-auth"},
|
|
Pat: map[string]string{
|
|
"java": `((method_invocation
|
|
object: (identifier) @alg
|
|
name: (identifier) @fn) @match
|
|
(#eq? @alg "Algorithm") (#eq? @fn "none"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaServletXSS() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-response-write-user-input",
|
|
Description: "`response.getWriter().write(request.getParameter(...))` — reflected XSS unless the writer is HTML-escaped. Use a templating engine or `org.owasp.encoder.Encode.forHtml`.",
|
|
Severity: "info",
|
|
CWE: "CWE-79",
|
|
Tags: []string{"xss", "audit-hook"},
|
|
Pat: map[string]string{
|
|
"java": `((method_invocation
|
|
object: (method_invocation name: (identifier) @writer)
|
|
name: (identifier) @write
|
|
arguments: (argument_list (method_invocation name: (identifier) @src))) @match
|
|
(#eq? @writer "getWriter") (#eq? @write "write") (#match? @src "^getParameter|getHeader|getQueryString$"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerJavaTrustAllCerts() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-trust-all-certs",
|
|
Description: "Custom `X509TrustManager` whose `checkServerTrusted` does nothing — accepts every certificate, defeating TLS verification.",
|
|
Severity: "error",
|
|
CWE: "CWE-295",
|
|
Tags: []string{"tls", "no-verify"},
|
|
Pat: map[string]string{
|
|
"java": `((method_declaration
|
|
name: (identifier) @fn
|
|
body: (block) @body) @match
|
|
(#eq? @fn "checkServerTrusted"))`,
|
|
// Empty-body heuristic via PostFilter.
|
|
},
|
|
// Filter out methods with non-trivial bodies; defaults catch
|
|
// {} / { return; } / { /* ... */ }.
|
|
})
|
|
}
|
|
|
|
func registerJavaSecretLiteralAnnotation() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "java-spring-value-hardcoded-secret",
|
|
Description: "`@Value(\"static-literal-secret\")` — Spring `@Value` annotation with a literal that names a credential. Move to env / a `@ConfigurationProperties` mapper backed by env / a secrets manager.",
|
|
Severity: "warning",
|
|
CWE: "CWE-798",
|
|
Tags: []string{"secrets", "spring"},
|
|
Pat: map[string]string{
|
|
"java": `((annotation
|
|
name: (identifier) @ann
|
|
arguments: (annotation_argument_list (string_literal) @val)) @match
|
|
(#eq? @ann "Value") (#match? @val "[\"'][^${].{20,}[\"']"))`,
|
|
},
|
|
})
|
|
}
|