The maven-release-plugin has been around since 2006 and is still how a sizeable fraction of enterprise Java shops cut releases. It is venerable, thoroughly documented, and carrying a decade and a half of defaults that made sense when it was written and make less sense now. Hardening it is worthwhile because the plugin sits in the middle of the release path — it has access to signing keys, SCM credentials, and the artifact repository push credentials, and a compromise during release is unusually blast-radius-heavy.
What the plugin actually does during a release
Two phases. Prepare bumps versions, commits to SCM, and tags. Perform checks out the tag, runs the full build and deploy, and pushes artifacts to the repository. Each phase has credentials it uses and each is a potential attack surface.
Concretely, during perform you hold:
- SCM write credentials (for tagging)
- GPG signing key (for artifact signatures)
- Repository deploy credentials (for Maven Central, Artifactory, Nexus)
- Build environment credentials (anything your build needs)
A build server compromise during this phase gives the attacker all of these at once.
The first hardening: release from dedicated infrastructure
Releases should not run from developer laptops. They should not run from the same Jenkins agents that run regular CI. A dedicated release agent (or a GitHub Actions job, or a scheduled pipeline) with its own credentials and its own access boundaries makes the credential exposure traceable.
Specific configuration: restrict the deploy credentials (Maven Central, Artifactory) to be usable only from the release agent's IP range or OIDC identity. Rotate them independently of other CI credentials.
Signing keys belong in a KMS, not on disk
The common antipattern: GPG signing keys live as files on the release agent, encrypted with a passphrase stored in an environment variable. Multiple failure modes — snapshotting the disk captures the key, process-memory dumps capture the passphrase, and rotation is painful.
Better: keys in AWS KMS, GCP KMS, or HashiCorp Vault Transit, accessed via the appropriate provider plugin. The release agent never has the key material locally. Rotation is managed outside the build pipeline.
For Maven Central specifically, the older maven-gpg-plugin assumes local keys. Newer alternatives (such as the official Sonatype central-publishing-maven-plugin released in late 2023) support KMS-backed signing out of the box. If you are still using the legacy workflow, migration is 2024's right-sized project.
SCM hook verification prevents a class of tag attacks
The release plugin creates a tag in SCM and then the perform phase checks it out. If an attacker can push a malicious tag to the SCM between prepare and perform, they can substitute code into the release.
Three mitigations:
- Tag protection in SCM (GitHub branch/tag protection rules, GitLab protected tags). Only the release agent's identity can create tags matching the release pattern.
- Signed tags — GPG-signed, verified during perform.
- Minimum time between prepare and perform — so automated tag-push attacks have less of a window.
Repository deploy credentials scoped narrowly
Deploy credentials to Maven Central, Artifactory, or Nexus should be scoped per-group-id (for Central) or per-repo-path (for private). A single set of credentials that can deploy any artifact to any path in your Artifactory is a credential with too much blast radius.
Artifactory specifically supports permission targets that can be narrowed to group patterns. Use them. "Release agent can only deploy to com/mycompany/prod/*" is the right level of specificity.
Version declaration manipulation is a subtle risk
The plugin reads pom.xml, bumps versions, writes, commits. If an attacker can influence what's read — a malicious parent POM, a resolved property from an external source — the resulting release can carry unintended dependencies or versions.
Mitigation: pin parent POMs and plugin versions in the root POM. Do not use LATEST or RELEASE anywhere. Dependency management ranges (e.g., [2.0,3.0)) should be eliminated from released code in favor of exact versions.
Reproducibility is achievable but requires configuration
The maven-reproducible-builds initiative, led by Apache Maven committers, provides configuration for deterministic builds. A properly configured maven build produces bit-identical artifacts across runs, which means supply chain verification can compare your release against an independent build for drift detection.
The configuration steps:
<properties>
<project.build.outputTimestamp>2024-10-22T00:00:00Z</project.build.outputTimestamp>
</properties>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Version>${project.version}</Implementation-Version>
</manifestEntries>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
</plugin>
Combined with toolchain pinning (Maven Daemon with fixed JDK) and classpath-stable dependency resolution, you can achieve reproducible releases. The payoff is that independent rebuilds of your release produce the same hash, which is a property downstream consumers can verify.
Migration to the central-publishing-maven-plugin
As of late 2023, Sonatype officially recommends central-publishing-maven-plugin over the older staging workflow. The new plugin:
- Uses per-user-scoped tokens, not username/password
- Handles signing via external providers (KMS-friendly)
- Has clearer error messages when validation fails
Migration is straightforward — replace the old <distributionManagement> snapshot with the new plugin configuration. The old workflow continues to work but is on a deprecation trajectory.
SBOM generation as part of release
Releases should emit an SBOM alongside the artifact. cyclonedx-maven-plugin (version 2.8+ as of 2024) produces CycloneDX 1.5 SBOMs; add it to the release build:
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.8.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>makeAggregateBom</goal>
</goals>
</execution>
</executions>
</plugin>
The resulting bom.xml becomes a release artifact alongside the JAR. Consumers and auditors expect this in 2024.
Practical checklist
- Release from dedicated infrastructure, not from dev or shared CI.
- Signing keys in KMS, not on disk.
- Tag protection + signed tags + narrow time window.
- Deploy credentials scoped per-group.
- Pinned parent POM and plugin versions.
- Reproducible build configuration.
- Migrate to central-publishing-maven-plugin.
- SBOM generated with every release.
How Safeguard Helps
Safeguard tracks Maven release configurations across a portfolio of Java services and flags pipelines that ship without SBOM, without signed tags, or with credential patterns inconsistent with policy. Griffin AI summarises release-plugin posture per service and identifies the highest-risk configurations first. Policy gates can require signed tags and KMS-backed signing before release jobs are allowed to run. For Java organisations still running the maven-release-plugin across many services, Safeguard compresses the uneven per-service posture into a tracked, centrally-governed state.