Safeguard
Security

How to Verify Java Builds and Artifacts (java verify)

Verifying Java means more than running tests. It covers Maven's verify phase, JAR signature checks, and confirming dependency integrity before you ship.

Yukti Singhal
Platform Engineer
5 min read

To verify Java properly you need to check three distinct things: that your build passes integration-level quality gates, that the JARs you ship carry valid signatures, and that every dependency you pulled matches its published checksum. People say "java verify" to mean any of these, and conflating them leaves gaps. This guide separates them so you know which command answers which question.

Verification is a security concern, not just a quality one. A build that compiles and passes unit tests can still ship a tampered dependency or an unsigned JAR that a downstream consumer cannot trust. Let's take each layer in turn.

The Maven verify phase

If you run Maven, mvn verify refers to a specific point in the default build lifecycle. The phases run in order — validate, compile, test, package, integration-test, verify, install, deploy — and invoking a phase runs everything up to and including it.

mvn verify

Running verify gets you past unit tests (test) and into integration tests plus any checks bound to the verify phase. This is where plugins that enforce quality and security gates typically attach. For example, the failsafe plugin runs integration tests here, and coverage or dependency-analysis plugins commonly bind to verify so a failure blocks promotion to install/deploy.

A useful pattern is binding the OWASP Dependency-Check plugin to this phase so a build fails when a dependency carries a known CVE above your threshold:

<plugin>
  <groupId>org.owasp</groupId>
  <artifactId>dependency-check-maven</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>check</goal>
      </goals>
    </execution>
  </executions>
</plugin>

With that in place, mvn verify becomes a real security gate rather than just a test runner.

Verifying JAR signatures with jarsigner

The JDK ships jarsigner, the tool for signing JARs and for confirming a JAR's signature is intact. To check a signed JAR:

jarsigner -verify -verbose -certs app.jar

A trustworthy result prints jar verified. Pay attention to the warnings jarsigner emits even on a "verified" JAR — an expired certificate, a certificate chain that does not chain to a trusted root, or a signature that only covers some entries all weaken the guarantee. "Verified" means the signature is internally consistent, not that you trust the signer; you still have to decide whether the certificate is one you accept.

Signing matters most when you distribute artifacts that others execute. It lets a consumer confirm the JAR came from you and was not modified in transit or in a compromised repository.

Checking dependency integrity

The riskiest bytes in a Java build are usually the ones you did not write. When Maven or Gradle downloads a dependency, you want assurance that what landed in your local repository is what the upstream author published.

Both tools support checksum verification. Maven checks .sha1/.md5 files alongside artifacts by default, and you can make it strict:

mvn verify -C
# -C fails the build on a checksum mismatch instead of warning

Gradle takes this further with dependency verification metadata. You generate a verification-metadata.xml that records the expected checksums (and optionally PGP signatures) of every dependency, and Gradle refuses to build if anything drifts:

./gradlew --write-verification-metadata sha256 help

After that file is committed, any substituted or tampered dependency causes an immediate, loud failure. This is one of the strongest defenses available against a compromised artifact in a public repository.

Reproducible builds as verification

A build you can reproduce byte-for-byte is a build you can verify against someone else's copy. Maven supports reproducible builds by fixing timestamps and ordering:

<properties>
  <project.build.outputTimestamp>2025-01-01T00:00:00Z</project.build.outputTimestamp>
</properties>

When two independent builds of the same source produce identical artifacts, a mismatch anywhere becomes evidence of tampering or environmental drift. It turns "verify java build output" from a hope into a checkable property.

Generate an SBOM and monitor it

Verifying once at build time is necessary but not sufficient, because new vulnerabilities get disclosed against dependencies you already verified. Produce a software bill of materials during the build — the CycloneDX Maven plugin does this cleanly — and keep monitoring it:

mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom

An SBOM turns your dependency set into a durable, queryable record. When the next Log4j-scale advisory lands, you answer "are we affected?" in seconds instead of grepping build files across dozens of repositories. A software composition analysis tool such as Safeguard can ingest that SBOM and flag transitively vulnerable packages continuously. If you work with the Jackson data-binding stack, the Jackson databind security guide covers a family of deserialization issues worth verifying against specifically.

Putting it together in CI

A solid verification stage in CI does all of the above in sequence:

mvn verify -C \
  && jarsigner -verify target/app.jar \
  && mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom

That single gate confirms integration tests and dependency-check pass, the shipped JAR's signature is valid, checksums matched, and an SBOM was produced for downstream monitoring.

FAQ

What does mvn verify actually do?

It runs the Maven lifecycle up to and including the verify phase — compile, unit tests, packaging, integration tests, and any checks bound to verify, such as coverage thresholds or OWASP Dependency-Check. It is the natural place to enforce quality and security gates.

How do I verify a JAR is signed correctly?

Run jarsigner -verify -verbose -certs your.jar. Look for "jar verified" and read the warnings — an expired or untrusted certificate still lets a JAR report as verified, so confirm the signing certificate is one you trust.

How can I verify my dependencies were not tampered with?

Enable strict checksum verification (Maven's -C flag) and, for Gradle, generate and commit verification-metadata.xml with SHA-256 or PGP entries. The build then fails immediately if any downloaded artifact does not match its recorded checksum.

Is running unit tests enough to verify a Java build?

No. Tests confirm behavior, not integrity. A build can pass every test while shipping a tampered dependency or an unsigned artifact. Combine tests with checksum verification, signature checks, and dependency scanning for real verification.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.