Skip to content

How to Secure JitPack Dependencies in build.gradle Against Supply Chain Attacks

Problem

When I scan my Android project’s dependencies, I find several JitPack dependencies that could be hijacked:

Terminal window
./gradlew dependencies --configuration releaseRuntimeClasspath

I see output like this:

+--- com.github.abandoned-user:library:1.0.0
| +--- com.github.transitive:lib:2.1.0

The problem is that these dependencies come from JitPack with mutable version tags like @main or @latest, which means anyone could hijack the abandoned namespace and publish malicious code.

Environment

  • Gradle 8.0
  • Android Gradle Plugin 8.1.0
  • Java 17
  • JitPack dependencies in build.gradle

What happened?

I read about a security researcher’s findings on JitPack supply chain vulnerabilities. They explained that JitPack allows anyone to publish packages to any namespace. If a GitHub user abandons their account or deletes their repo, a malicious actor can claim the same namespace and publish malicious versions with the same dependency coordinates.

Here’s my vulnerable build.gradle:

app/build.gradle
dependencies {
// Vulnerable: tag can be hijacked
implementation 'com.github.user:repo:latest'
// Vulnerable: branch can be changed by anyone
implementation 'com.github.user:repo:main-SNAPSHOT'
// Vulnerable: even specific tags can be republished
implementation 'com.github.abandoned-user:library:1.0.0'
}

The issue is that com.github.user:repo:latest doesn’t pin to anything immutable. If the user account is abandoned, someone else could claim it and push a new “latest” version that contains malware.

How to solve it?

I tried three approaches to secure my JitPack dependencies.

Step 1: Pin dependencies to commit hashes

I replaced mutable version tags with specific commit hashes:

app/build.gradle
dependencies {
// Secure: pinned to specific commit hash
implementation 'com.github.user:repo:1.2.3'
// Find the commit hash from GitHub releases or tags
// Example: commit abc123def becomes version abc123def
}

But this alone isn’t enough. I need to verify the artifact checksums.

Step 2: Enable Gradle dependency verification

I added verification metadata to my project. First, I generated the metadata file:

Terminal window
./gradlew --write-verification-metadata sha512

This created a verification-metadata.xml file in my project root:

verification-metadata.xml
<?xml version="1.1" encoding="UTF-8"?>
<verification-metadata xmlns="https://schema.gradle.org/dependency-verification" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.3.xsd">
<configuration>
<verify-metadata>true</verify-metadata>
<verify-signatures>false</verify-signatures>
<trusted-artifacts>
<trust group="com.github.user" name="repo" version="1.2.3" reason="Pinned commit"/>
</trusted-artifacts>
</configuration>
<components>
<component group="com.github.user" name="repo" version="1.2.3">
<artifact name="repo-1.2.3.jar">
<sha512 value="a1b2c3d4e5f67890abcdef1234567890..." algorithm="SHA-512"/>
</artifact>
</component>
</components>
</verification-metadata>

Then I enabled it in my settings.gradle:

settings.gradle
dependencyResolutionManagement {
verificationMode = VerificationMode.STRICT
}

Now when I build, Gradle verifies the checksums. If someone hijacks the namespace and publishes a malicious artifact, the build fails because the SHA-512 hash doesn’t match.

Step 3: Scan transitive dependencies

I needed to check all dependencies, not just the ones I directly include:

Terminal window
./gradlew dependencies --configuration releaseRuntimeClasspath

I found transitive dependencies also using JitPack:

+--- com.github.direct:lib:1.0.0
| \--- com.github.transitive:core:2.0.0 <-- Transitive JitPack dep!

For these, I used dependencyInsight to see where they come from:

Terminal window
./gradlew dependencyInsight --dependency com.github.transitive:core --configuration releaseRuntimeClasspath

Output showed which direct dependency pulls it in:

com.github.transitive:core:2.0.0
+--- com.github.direct:lib:1.0.0
| \--- project :app

Now I can either:

  • Exclude the transitive dependency
  • Pin it directly with checksum verification
  • Contact the upstream maintainer to use a secure repository

Testing the fix

I tested the verification by modifying a checksum in verification-metadata.xml:

<sha512 value="0000000000000000..." algorithm="SHA-512"/>

Then I ran the build:

Terminal window
./gradlew build

The build failed with:

Execution failed for task ':app:checkDebugAndroidTestDuplicateClasses'.
> Could not resolve com.github.user:repo:1.2.3.
> Artifact verification failed for com.github.user:repo:1.2.3

This confirms the verification is working. I reverted the checksum and the build succeeded.

The reason

The key reason for this vulnerability is that JitPack doesn’t enforce namespace ownership. Unlike Maven Central, where publishing requires signing keys and ownership verification, JitPack constructs the group ID from the GitHub username com.github.{username}. If the username is abandoned, anyone can claim it.

By pinning to commit hashes and enabling checksum verification, I create two layers of defense:

  1. The commit hash ensures I’m getting a specific version from a specific commit
  2. The checksum ensures the artifact content hasn’t been tampered with

This is the same defense-in-depth principle used in npm package-lock.json, Rust’s Cargo.lock, and Python’s pip requirements with hashes.

Summary

In this post, I showed how to secure JitPack dependencies against supply chain attacks by pinning to commit hashes, enabling Gradle verification metadata, and scanning transitive dependencies. The key point is that mutable version tags like latest or main-SNAPSHOT are vulnerable to namespace hijacking, and you need checksum verification to ensure artifact integrity.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments