Both wrappers fetch the build tool for you, so both are places where a swapped download could run on your machines. Each lets you pin SHA-256 checksums in a properties file: Gradle verifies the distribution, and Maven can verify both the distribution and the wrapper JAR. Turn those on and review wrapper changes like code.
Why pin the build tool at all
A wrapper script makes builds consistent: everyone uses the project's chosen version, downloaded on first use. The Maven documentation describes it exactly this way. The cost is that your build now begins by downloading and running something. If that file can be altered in transit or in the repository, the attacker runs before any of your other controls start.
Side by side
| Maven Wrapper | Gradle Wrapper | |
|---|---|---|
| Properties file | .mvn/wrapper/maven-wrapper.properties | gradle/wrapper/gradle-wrapper.properties |
| Distribution checksum | distributionSha256Sum | distributionSha256Sum |
| Wrapper JAR checksum | wrapperSha256Sum | Checked against Gradle's published JAR checksums, or by the Setup Gradle action |
| Binary in repo | Optional: bin type adds a JAR, other types do not | The wrapper JAR is usually committed |
| Custom download location | distributionUrl, or MVNW_REPOURL | distributionUrl |
What the Maven documentation says
The Maven Wrapper page states that to avoid supply chain attacks by downloading a corrupted artifact, you can specify checksums for both the maven-wrapper.jar and the downloaded distribution. Add the expected SHA-256 in lowercase hex notation to maven-wrapper.properties. The JAR property is wrapperSha256Sum and the distribution property is distributionSha256Sum.
Maven also gives you a way to avoid a committed binary. It describes types: bin adds the JAR, source adds a Java downloader file, script keeps only scripts, and the lite only-script type, which is the default and downloads Maven directly using wget or curl on Unix like systems or PowerShell on Windows. If your policy forbids binaries in the repository, choose a type without the JAR, and still pin the distribution checksum.
What the Gradle documentation says
Gradle's wrapper supports distributionSha256Sum, and the build fails if the checksum does not match the one found on the server. The documentation adds that the check only runs when the distribution has not yet been downloaded. For the wrapper JAR, Gradle publishes checksums of releases and the Setup Gradle GitHub action validates it automatically, with validation built in since version 4. Full steps are in how to stop a tampered gradle-wrapper.jar.
A shared checklist
- Pin the distribution checksum in the wrapper properties.
- For Maven, also set wrapperSha256Sum if you keep the JAR.
- For Gradle, validate the wrapper JAR in CI on every pull request.
- Download from an HTTPS address. If you use an internal repository manager, Maven supports pointing the wrapper at it through MVNW_REPOURL or by setting the URLs in the properties file.
- Require code owner review on the wrapper directory.
- Update the checksum in the same pull request as any version bump, and have a reviewer confirm the new value against the official published one.
A common mistake
Copying the checksum from the same place you downloaded the file proves little. Take the hash from the project's official release page, over HTTPS, and compare. Make it a habit to read the diff in a properties file as carefully as a code change, because it is one.
Safeguard dependency scanning covers the libraries your Java builds resolve, and policies and gates can block a pull request that changes them unexpectedly. Free scan: gold.safeguard.sh/scan.
Quick check
Do I still need a checksum if I use an internal repository manager?
It is still a good control. It protects against a bad file served from your own manager and against a changed URL in the properties file.
Can I avoid committing a wrapper JAR?
With Maven, yes: the script and only-script types do not add the JAR. Gradle's wrapper normally includes one, so validate it.
Sources
Last reviewed: 19 October 2026.