[SECURITY NOTICE] partial credential exposure in public CI logs (no user action required)
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 15/100
Research direction
This issue documents a credential-exposure incident in GitHub Actions and publishing, including changes already made to secret handling and branch restrictions. No source file, test, or contribution entry point is named; the incident follow-up and restoration of publishing are the stated completion points.
Written by the indexing model from the issue text.
Description
No released artifact is affected. Nothing was published by anyone but us, and we have verified that. No action is required of Spotless users.
What was exposed
While debugging a publishing change, two secrets were printed into public GitHub Actions logs:
- Our Sonatype/Maven Central token password — but not the token username.
- Our GPG signing subkey, still encrypted — but not the passphrase that decrypts it (>100 bits of entropy, never printed anywhere).
- Our master GPG key was not exposed. The CI copy contains only the signing subkey.
Each leaked value was one half of a pair whose other half stayed masked. The logs were public for roughly 28 hours, so we assume they were copied; nothing below depends on them having gone unread.
How it happened
Both secrets were stored base64-encoded, a leftover from an older CI system. Base64 is an encoding, not protection.
Our previous build decoded them inside Gradle, so the plaintext never left the build process. When we modernized publishing, the new plugin reads plaintext Gradle properties instead, so a workflow step decoded the secrets and wrote them to $GITHUB_ENV.
GitHub masks a secret only when the logged text matches the value it was given. A decoded value is a different string, so it is not masked — and variables written to $GITHUB_ENV are printed in the log header of every later step. Both decoded values were printed there.
Sequence:
- #3052 migrated publishing to a new plugin. The publish job only ran on
main, so the new path was never exercised by a PR. - #3079 added snapshot publishing from
main, which put release credentials into every push tomain. - After merging, publishing failed on
main. While diagnosing it in #3086, the branch restriction on the publish job was temporarily removed so the job would run on the PR, and the decoded secrets were printed in those runs. Secrets were available to any branch in the repository; only that restriction had been keeping them out of PRs. - Because publishing had changed, we ran a security review of everything merged since the previous release, which caught it.
What we verified
- All 68
com.diffplugrelease coordinates on Maven Central are untouched since the 8.10.2 release on 2026-09-04. - The snapshot repository contains only the two expected test uploads from our own CI.
- Every published file is signed by our legitimate key, with signature timestamps matching our CI jobs.
- The Central Portal shows no other deployments.
Response
- ~25 minutes from detection to contained: pending CI cancelled, the exposed logs deleted, and the Sonatype token revoked and rotated.
- The base64 secrets were deleted outright, organization-wide, so no workflow can decode a secret again.
mainis locked, and publishing is currently paused while we finish the key work.
Signing key
The leaked subkey was not compromised — the passphrase protecting it has never leaked — but we are retiring it anyway. We are issuing a new signing subkey and deleting every copy of the passphrase that protects the old one, which leaves the exposed key material permanently unusable.
We are not revoking the old subkey, so signatures on existing releases remain valid.
If you use Gradle dependency verification or otherwise pin our signing key, you will need to add the new subkey before verifying a future release. We will post the new subkey ID as a follow-up comment on this issue within hours.
- New signing subkey:
0xFA5C18CFB74EC7C6, under the same primary key
27294482F2D2F9A318CA041B1AAAA7AB37293D3E. It is published on keys.openpgp.org and
keyserver.ubuntu.com, including by-email lookup forsecurity@diffplug.com.
Policy changes
It should never have been possible for these credentials to be reachable from a PR, and exposing them to every push to main for snapshot publishing was an unacceptable risk.
- Snapshot publishing from
mainhas been removed. We no longer publish snapshots. - Release credentials now live in a deployment environment restricted to the
releasebranch, which only one maintainer can push to. No PR, topic branch, fork, or push tomaincan reach them. - Secrets are stored in the exact form the build consumes. Nothing decodes a secret in CI.
- CI tokens are least-privilege by default, and changes to workflow and build files now require review from a code owner.
Security reports: spotless-security@diffplug.com
I will follow-up in this issue when publishing has been restored and we are accepting pull requests again. I expect we will not publish a new release or accept PRs until next week.
- Dominant language
- Java
- Stars
- 5.7k
- Forks
- 560
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 43
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from diffplug/spotless
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
-
Difficulty 3/5 1-2 days Newbie friendliness 66/100
-
Difficulty 3/5 1-2 days Newbie friendliness 68/100
-
Difficulty 4/5 3-5 days Newbie friendliness 52/100
-
Difficulty 3/5 1-2 days Newbie friendliness 68/100
All issues in diffplug/spotless
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
infinispan/infinispan#18150 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
opensearch-project/k-NN#3597 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100