Skip to content

Harden actions/setup-java action #794

@ppkarwasz

Description

@ppkarwasz

Although admittedly this is not a priority item, we should open an issue and possibly contribute some supply-chain verification steps. The following paragraphs were generated by Claude, so they might contain errors, but they agree with what I have been able to observe.

Current situation

Currently the downloads of all JDK distributions configured by actions/setup-java rely entirely on the TLS connection to the apposite CDN servers. Neither signatures nor checksums are verified by the action itself.

A direct inspection of every per-vendor installer in src/distributions/ confirms this: not one of them computes a hash or invokes any signature verification primitive. The pattern is uniformly tc.downloadTool(url) followed by extractJdkFile(...) followed by tc.cacheDir(...). Several installers even parse a checksum field from the upstream metadata API (Adopt, Temurin, Corretto, Dragonwell, SAPMachine, Semeru) and then never use it.

This means a compromise of any vendor CDN (or of any of the certificate authorities that vendor's CDN trusts) silently propagates into every CI run, every cached tool entry on every runner image, and every downstream artifact built against that JDK. It also means there is no defense in depth against the more pedestrian failure mode of an archive being corrupted in transit.

Possible improvements

Distributions that publish a detached signature on the archive

These are the highest-value targets: a signature ties the artifact to a publisher-controlled key, so verification defends against CDN compromise even when the attacker can also rewrite a published checksum on the same origin. For all five entries below, the signing key is long-lived, publicly documented, and the signature file is available at a predictable URL alongside the archive that setup-java already downloads.

Distribution Signature artifact Scheme Publisher key Key location
Temurin (Adoptium) .sig per asset, URL exposed as signature_link field in the existing api.adoptium.net JSON GPG (RSA 4096) 3B04D753C9050D9A5D343F39843C48A565F8F04B "Adoptium GPG Key (DEB/RPM Signing Key)" keyserver.ubuntu.com, plus adoptium.net/installation/gpg-verification
Adopt (legacy AdoptOpenJDK) .sig per asset (same Adoptium pipeline) GPG (RSA 4096) Same key as Temurin Same as Temurin
Corretto (Amazon) <archive>.tar.gz.sig next to each archive on corretto.aws GPG 6DC3636DAE534049C8B94623A122542AB04F24E3 "Amazon Services LLC (Amazon Corretto release)" apt.corretto.aws/corretto.key. Has rolled at least once (Dec 2024); verification logic must accommodate rotation.
Microsoft Build of OpenJDK .sig per archive on aka.ms/download-jdk/... GPG "Microsoft public key" published on the download page learn.microsoft.com/en-us/java/openjdk/download
Semeru (IBM) .sig per archive OpenSSL / X.509, not GPG. ibm-semeru-public-<yyyymmdd>.pem plus DigiCert code-signing certificate ibm.com/support/pages/semeru-runtimes-verification. Requires a different code path from the GPG-based vendors.

Distributions without archive signatures: checksum sources

For the remaining seven, no detached cryptographic signature is published on the standalone archive, so publisher-key authentication is not possible without changes upstream. The next-best defense is verifying the SHA-256 / SHA-512 from a source distinct from the CDN serving the archive. The "Independent of archive CDN?" column captures whether the checksum is fetched from a different origin from the binary; where the answer is no, an attacker who controls the download origin can also rewrite the checksum, so the verification only buys defense against in-transit corruption.

Distribution Archive download origin Checksum source Independent of archive CDN? Algorithm
Zulu (Azul) cdn.azul.com Azul Metadata API at api.azul.com/metadata/v1/zulu/packages/... returns sha256_hash field Yes (api.azul.com vs cdn.azul.com) SHA-256
Liberica (BellSoft) download.bell-sw.com BellSoft API at api.bell-sw.com/v1/liberica/releases returns sha1 field per asset Yes (api.bell-sw.com vs download.bell-sw.com) SHA-1 (weak; SHA-256 also published on the human-facing bell-sw.com/pages/downloads/ page)
SAPMachine github.com/SAP/SapMachine/releases/download/... sap.github.io/SapMachine/assets/data/sapmachine_releases.json returns checksum per asset Partially (both ultimately served by GitHub Pages / GitHub Releases, but distinct origins and TLS chains) SHA-256
Dragonwell (Alibaba) github.com/dragonwell-project/.../releases/download/... dragonwell-jdk.io/map_with_checksum.json Yes (dragonwell-jdk.io vs github.com) SHA-256
Oracle JDK / Oracle GraalVM download.oracle.com SHA-256 published on the human-facing oracle.com/java/technologies/downloads/ and oracle.com/java/technologies/javase/graalvm-jdk*-readme.html pages Yes-ish (same parent domain oracle.com, different subdomains; both Oracle-controlled, so a full Oracle compromise defeats both) SHA-256
GraalVM Community github.com/graalvm/graalvm-ce-builds/releases/download/... SHA-256 in the GitHub Release notes (rendered from the same repo's release metadata) No (both served by GitHub from the same release) SHA-256
JetBrains Runtime cache-redirector.jetbrains.com and github.com/JetBrains/JetBrainsRuntime/releases/download/... SHA-512 in the GitHub Release notes No for the GitHub-hosted archives; yes for cache-redirector.jetbrains.com where the release notes on GitHub provide an independent reference SHA-512

A note on the "independent" column: for entries marked "no" or "partially", checksum verification still meaningfully defends against transient corruption, mirror substitution, and any compromise that affects only the binary CDN. It does not defend against a compromise of the vendor's overall infrastructure. Honest framing of this in any documentation we write would help avoid false security claims.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions