Dependency Firewall sits between the agent and the public registries. It leaves out versions that are too new, blocks versions with known vulnerabilities or malware, and logs every install with the token that asked. The rules are set in the firewall, so they apply wherever the agent runs.
The install runs before anyone reads the diff
Give a coding agent shell access and it runs npm install, pip install or cargo add in the middle of a task. The model writes the package name and the version. By the time a person reads the diff, the package is installed.
Which version gets installed varies. An install without a version resolves to the newest release the package manager accepts. A version the model writes into a manifest comes from what it learned in training, and that can be a release from years ago. Some agents look the package up in the registry first.
So one task can pull a release that is a few hours old, and the next one a version with a known vulnerability. Some of the names a model writes were never published, and anyone can register such a name afterwards.
Each package manager has its own age setting
npm, pnpm, Yarn, Bun and uv now each have a setting that skips versions younger than a set age. The setting works, but it is a line in a config file, on one machine or in one repository.
| Client | Setting | Counted in |
|---|---|---|
| npm | min-release-age | Days. Off until you set it. |
| pnpm | minimumReleaseAge | Minutes. 1 day by default. |
| Yarn | npmMinimalAgeGate | A duration. |
| Bun | minimumReleaseAge | Seconds. |
| uv | exclude-newer | A date or a duration. |
The same policy is written differently in every client, and every client has its own list of packages that skip the check. A developer can change the value, pass a flag or add a package to that list, and so can an agent that has been told to make a failing install pass.
Agents install in more places than developers do
A developer installs on one laptop. An agent installs in a terminal on that laptop, in a cloud sandbox, in a CI job and in a container image built last month. Each of those has its own package manager, its own version of it and its own configuration.
Each tool reads its own instruction file, nothing enforces what the file says, and nothing checks afterwards which version the agent installed. So instruction files do not close that gap.
The firewall applies the same rules to every install
Every one of those installs ends in a request for a package. When that request goes through Dependency Firewall, the rules of that ecosystem's firewall apply whichever package manager sent it, on any machine, whether a person or an agent ran the command.
- Release delay. Versions younger than your window are left out of the version list. An agent that asks for the latest version gets the newest one that has aged, and the install succeeds.
- Vulnerability threshold. A version the agent chose from memory is not served if it has a vulnerability above the CVSS and EPSS scores you set.
- Malware blocking. A package with a malware finding is not served, whatever name the model wrote.
A name that was never published fails as not found. A name that someone registered yesterday is inside the delay window, so it is not on the list either.
Put these rules on a baseline firewall for each ecosystem. The firewalls for developers, CI and agents inherit them, and an inherited rule cannot be removed downstream.
Route agents through the firewall
Agents use the same package managers as developers, so they read the same client configuration. Commit that configuration to the repository. Every clone and every agent workspace then installs through the firewall.
Keep the token in an environment variable. Give agents their own access token, so the log shows which installs came from an agent.
What the agent sees when a version is blocked
A blocked version fails the install with the same error a developer would get. The log records the package, the version, the rule and the token that asked.
With the bsfw CLI installed, an agent can read that log itself. The CLI searches the log by package name, follows it live while an install runs and returns each entry as JSON. The agent can also look up the known vulnerability and malware findings for an exact package version before installing it.