Java and Spring
Vulkro does full source analysis for Java, with first-class Spring Boot support. It extracts your endpoint map, reads the access-control model off the annotations and the security filter chain, runs 30 dedicated Java detectors, tracks request data through same-file call chains to dangerous sinks, and matches your Maven dependencies against the local CVE bundle.
Java is part of the Pro tier. Because your first vulkro login starts a
14-day trial of the full product, you can scan Java from day one. The Free
tier covers Python, JavaScript, TypeScript, and Go; Java, Kotlin, C#, PHP,
Ruby, and Apex are in Pro.
Project detection
Vulkro recognises a Java project from its build files:
pom.xml(Maven)build.gradle(Gradle, Groovy DSL)build.gradle.kts(Gradle, Kotlin DSL)
Spring Boot is recognised from the dependency coordinates in those files:
org.springframework.boot, spring-boot-starter, spring-web, and
spring-webmvc. When those markers are present, endpoint and access-control
extraction turn on automatically.
Run a scan with no extra flags:
vulkro scan .
To see the endpoint map first, without running the security passes:
vulkro discover .
vulkro discover . --format json
Endpoint extraction
Vulkro reads the route table straight from the annotations. For Spring MVC and Spring WebFlux it understands the six mapping annotations:
@GetMapping@PostMapping@PutMapping@DeleteMapping@PatchMapping@RequestMapping(including themethod = RequestMethod.*form)
Class-level @RequestMapping base paths are combined with the method-level
mapping, so the recorded path matches what the server actually serves. A
controller annotated @RequestMapping("/api/users") with a method
@GetMapping("/{id}") is recorded as GET /api/users/{id}.
For JAX-RS (Jakarta / Java EE REST) it reads @Path together with the method
annotations @GET, @POST, @PUT, @DELETE, @PATCH, @HEAD, and
@OPTIONS.
Access-control extraction
For each endpoint, Vulkro determines whether an access-control gate is present and what it requires. It reads:
- Method-security annotations:
@PreAuthorize,@PostAuthorize,@Secured,@RolesAllowed,@PermitAll,@DenyAll. - SpEL role expressions inside those annotations:
hasRole(...),hasAnyRole(...),hasAuthority(...),hasAnyAuthority(...). - The
HttpSecurityfilter-chain DSL:requestMatchers(...),antMatchers(...),mvcMatchers(...), andanyRequest()chained topermitAll(),authenticated(),hasRole(...), and the rest of the authorization terminals.
The result is a per-endpoint protected / unprotected status, the same shape Vulkro builds for every other language. Java endpoints then flow into the language-agnostic OWASP API Top 10 endpoint checks:
- API1 (BOLA / IDOR) - object-reference handlers without an ownership or tenant gate.
- API2 (broken authentication) - endpoints reachable with no access-control gate.
- API4 (unrestricted resource consumption) - list endpoints without pagination.
- API9 (improper inventory) - the discovered surface as an inventory input.
See OWASP API Top 10.
Detector families
Vulkro ships 30 dedicated Java detectors, each with its own finding ID. Every
one carries a finding-level message and remediation you can read with
vulkro explain <ID>. The descriptions below are of detector behaviour; the
detection logic itself is not published.
Injection
| ID | What it flags |
|---|---|
JAVA-SQLI-001 | Request data concatenated into a JDBC Statement / string-built query instead of a PreparedStatement bind. |
JAVA-CMDI-001 | Untrusted data reaching Runtime.exec / ProcessBuilder command construction. |
JAVA-LDAP-001 | Untrusted data in an LDAP search filter without escaping. |
JAVA-XPATH-001 | Untrusted data concatenated into an XPath expression. |
JAVA-SPEL-001 | Untrusted data evaluated as a Spring Expression Language (SpEL) expression. |
JAVA-SCRIPT-001 | Untrusted data passed to a ScriptEngine (eval) invocation. |
JAVA-JNDI-001 | Untrusted data in a JNDI lookup (the log4shell-shaped sink). |
JAVA-REFLECT-001 | Untrusted data driving reflective class / method resolution. |
JAVA-NOSQL-001 | Untrusted data in a NoSQL query (MongoDB and similar). |
JAVA-XSS-001 | Untrusted data written into an HTML response or template without encoding. |
JAVA-CRLF-001 | Untrusted data in a response header or redirect target (header / response splitting). |
JAVA-REDIRECT-001 | Untrusted data driving a redirect destination (open redirect). |
JAVA-SSRF-001 | Untrusted data driving an outbound HTTP request URL. |
JAVA-REDOS-001 | A user-influenced regular expression prone to catastrophic backtracking. |
Deserialization and XML
| ID | What it flags |
|---|---|
JAVA-DESER-001 | Native Java deserialization of untrusted bytes (ObjectInputStream.readObject and the well-known gadget-chain sinks). |
JAVA-XXE-001 | XML parser configured without disabling external entities (XXE). |
Cryptography and TLS
| ID | What it flags |
|---|---|
JAVA-CRYPTO-001 | Weak or misused cryptographic primitives (broken ciphers / hashes, ECB mode, static IV). |
JAVA-TLS-001 | Disabled certificate or hostname verification (trust-all TrustManager / HostnameVerifier). |
JAVA-RANDOM-001 | java.util.Random used for security-sensitive values instead of SecureRandom. |
JAVA-JWT-001 | JWT parsing without signature verification, or an insecure signing configuration. |
JAVA-TIMING-001 | Non-constant-time comparison of secrets / tokens. |
Session and cookies
| ID | What it flags |
|---|---|
JAVA-COOKIE-001 | Cookies set without the Secure / HttpOnly flags. |
Spring and framework configuration
| ID | What it flags |
|---|---|
JAVA-SECCONF-001 | Insecure Spring Security configuration (for example CSRF disabled, or a permissive filter chain). |
JAVA-ACTUATOR-001 | Spring Boot Actuator endpoints exposed without access control. |
JAVA-CORS-001 | Over-permissive CORS configuration (wildcard origin with credentials). |
Information exposure
| ID | What it flags |
|---|---|
JAVA-ERROR-001 | Stack traces or internal error detail returned to the client. |
File handling
| ID | What it flags |
|---|---|
JAVA-PATH-001 | Untrusted data in a filesystem path (path traversal). |
JAVA-FILEPERM-001 | Files created with overly broad permissions. |
JAVA-TOCTOU-001 | A check-then-use gap on a filesystem resource (time-of-check to time-of-use). |
JAVA-MASSASSIGN-001 | Request bodies bound directly onto persistence entities (mass assignment / over-posting). |
Java code is also covered by the language-agnostic
trust-boundary check (TRUST-BOUNDARY-001).
Cross-method taint tracking
Beyond the single-statement detectors, Vulkro runs an interprocedural taint pass for Java. It follows request-bound data from a source, through method calls within the same file, to a dangerous sink.
Sources it treats as user-controlled:
- Spring binding annotations on handler parameters:
@RequestParam,@PathVariable,@RequestBody,@RequestHeader,@CookieValue. - Servlet request objects typed
HttpServletRequest. - Servlet entry methods:
doGet,doPost,doPut,doDelete,service.
When tainted data reaches a sink through a chain of same-file calls, Vulkro
emits one of these rules, and the finding carries the source-to-sink hop chain
(rendered as SARIF codeFlows):
| ID | Sink class |
|---|---|
JAVA-TAINT-SQL-001 | SQL query construction |
JAVA-TAINT-CMDI-001 | Command execution |
JAVA-TAINT-PATH-001 | Filesystem path |
JAVA-TAINT-SSRF-001 | Outbound request URL |
JAVA-TAINT-DESER-001 | Deserialization |
JAVA-TAINT-REFLECT-001 | Reflective resolution |
JAVA-TAINT-MISC-001 | Other tracked sinks |
See Taint analysis for the cross-language view.
Honest limits
Stated plainly, so you know what the Java taint pass does and does not do:
- No cross-file taint. A flow is followed only within a single file. A controller that hands a request value to a service class in another file is still scanned in its own right, but the flow spanning both files is not stitched together.
- Spring bean wiring is not modelled as a flow. Constructor injection and
@Autowireddependencies are not followed as taint edges, so a controller-to-service call across files does not propagate taint. - Instance-field taint is not propagated. Tainting a field in one method and reading it in another is not tracked.
- Sanitiser detection is coarse. Recognition of encoders, validators, and parameter binding is pattern-based, not type-resolved.
These limits mean the taint pass under-reports rather than over-reports across file and object boundaries. The single-statement detectors above still fire independently of the taint pass.
Dependencies
Vulkro parses Maven pom.xml <dependencies> and matches them against the
local CVE bundle (OSV Maven ecosystem). Coordinates are keyed as
groupId:artifactId, and ${property} placeholders are resolved against
<properties>. Direct declared dependencies are covered; parent-POM
inheritance, <dependencyManagement> version pins, and transitive resolution
are out of scope, so a version managed by a parent POM or BOM (for example a
Spring Boot starter) is reported without a version and is not matched against
CVEs.
Gradle projects (build.gradle, build.gradle.kts) are detected as Java and
scanned for code, but their dependency declarations are not yet parsed for
CVE matching. If your CVE coverage depends on Gradle manifests, track that as a
gap. See Dependencies and CVEs.
Fully offline (VULKRO_OFFLINE=1) Maven matching additionally needs the
Maven ecosystem in the local CVE bundle; confirm your installed bundle
includes it before relying on offline Maven CVE matching.
Suppressing findings
Inline suppression works in Java comments:
// vulkro:disable next-line JAVA-SQLI-001
String q = "SELECT * FROM users WHERE id = " + id;
You can also suppress in vulkro.toml with an optional expiry. See the
suppressions guide for the full syntax.
Not yet in the benchmark
Java and Spring support is newer than Vulkro's published benchmark corpus, so it is not yet reflected in those precision / recall numbers - the corpus's Java repositories stay excluded from the roll-up pending a re-score. See the Benchmark page for what is and is not measured today.
Useful commands
vulkro scan . # full scan
vulkro scan ci . # CI preset (gate + fail-on critical/high)
vulkro discover . --format json # endpoint map only
vulkro dataflow . # input-to-sink data-flow document
vulkro explain JAVA-SQLI-001 # remediation guidance for a finding ID