Safeguard
Supply Chain•

Why should publishing and resolving use separate mirror repositories?

Keep internal packages in a hosted repository, keep public packages in a proxy repository, and expose one read endpoint. Why the split limits damage.

Safeguard Security Team
4 min read

Because mixing them lets public packages land next to your internal ones, and lets anyone who can write to the mirror alter what everybody installs. Keep a hosted repository for your internal packages and a proxy repository for public ones, and give clients a single read address that combines them in a defined order.

Three kinds of repository

Most repository managers offer the same three building blocks, under different names.

TypeWhat it holdsWho writes
HostedYour internal packagesYour CI only
ProxyCached copies of a public registryThe mirror itself, on demand
Group or virtualA read view combining the others in a set orderNobody, it is a view

Developers and CI read from the group. Only CI publishes, and only to the hosted repository.

What the split buys you

First, a clear write path. Only a handful of service accounts need write permission on the hosted repository, and nobody needs it on the proxy.

Second, predictable resolution. In the group, put the hosted repository first. For names you own, the internal copy answers before the public one is consulted. Some ecosystems also let clients restrict which repository may serve which names, which is stronger than ordering alone. Earlier posts in this series cover source mapping for NuGet and filters for Composer.

Third, easier cleanup. Retention rules for a proxy cache are very different from rules for artifacts you must keep.

Publishing is a separate configuration

Build tools usually treat publishing as separate from resolution. Gradle's documentation on mirrors states that mirrors apply to resolution only, and that publishing always uploads to the repository URL declared in the build. That is a useful reminder: pointing resolution at the group does not move uploads, so check where each tool publishes, and give it the hosted repository address with a write credential that only CI holds.

Steps to set it up

  1. Create the hosted repository and restrict write to a CI service account.
  2. Create a proxy repository for each public registry you use.
  3. Create the group with the hosted repository first.
  4. Point clients at the group address for reads.
  5. Point publish steps at the hosted address with a dedicated token.
  6. Test that a developer account cannot upload to the group or the proxy.
  7. Test that a public package with the same name as an internal one does not win.

Common mistakes

Allowing redeploy of released versions in the hosted repository is a frequent one. A released version should be immutable, so a fix ships as a new version. Another is giving the proxy repository a write role for convenience. Finally, teams sometimes leave the group's order unreviewed after adding a new repository, which can put a public source ahead of an internal one.

Where Safeguard fits

Safeguard's policy gates can check dependency changes in pull requests, which complements repository layout by catching names that do not belong. A free scan is at gold.safeguard.sh/scan.

Try it yourself

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

Watch how a gate holds a change for review, and think about which publish steps in your pipeline deserve the same hold.

Quick check

Can developers publish test packages to the hosted repository?

Give them a separate sandbox repository so experiments never sit beside released internal packages.

Is ordering enough to stop dependency confusion?

It helps, but client side filters or source mapping are stronger because they do not depend on order.

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.