Safeguard
Vulnerability Analysis•

Gradle 9.8.1 and 8.14.6 Fix Daemon Deserialization on Shared Hosts

Two high severity Gradle advisories let a local user run code in another user's daemon over loopback. Shared build hosts are most at risk. Upgrade the wrapper.

Safeguard Security Team
6 min read

On 7 October 2026 Gradle published three high severity advisories, fixed in Gradle 9.8.1 (released 7 October) and 8.14.6 (released 8 October). Two of them concern the same weakness: the long-lived Gradle daemon accepts Java-serialized objects over loopback TCP before it knows who is talking to it. A local attacker who can put bytes on those sockets can run code inside the daemon JVM, with the privileges of the user running the build.

The third advisory, about repository failover on TLS errors, is covered in a separate post. This one is about the daemon.

What's affected

Both advisories cover org.gradle:gradle-core below 8.14.6, and 9.0.0 through 9.8.0. Fixed open source releases are 9.8.1 and 8.14.6. Gradle also lists backports for older 9.x lines and 7.6.7, mostly through its paid Security Subscription. Neither advisory has a CVE ID.

GHSA-xwqc-3h47-hg64, client to daemon (CVSS v4 8.6). The gradle or gradlew CLI, or an IDE using the Tooling API, talks to the daemon over a loopback TCP port the daemon holds open for its whole lifetime. The daemon checks a secret token on client commands, but the advisory says it "deserializes the incoming message before it verifies that token." A hostile object graph can therefore reach Java deserialization without authentication. A daemon must be running, but no build needs to be active. The fix verifies the token before deserializing.

GHSA-mvvg-497x-hmj8, worker to daemon (CVSS v4 7.3). Compilation, tests and Worker API actions run in forked worker processes that connect back to the daemon over another loopback socket with no peer authentication. The advisory says the connection "is accepted on a first-come basis during a short window while a worker starts." An attacker who connects first can send serialized objects. The fix adds a per-connection secret.

Both advisories state that the bugs are not exploitable from a remote network connection. The risk is other users on the same machine. The advisories call out shared, multi-user build hosts as most at risk, and note that code execution can expose in-memory and on-disk secrets. Proofs of concept were demonstrated to Gradle but not published.

How to check if you're exposed

Find the Gradle version each project uses. The wrapper decides it, not whatever Gradle is installed on the machine:

# Across a checkout of many repositories
grep -rH "distributionUrl" --include=gradle-wrapper.properties . \
  | sed -E 's/.*gradle-([0-9.]+)-(bin|all)\.zip.*/\1  &/' | sort

# In one project
./gradlew --version | head -3

Anything below 8.14.6, or from 9.0.0 to 9.8.0, is affected.

Then ask where builds run. A developer laptop with one user is low risk. These are the cases to fix first:

  • Self-hosted CI agents that run jobs for several teams or projects under different users on the same host.
  • Shared build servers or jump hosts where engineers log in and run Gradle.
  • Long-lived agents where daemons stay up between jobs.

List running daemons and their versions on a host:

./gradlew --status

For forensics, the advisories describe what to look for. A failed client message logs Unable to receive command from client socket connection in the daemon log. A worker hijack shows up as a task failure with Could not connect to server caused by Connection refused. Daemon logs live under the Gradle user home:

grep -rl "Unable to receive command from client socket connection" ~/.gradle/daemon/*/daemon-*.out.log

Gradle is clear that a log entry is not proof of an attack, and no entry does not rule one out.

What to do now

  1. Upgrade the wrapper in every project to 9.8.1 or 8.14.6:
    ./gradlew :wrapper --gradle-version=9.8.1 && ./gradlew :wrapper
    
    Commit both gradle/wrapper/gradle-wrapper.properties and the wrapper JAR changes.
  2. Stop old daemons after upgrading so nothing vulnerable stays listening:
    ./gradlew --stop
    
  3. Move CI to single-tenant, ephemeral runners. This is Gradle's own workaround if you can't upgrade. A runner that serves one job and is destroyed afterwards leaves no other user to attack the daemon.
  4. Restrict local access on any host that must stay shared. Only trusted users should be able to log in while a daemon is running.
  5. Rotate secrets on shared build hosts if you find unexplained daemon log warnings. Build credentials, signing keys and registry tokens all live in that JVM.

Why it matters

Both bugs follow a familiar pattern: an internal channel assumed to be private because it binds to localhost. Loopback is only private if the machine has one user. On shared CI agents, the other "user" may be another team's job, or a pull request from a fork that runs on the same host.

The fix also reflects a longer trend. Gradle's own architecture notes include a decision to avoid Java serialization, and these advisories are what happens where it was still in use. Any build tool that keeps a background process running between commands has a similar control channel, and it is worth asking how each one authenticates its clients.

Try it yourself

Pick one self-hosted CI host and list who can run code on it: which pipelines, which repositories, which users. Then run ./gradlew --status from a job and see how many daemons from other jobs are still alive. If more than one trust boundary shares the host, you have the setup these advisories describe.

Click through it at your own pace, or open it full screen.

Quick check

Can an attacker on the internet exploit the Gradle daemon advisories directly?

No. Both advisories state the bugs are not exploitable from a remote network connection. The attacker needs to put bytes on loopback sockets on the same host.

Does the client to daemon bug require a build to be running?

No. A daemon must be running, but the advisory says no active build is needed.

Which Gradle versions are fixed for open source users?

9.8.1 and 8.14.6. Backports for other lines are listed mostly through Gradle's Security Subscription.

Sources

Never miss an update

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

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.