Java / Spring source review
When it applies
Reviewing Java source, most often a Spring/Spring Boot service. Java's biggest hitters are
deserialization, XXE-by-default, and expression-language injection — all high impact and all
grep-able.
Why it works
Several Java APIs are unsafe by default (XML parsers resolve external entities; ObjectInputStream
instantiates arbitrary classes) and frameworks expose powerful expression languages (SpEL/OGNL) that
turn a string into code. Tracing the source to a request parameter or message body confirms reach.
Sinks & patterns (grep, then trace to user input)
- Deserialization:
ObjectInputStream.readObject, Jackson enableDefaultTyping/polymorphic
types, XMLDecoder, SnakeYAML new Yaml().load, unsafe readValue with type info → RCE gadgets.
- XXE:
DocumentBuilderFactory, SAXParser, XMLInputFactory, TransformerFactory without
setFeature(disallow-doctype)/secure-processing.
- Command exec:
Runtime.getRuntime().exec, ProcessBuilder with concatenated input.
- Expression injection: SpEL (
SpelExpressionParser, @Value("#{...}") on input), OGNL
(Struts), MVEL; template engines with unescaped output.
- SQL/HQL:
Statement/string-built queries, createQuery with concatenation.
- SSRF:
URL.openConnection, RestTemplate, HttpClient, WebClient on user URLs.
- JNDI:
InitialContext.lookup, log4j-style ${jndi:...} (Log4Shell) reachable from input.
Framework specifics
- Spring: mass assignment via
@ModelAttribute/DataBinder (missing setAllowedFields),
exposed/unsecured Actuator endpoints, @RequestMapping path traversal, permit-all misconfig in
SecurityFilterChain, SpEL in @PreAuthorize.
- Struts/older MVC: OGNL injection (S2-* CVEs).
Method
rg for the sinks; trace to controller params, headers, or message consumers.
- Check XML parser factory configuration everywhere XML is read.
- Review the Spring Security config for accidental
permitAll()/disabled CSRF on state-changing routes.
- Confirm with
web-deserialization, web-xxe, web-ssrf, or web-command-injection.
Gotchas
- Jackson is safe unless default/polymorphic typing is enabled — check for it specifically.
find-sec-bugs/CodeQL surface candidates; you still must prove input reaches the sink.
- Log4Shell-style lookups can fire from headers (User-Agent, X-Forwarded-For), not just body.
References
OWASP Deserialization & XXE cheat sheets; SpEL/OGNL injection research; find-sec-bugs rules.
1---2name: code-review-java3description: Security review of Java code — dangerous sinks and Spring pitfalls. Load when reviewing a Java/ Spring codebase/PR, on .java source in scope, or "review this Java". Signals: pom.xml/build.gradle, Spring/Spring Boot, ObjectInputStream, XML parsers, Runtime.exec, JNDI/lookups.4---56# Java / Spring source review78## When it applies9Reviewing Java source, most often a Spring/Spring Boot service. Java's biggest hitters are10deserialization, XXE-by-default, and expression-language injection — all high impact and all11grep-able.1213## Why it works14Several Java APIs are unsafe by default (XML parsers resolve external entities; `ObjectInputStream`15instantiates arbitrary classes) and frameworks expose powerful expression languages (SpEL/OGNL) that16turn a string into code. Tracing the source to a request parameter or message body confirms reach.1718## Sinks & patterns (grep, then trace to user input)19- **Deserialization**: `ObjectInputStream.readObject`, Jackson `enableDefaultTyping`/polymorphic20 types, XMLDecoder, SnakeYAML `new Yaml().load`, unsafe `readValue` with type info → RCE gadgets.21- **XXE**: `DocumentBuilderFactory`, `SAXParser`, `XMLInputFactory`, `TransformerFactory` without22 `setFeature(disallow-doctype)`/secure-processing.23- **Command exec**: `Runtime.getRuntime().exec`, `ProcessBuilder` with concatenated input.24- **Expression injection**: SpEL (`SpelExpressionParser`, `@Value("#{...}")` on input), OGNL25 (Struts), MVEL; template engines with unescaped output.26- **SQL/HQL**: `Statement`/string-built queries, `createQuery` with concatenation.27- **SSRF**: `URL.openConnection`, `RestTemplate`, `HttpClient`, `WebClient` on user URLs.28- **JNDI**: `InitialContext.lookup`, log4j-style `${jndi:...}` (Log4Shell) reachable from input.2930## Framework specifics31- **Spring**: mass assignment via `@ModelAttribute`/`DataBinder` (missing `setAllowedFields`),32 exposed/unsecured Actuator endpoints, `@RequestMapping` path traversal, permit-all misconfig in33 `SecurityFilterChain`, SpEL in `@PreAuthorize`.34- **Struts/older MVC**: OGNL injection (S2-* CVEs).3536## Method371. `rg` for the sinks; trace to controller params, headers, or message consumers.382. Check XML parser factory configuration everywhere XML is read.393. Review the Spring Security config for accidental `permitAll()`/disabled CSRF on state-changing routes.404. Confirm with `web-deserialization`, `web-xxe`, `web-ssrf`, or `web-command-injection`.4142## Gotchas43- Jackson is safe unless default/polymorphic typing is enabled — check for it specifically.44- `find-sec-bugs`/CodeQL surface candidates; you still must prove input reaches the sink.45- Log4Shell-style lookups can fire from headers (User-Agent, X-Forwarded-For), not just body.4647## References48OWASP Deserialization & XXE cheat sheets; SpEL/OGNL injection research; find-sec-bugs rules.