Supply chain naming
Anyone can publish a package called acme-auth. Your build might install it.
This is how dependency confusion works, and it ends with a stranger's code running inside your build. The names at risk are the ones written in your own manifests, and SourceAnt has already graded every one of them.
How it happens
No exploit and no clever trick. Just a name that nobody owns.
- 01
They read a name
Your internal package is called acme-auth. The name is in a lockfile in a public repository, in a stack trace, in a job log, or in a blog post one of your engineers wrote.
- 02
They publish it
Anyone can register acme-auth on the public registry. It costs nothing and takes a minute. They set the version higher than yours.
- 03
Your build takes theirs
Depending on how your installer is configured, a public package can win over the private one. Now their install script runs where your build runs, with whatever your build can reach.
The fix is well known: own the name, or pin the source it must come from. The hard part is knowing which of your names are exposed, and that list is not written down anywhere.
Why SourceAnt knows
It had to decide how far to trust the name
When SourceAnt reads a manifest and sees a dependency on a name one of your own repositories publishes, it proposes the relationship. First it asks whether the name carries its owner.
A name that carries its owner resolves to you and to nobody else, so the proposal comes back at full confidence. A bare word gets a lower grade, because the public registry can answer for that word too. The number is not a hedge. It is the shape of the exposure.
So the list you want is a filter you can already run.
The name carries its owner. Nobody else can publish it.
A bare word. It probably resolves to you, and a stranger could take it tomorrow.
Two of your repositories publish the same name. That is ambiguous, so nothing is proposed rather than a coin toss.
Three of these cannot be hijacked. One can.
Most ecosystems put the owner in the name. Python does not.
| Ecosystem | A name of yours | Who can publish it |
|---|---|---|
| Composer | acme/auth | Only you The vendor is part of the name. Nobody else can publish it. |
| Go | github.com/acme/auth | Only you The module path is a host you control. |
| npm | @acme/auth | Only you Owned when scoped. A bare name is not. |
| PyPI | acme-auth | Anyone PyPI names carry no owner. There is no scoped form to move to. |
If your internal packages are Python, every one of them is in the second group. That is not a fault in the inference. It is what PyPI names are.
Then you have a list, and two ways to close it
Take the name, or stop the registry answering for it
Register it publicly so nobody else can, move the package behind a scope you own, or pin the source your installer is allowed to resolve it from.
Write down the ones you decide to live with
Record it as a constraint with your reasoning attached. The next person who finds it, or the next agent, reads the decision instead of reopening it.
Put your system on the record
Run the open core on your own infrastructure, or start on the hosted workspace. The graph is portable either way.