Safeguard
Developer Tools•

Why are Gradle dynamic versions risky in mobile app releases?

Selectors like 5.+ can pull new library code into a mobile release without any change in your repo. Why that matters and how dependency locking fixes it.

Safeguard Security Team
3 min read

A dynamic version such as 5.+ or [5.0,6.0) lets Gradle pick a newer release at build time. For a mobile app that means a release build can contain library code nobody reviewed, with no change in your repository. Pin versions or turn on dependency locking, and update on purpose.

What the docs say

Gradle's locking documentation states that dynamic selectors can pick up new releases over time and break builds without any change to your code. Locking records the resolved version of each dependency and transitive dependency in a lock file. Later builds check against it, and if resolution would change, the build fails.

Gradle also warns against using locking with changing versions such as snapshots.

Why mobile is worse than most

A server fix is deployed in minutes. A mobile build is submitted to a store, reviewed, and rolled out in stages. Whatever was in the binary at build time is what users hold for months. If a dynamic selector pulled in a bad version on the day of your release build, you ship it, and you may not be able to rebuild the same binary later to investigate.

Two failure cases:

  • Silent breakage. A new minor version of a library changes behavior, and the release build passes only because tests missed it.
  • Silent compromise. A malicious or mistaken release lands in the version range you allowed, and your next build ingests it.

Three options compared

ApproachReproducible?Picks up fixes automatically?Effort
Exact version in the build fileYesNoManual bumps
Dynamic selector, no lockNoYes, unreviewedNone, until it breaks
Dynamic selector plus lock fileYesOnly when you refreshRun an update step

Most teams are better served by exact versions or a lock file, plus a scheduled step that proposes updates for review.

A scenario

Say your app declares a networking library with a selector like 4.+. On Monday the release build resolves to 4.11. On Thursday the maintainers publish 4.12, which changes how redirects are handled. A hotfix build on Friday resolves to 4.12, and nobody touched the build file. The hotfix now carries a behavior change that was never part of the review, and the store rollout begins.

With a lock file, Friday's build would have resolved to 4.11 again, and the move to 4.12 would appear as a diff in the lock file for someone to read.

How to turn locking on

From Gradle's documentation:

dependencyLocking {
    lockAllConfigurations()
}

Then write the lock state:

./gradlew dependencies --write-locks

The file is gradle.lockfile in each project directory, and Gradle says to check lock files into source control. To update only some modules, use --update-locks with a comma separated list. Our walkthrough is in Gradle dependency locking: how to turn it on.

Quick check

Do lock files stop me getting security fixes?

They stop unreviewed changes. You still update, but on purpose, by refreshing the locks and reviewing the diff.

Should the lock file be committed?

Yes. Gradle's documentation says to check lock files into source control.

Safeguard's dependency scanning and SBOM generation work from your resolved versions, so a locked build gives it a stable list to match against known vulnerabilities. A free scan is available.

Sources

Last reviewed: 19 October 2026.

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.