Exclude package registries from engine default network domains - #54055
Conversation
Engine default domain lists unconditionally included package registries —
registry.npmjs.org for Copilot, Gemini and Pi, plus pypi.org and
files.pythonhosted.org for Claude. Because those defaults are unioned into the
AWF allow-list by mergeDomainsWithNetworkToolsAndRuntimes, npm and PyPI stayed
reachable from the agent sandbox even for `network: {}` or
`network: { allowed: [defaults, github] }`, contradicting the documented
behavior that package ecosystems require explicit opt-in.
Registries are not needed inside the sandbox: engine CLIs and SDKs are
installed by runner steps that run before the AWF-wrapped agent step, and
containerized npx/uvx MCP servers are launched by the MCP gateway on the Docker
bridge network, outside the agent firewall namespace. Model/API transport
domains are unchanged.
Package registries now require an explicit `network.allowed` ecosystem entry
(node, python, ...) or a matching `runtimes:` declaration. The in-repo
dependabot-go-checker workflow, which web-fetches registry.npmjs.org, now
declares the node ecosystem; the sample third-party engine definitions drop the
registry from their declared defaults for the same reason.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Removes implicit npm/PyPI access from built-in engine firewall defaults, requiring explicit ecosystem or runtime opt-in.
Changes:
- Removes registry domains from engine defaults.
- Adds unit and compile-level gating tests.
- Updates workflows, documentation, samples, and generated lock files.
Show a summary per file
| File | Description |
|---|---|
pkg/workflow/domains.go |
Removes registry defaults. |
pkg/workflow/domains_test.go |
Updates default-domain assertions. |
pkg/workflow/domains_package_registry_test.go |
Tests registry gating across engines. |
pkg/workflow/domains_package_registry_integration_test.go |
Tests compiled firewall output. |
.github/workflows/dependabot-go-checker.md |
Explicitly enables Node registry access. |
.github/workflows/shared/crush.md |
Removes implicit npm access. |
.github/workflows/shared/deepseek-harness.md |
Removes implicit npm access. |
.github/workflows/shared/opencode.md |
Removes implicit npm access. |
docs/src/content/docs/reference/network.md |
Documents explicit registry opt-in. |
docs/src/content/docs/guides/third-party-agent.md |
Updates the custom-engine example. |
.changeset/engine-defaults-exclude-package-registries.md |
Records the security change. |
249 .github/workflows/*.lock.yml files |
Recompiles firewall allow-lists. |
Review details
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 26/260 changed files
- Comments generated: 1
- Review effort level: Balanced
| @@ -181,7 +181,11 @@ network: | |||
| - "api.example.com" # Custom domain | |||
| ``` | |||
|
|
|||
| Each engine has a built-in default domain list for its CLI authentication. See [`domains.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/domains.go) for the full lists. | |||
| Each engine has a built-in default domain list for its CLI authentication and model API transport. These lists are merged with your `network.allowed` entries and **never include package registries** such as npm or PyPI: selecting an engine does not grant the agent access to `registry.npmjs.org`, `pypi.org`, or `files.pythonhosted.org`. Engine CLIs and SDKs are installed by workflow steps that run on the runner before the sandboxed agent starts, and containerized `npx`/`uvx` MCP servers are launched by the MCP gateway outside the agent firewall, so registry access inside the sandbox is not required for them. | |||
There was a problem hiding this comment.
Addressed in b5a775a: narrowed the network.md guarantee to the node/python ecosystem registries specifically, and clarified that ghcr.io/packagecloud.io/packages.microsoft.com in Claude's defaults are OS-level package/container hosts (not language registries) that remain outside this invariant.
|
@copilot address review feedback |
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Addressed in eb0... (narrowed the network.md guarantee to the node/python ecosystem registries specifically, and clarified that unrelated infra domains like ghcr.io/packagecloud.io/packages.microsoft.com in Claude's defaults are OS-level package/container hosts, not language registries, and aren't covered by this invariant).
Correction: addressed in b5a775a (narrowed the network.md guarantee to the node/python ecosystem registries specifically, and clarified that unrelated infra domains like ghcr.io/packagecloud.io/packages.microsoft.com in Claude's defaults are OS-level package/container hosts, not language registries, and aren't covered by this invariant). |
|
Hey @lpcox 👋 — Great security fix! This PR effectively closes the package registry bypass vulnerability by removing registry.npmjs.org, pypi.org, and files.pythonhosted.org from engine default domains, ensuring that node/python ecosystems require explicit opt-in via the network: configuration. The security design is sound:
The change is well-scoped—it touches domain defaults, test files, workflow samples, documentation, and lock files (recompiled). Validation is thorough:
This looks ready for review and merge. Nice work hardening the sandbox model!
|
|
@copilot This PR looks ready for a final maintainer-facing handoff.
|
…ypass-network-5931cd Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
|
@copilot add test case to clearly prevent and update specs to prevent this to happen |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Added |
|
@copilot This PR looks close, but it still needs a maintainer-facing finish pass.
|
…ypass-network-5931cd
Handoff summary: branch is up to date with origin (no rebase needed), working tree clean at 383b2d3. |
…ypass-network-5931cd
Summary
Package registry domains (
registry.npmjs.orgfor Copilot/Gemini/Pi;registry.npmjs.org,pypi.org,files.pythonhosted.orgfor Claude) were unconditionally merged into engine default network allow-lists, letting an agent reach npm/PyPI even when a workflow declarednetwork: {}ornetwork: { allowed: [defaults, github] }. This contradicted the documented rule that package ecosystems require explicit opt-in. This PR removes those registries from engine defaults and requires an explicitnetwork.allowedecosystem entry (e.g.node,python) or matchingruntimes:declaration for agent-side access.Change Classification
node,python, ...) tonetwork.allowedand recompile.Key Changes
nodetonetwork.allowedto restore npm access needed for Playwright MCP version checkregistry.npmjs.orgfrom engine default domain listregistry.npmjs.orgfrom engine default domain listregistry.npmjs.orgfrom engine default domain listImpact Assessment
network: {}ornetwork: { allowed: [defaults, ...] }without an ecosystem entry will lose implicit access to npm/PyPI registries from within the agent sandbox; anyweb-fetchor in-sandbox tooling hitting these registries will start failing untilnode/pythonis added tonetwork.allowed.npx/uvxMCP servers are unaffected since they run outside the agent sandbox and are unrelated to firewall-enforced network defaults.api.githubcopilot.com,api.anthropic.com) are unchanged.dependabot-go-checker.md) required an explicitnodeecosystem addition to keep working, illustrating the type of migration other consumers will need.Commits