JVM (Java, Kotlin, Scala)
Full Application Reachability setup guide for JVM projects. Covers Gradle, Maven, and sbt.
This guide covers Full Application Reachability (previously Tier 1) via the
--reachflag. Precomputed and dependency reachability apply automatically in the Dashboard without CLI flags. For an overview of all reachability types, see the Reachability Analysis overview.
Socket supports Full Application Reachability for the following JVM build tools:
Prerequisites
Install Socket CLI:
npm install -g socket
socket loginOr set API key:
export SOCKET_SECURITY_API_TOKEN=sktsec_<your_key>Note:
socket scan createrequires an org slug. Runsocket loginto set a default, or pass--org <your-org-slug>on every command.
Runtime requirements for Full Application Reachability:
- Java 8 to 27. Your build tool runs with your
JAVA_HOME, so use a JDK your Gradle, Maven, or sbt version supports. - With
--dynamic-sbom-inference: the Java version and build tool your project builds with (Gradle, Maven, or sbt, or the project's wrapper), installed and onPATH
Note: Java, Kotlin, and Scala are statically typed, making reachability analysis faster and less resource-intensive than dynamic languages. 8 GB RAM is typically sufficient.
Recommended: --dynamic-sbom-inference
--dynamic-sbom-inferenceFor any Gradle, Maven, or sbt project, add --dynamic-sbom-inference to your scans. It has your build tool generate a Socket facts file (written to each build root, with a name ending in .socket.facts.json, such as gradle.socket.facts.json or pom.xml.socket.facts.json) as part of the scan, covering every JVM build under the scan target rather than only the one at the root. This gives you:
- Per-subproject analysis: reachability is analyzed and reported per subproject, including multi-module builds and repositories with several independent builds.
- More accurate results: the dependency graph comes from the graph your own build resolves, including where each dependency lives.
If no Gradle, Maven, or sbt build is found under the target, the scan stops with an error. Either point the scan at the right directory (use --cwd), or drop the flag.
Note:
--dynamic-sbom-inferencealso covers .NET projects. To limit it to JVM builds in a mixed repository, add--dynamic-sbom-inference-ecosystems maven. The generated facts files stay in your working tree after the scan; commit them, or ignore them with a pattern such as*.socket.facts.json.
To generate the facts files yourself instead of during the scan:
socket manifest dynamic-sbom-inferenceThis resolves the full dependency tree for each build and writes a Socket facts file to its root directory. For a single build, use socket manifest gradle, socket manifest maven, or socket manifest scala in the build directory. See socket manifest dynamic-sbom-inference --help for the available flags.
Gradle
Step 1: Prepare the Dependency Manifest
The recommended approach is to add --dynamic-sbom-inference to the scans in Steps 2 and 3. No separate step is needed.
Note: If your project commits a
gradle.lockfile(or uses alibs.versions.tomlversion catalog), Socket can read it directly, so the scan works without--dynamic-sbom-inference. The flag is still recommended: a committed file records versions captured at some earlier point and no artifact locations, so it can drift from what your build resolves today, and you give up the per-subproject analysis. See the Gradle setup instructions for the trade-offs.
CycloneDX alternative: If you prefer a CycloneDX SBOM, run
socket cdxgen -t gradle -o socket-gradle.cdx.json --install-deps --lifecycle build. Without--lifecycle build, cdxgen defaults topre-buildto avoid arbitrary code execution; use--lifecycle buildfor a complete dependency graph that includes build-time resolved dependencies.
Step 2: Run Baseline Scan
Scan without reachability to establish a baseline CVE count. Use --dynamic-sbom-inference here too, so the baseline uses the same dependency graph as the reachability scan:
socket scan create --dynamic-sbom-inference .Note the total CVE count.
Step 3: Run Reachability Scan
socket scan create --reach --dynamic-sbom-inference .Socket performs function-level reachability analysis to determine which CVEs are exploitable. The project does not need to be compiled first. Analysis runs on source, but uses class files when found (useful for builds that generate code at compile time).
To run reachability analysis locally without creating a scan (manifest files are still uploaded to build the dependency graph):
socket scan reach --dynamic-sbom-inferenceResults are saved to .socket.facts.json. Useful for sensitive codebases.
Note: Delete
.socket.facts.jsonbefore runningsocket scan createwithout--reach. Otherwise it is uploaded as an SBOM carrying stale reachability results.
Maven
Step 1: Prepare the Dependency Manifest
Socket reads pom.xml directly, so a basic scan works without generating anything. For Full Application Reachability, add --dynamic-sbom-inference to the scans in Steps 2 and 3. It resolves the dependency graph with Maven itself, which handles BOMs, parent POMs, and profiles more accurately than reading pom.xml alone.
CycloneDX alternative:
socket cdxgen -t maven -o socket-maven.cdx.json --install-deps --lifecycle build
Step 2: Run Baseline Scan
socket scan create --dynamic-sbom-inference .Note the total CVE count.
Step 3: Run Reachability Scan
socket scan create --reach --dynamic-sbom-inference .Socket performs function-level reachability analysis to determine which CVEs are exploitable. The project does not need to be compiled first. Analysis runs on source, but uses class files when found.
To run reachability analysis locally without creating a scan (manifest files are still uploaded to build the dependency graph):
socket scan reach --dynamic-sbom-inferenceResults are saved to .socket.facts.json.
Note: Delete
.socket.facts.jsonbefore runningsocket scan createwithout--reach. Otherwise it is uploaded as an SBOM carrying stale reachability results.
sbt
Additional prerequisites:
- sbt installed and on
PATH. Manifest generation invokessbtto resolve dependencies. - sbt 1.x builds only. sbt 2.x builds (
sbt.version=2.x) are not yet supported. If your installed sbt launcher is 2.x, make sureproject/build.propertiespins an sbt 1.x version.
Step 1: Prepare the Dependency Manifest
sbt projects need a generated dependency manifest for Full Application Reachability. The recommended approach is to add --dynamic-sbom-inference to the scans in Steps 2 and 3.
To generate it yourself for a single build, run socket manifest scala in the build directory.
CycloneDX alternative:
socket cdxgen -t sbt -o socket-sbt.cdx.json --install-deps --lifecycle build. Without--lifecycle build, cdxgen defaults topre-buildto avoid arbitrary code execution.
Step 2: Run Baseline Scan
socket scan create --dynamic-sbom-inference .Note the total CVE count.
Step 3: Run Reachability Scan
socket scan create --reach --dynamic-sbom-inference .Socket performs function-level reachability analysis to determine which CVEs are exploitable. The project does not need to be compiled first.
To run reachability analysis locally without creating a scan (manifest files are still uploaded to build the dependency graph):
socket scan reach --dynamic-sbom-inferenceResults are saved to .socket.facts.json.
Note: Delete
.socket.facts.jsonbefore runningsocket scan createwithout--reach. Otherwise it is uploaded as an SBOM carrying stale reachability results.
Performance Tuning
For large projects with any build tool, adjust these flags as needed:
socket scan create --reach --dynamic-sbom-inference \
--reach-analysis-timeout 20m \
--reach-analysis-memory-limit 32GB \
--reach-concurrency 4 \
.| Flag | Default | Description |
|---|---|---|
--reach-analysis-timeout | 10m | Per-run analysis timeout; specify with an s, m, or h unit (e.g. 90s, 10m, 1h) |
--reach-analysis-memory-limit | 8GB | Per-run memory limit; specify with an MB or GB unit (e.g. 512MB, 8GB); 16–32 GB recommended for large projects |
--reach-concurrency | 1 | Maximum concurrent analysis runs (one per project or workspace); give each run at least --reach-analysis-memory-limit of memory |
Interpreting Results
View scan results in Socket Dashboard and filter by reachability status.
The CLI outputs a summary table per ecosystem, including a Noise% column:
Project │ Vulns │ Reach │ Unreach │ NoSup │ NoReach │ Skipped │ Error │ Noise% │ Time
You can also calculate noise reduction manually:
Noise% = ((Unreachable + NoSup + NoReach) / Total Vulns) × 100
Result Categories
| Column | Meaning |
|---|---|
| Reach | Call chain exists from app code to vulnerable function |
| Unreach | No exploitable call chain; safe to ignore |
| NoSup | Socket hasn't classified the vulnerable functions for this CVE yet |
| NoReach | Reachability analysis not possible for this vulnerability |
| Skipped | Filtered out via --exclude-paths or other options |
| Error | Analysis error; check logs or contact support |
| Noise% | Percentage of vulns filtered as non-reachable |
In the Dashboard, additional statuses appear: Potentially Reachable (precomputed reachability indirect chain), Pending Precomputation (precomputed reachability processing), Not Determinable, and Unknown.
Triage Reachable CVEs
Review CVEs marked as "Reachable" in Dashboard. For each:
- Check severity and CVSS score
- Evaluate upgrade path
- Prioritize remediation
Override Unreachable CVEs (Optional)
For unreachable CVEs with low business impact, click Override in Dashboard to suppress from future scans.
Updated about 13 hours ago