How to Prevent AI Agents from Publishing Packages
SafeClaw by Authensor blocks all package publishing commands by default, preventing AI agents from releasing code to npm, PyPI, RubyGems, crates.io, or any other package registry. Install SafeClaw with npx @authensor/safeclaw and every publish attempt — npm publish, twine upload, gem push, cargo publish — is denied and recorded in a hash-chained audit log.
Why Package Publishing Is Dangerous When AI Agents Do It
Publishing a package is a public, often irreversible action. An npm package published under your organization's scope is immediately downloadable by anyone. A PyPI package can be installed by every project that lists it as a dependency. An agent that publishes can ship code containing bugs, vulnerabilities, leaked secrets, hallucinated implementations, or malicious payloads to your downstream consumers. Version numbers, once published, often cannot be reused even after unpublishing. Depending on the registry, published packages may be cached by mirrors and CDNs indefinitely. Registry credentials (npm tokens, PyPI API tokens) are typically stored in environment variables or .npmrc/.pypirc files — both accessible to agents with file read permissions.
The Exact SafeClaw Policy to Block Package Publishing
Add these rules to .safeclaw/policy.yaml:
rules:
# Block npm publish
- id: deny-npm-publish
action: shell.exec
match:
command: "npm publish*"
effect: deny
audit: true
message: "npm publish is permanently denied for AI agents."
# Block yarn publish
- id: deny-yarn-publish
action: shell.exec
match:
command: "yarn publish*"
effect: deny
audit: true
message: "yarn publish is permanently denied."
# Block pnpm publish
- id: deny-pnpm-publish
action: shell.exec
match:
command: "pnpm publish*"
effect: deny
audit: true
message: "pnpm publish is permanently denied."
# Block Python package publishing
- id: deny-twine-upload
action: shell.exec
match:
command: "twine upload*"
effect: deny
audit: true
message: "PyPI package upload is permanently denied."
- id: deny-python-setup-upload
action: shell.exec
match:
command: "python setup.py upload"
effect: deny
audit: true
message: "setup.py upload is permanently denied."
# Block Ruby gem publishing
- id: deny-gem-push
action: shell.exec
match:
command: "gem push*"
effect: deny
audit: true
message: "gem push is permanently denied."
# Block Rust crate publishing
- id: deny-cargo-publish
action: shell.exec
match:
command: "cargo publish*"
effect: deny
audit: true
message: "cargo publish is permanently denied."
# Block NuGet publishing
- id: deny-nuget-push
action: shell.exec
match:
command: "nuget push*"
effect: deny
audit: true
message: "nuget push is permanently denied."
- id: deny-dotnet-nuget-push
action: shell.exec
match:
command: "dotnet nuget push*"
effect: deny
audit: true
message: "dotnet nuget push is permanently denied."
# Protect registry credential files
- id: deny-read-npmrc
action: file.read
match:
path: "*/.npmrc"
effect: deny
audit: true
message: "Reading .npmrc (contains npm tokens) is denied."
- id: deny-read-pypirc
action: file.read
match:
path: "*/.pypirc"
effect: deny
audit: true
message: "Reading .pypirc (contains PyPI tokens) is denied."
This policy covers the six major package ecosystems: npm/yarn/pnpm (JavaScript), twine/setup.py (Python), gem (Ruby), cargo (Rust), and nuget (C#/.NET). Registry credential files are also protected from being read.
What Happens When the Agent Tries
When an agent attempts npm publish --access public:
- SafeClaw intercepts the
shell.execaction. - The
deny-npm-publishrule matchesnpm publish*. - The command is blocked. No package is uploaded. No registry API call is made.
- Audit entry:
{
"timestamp": "2026-02-13T15:40:33Z",
"action": "shell.exec",
"command": "npm publish --access public",
"effect": "deny",
"rule": "deny-npm-publish",
"agent": "release-agent-01",
"hash": "o4q1t7...chain"
}
If the agent tries to read .npmrc to extract the auth token for a manual HTTP publish request, the deny-read-npmrc rule catches that attempt separately.
How to Allow Publishing with Approval
For CI/CD agents that need to publish releases after human review:
rules:
# Protect credentials (always deny)
- id: deny-read-npmrc
action: file.read
match:
path: "*/.npmrc"
effect: deny
audit: true
message: "Reading .npmrc is denied."
# Approval-gated publishing
- id: approve-npm-publish
action: shell.exec
match:
command: "npm publish*"
effect: approval
audit: true
approvers:
- role: release-manager
timeout: 600
message: "npm publish requires release manager approval. Version and scope logged."
# Deny other registries
- id: deny-twine-upload
action: shell.exec
match:
command: "twine upload*"
effect: deny
audit: true
message: "PyPI publishing is denied."
The release manager sees the full command — including any --tag, --access, or --registry flags — before approving. The 600-second timeout gives time to review the package contents, verify the version number, and check the changelog.
For maximum safety, combine with a pre-publish verification step:
rules:
- id: allow-npm-pack
action: shell.exec
match:
command: "npm pack*"
effect: allow
audit: true
- id: approve-npm-publish
action: shell.exec
match:
command: "npm publish*"
effect: approval
audit: true
approvers:
- role: release-manager
timeout: 600
message: "Review npm pack output before approving publish."
This lets the agent run npm pack (which creates a local tarball without uploading) so the release manager can inspect the exact contents before approving the publish.
Verification
npx @authensor/safeclaw simulate --action 'shell.exec' --command 'npm publish --access public'
Expected: deny, rule: deny-npm-publish
npx @authensor/safeclaw simulate --action 'file.read' --path '/home/user/.npmrc'
Expected: deny, rule: deny-read-npmrc
Related Pages
- How to Gate npm install in AI Agent Workflows
- Supply Chain Agent Attack Threat
- CI/CD Pipeline Agent Recipe
- How to Gate Shell Command Execution in AI Agents
- API Key Exfiltration Threat
Try SafeClaw
Action-level gating for AI agents. Set it up in your browser in 60 seconds.
$ npx @authensor/safeclaw