Safeguard
Developer Tools•

How do I stop Gradle fetching my private groups from public repos?

Use Gradle repository content filtering: includeGroup on the private repository and exclusiveContent so only it can serve your internal groups.

Safeguard Security Team
4 min read

Declare your private repository with Gradle's exclusiveContent and an includeGroup filter for your internal group names. Then no other repository can supply those artifacts, even one listed earlier. Gradle's docs name security, performance and reliability as the reasons for content filtering, and it takes about ten lines.

Why order alone is not enough

Gradle searches repositories in the order you declare them, and once it finds a module's metadata in one repository it downloads that module's artifacts from the same place. That is a sensible default, but it means a public repository listed first gets the first chance to answer for any coordinate, including one that only exists internally.

If an attacker publishes a public artifact under a group name you use privately, the public repository can answer first. This is the shape of a dependency confusion attack. Reordering helps, but it is a convention someone can break later. A filter is a rule the build enforces.

The three filtering tools

ToolWhat it doesUse it when
includeGroup on a repositoryLimits that repository to the named groupA private repository holds only your own groups
exclusiveContentDeclares that a repository is the only source for matching artifactsYou want other repositories blocked from serving those artifacts
includeModule or version filtersNarrow the match to a module or version, exact or by regular expressionOne public module lives in a special repository

The Gradle docs describe filters by group, module or version, using exact values or regular expressions.

Example

This is the pattern from the Gradle documentation, shown in the Kotlin DSL:

repositories {
    // Not searched for my.company artifacts, despite being declared first
    mavenCentral()
    exclusiveContent {
        forRepository {
            maven {
                url = uri("https://repo.mycompany.com/maven2")
            }
        }
        filter {
            includeGroup("my.company")
        }
    }
}

Read it as two rules. The public repository is never asked for my.company artifacts. The private repository is the only source for them. If the private repository is down, the build fails loudly instead of quietly accepting a public lookalike.

Steps to adopt it

  1. List every group name your organization publishes internally.
  2. Put those names in includeGroup filters on the private repository, in the settings file if you centralize repositories.
  3. Use exclusiveContent for groups that must never come from anywhere else.
  4. Do the reverse for special repositories: if a vendor repository serves one group, filter it to that group so it cannot answer for others.
  5. Run a build with a clean cache and read the resolution output for unexpected sources.

The same logic applies in the other direction. Gradle's docs also point out that filtering avoids leaking which private dependencies you use, because requests for internal groups are never sent to public servers.

What filtering does not do

It does not prove an artifact is genuine. It controls where Gradle looks, not what it finds. Pair it with dependency verification for checksums and locking for repeatable versions. For the wider repository picture on Android, see how to control where Gradle downloads Android dependencies from.

Try it yourself

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

Click into a component and look at where it came from. Anything with an unexpected source deserves a filter.

Safeguard's dependency scanning and SBOM generation list every resolved component in a repository, which makes unexpected sources easy to spot. You can run the free scan at gold.safeguard.sh/scan.

Quick check

Does a repository declared first always win in Gradle?

Gradle searches in declaration order, so yes for any coordinate the first repository can answer. Content filters change that: a filtered repository is skipped for artifacts it is not allowed to serve.

Is exclusiveContent the same as includeGroup?

No. includeGroup limits what one repository may serve. exclusiveContent also stops all other repositories from serving the matching artifacts.

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.