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 --reach flag. 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 login

Or set API key:

export SOCKET_SECURITY_API_TOKEN=sktsec_<your_key>

Note: socket scan create requires an org slug. Run socket login to 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 on PATH

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

For 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-inference also 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-inference

This 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 a libs.versions.toml version 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 to pre-build to avoid arbitrary code execution; use --lifecycle build for 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-inference

Results are saved to .socket.facts.json. Useful for sensitive codebases.

Note: Delete .socket.facts.json before running socket scan create without --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-inference

Results are saved to .socket.facts.json.

Note: Delete .socket.facts.json before running socket scan create without --reach. Otherwise it is uploaded as an SBOM carrying stale reachability results.


sbt

Additional prerequisites:

  • sbt installed and on PATH. Manifest generation invokes sbt to 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 sure project/build.properties pins 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 to pre-build to 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-inference

Results are saved to .socket.facts.json.

Note: Delete .socket.facts.json before running socket scan create without --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 \
  .
FlagDefaultDescription
--reach-analysis-timeout10mPer-run analysis timeout; specify with an s, m, or h unit (e.g. 90s, 10m, 1h)
--reach-analysis-memory-limit8GBPer-run memory limit; specify with an MB or GB unit (e.g. 512MB, 8GB); 16–32 GB recommended for large projects
--reach-concurrency1Maximum 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

ColumnMeaning
ReachCall chain exists from app code to vulnerable function
UnreachNo exploitable call chain; safe to ignore
NoSupSocket hasn't classified the vulnerable functions for this CVE yet
NoReachReachability analysis not possible for this vulnerability
SkippedFiltered out via --exclude-paths or other options
ErrorAnalysis 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.


Did this page help you?