Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 9 additions & 16 deletions nemoclaw-blueprint/policies/openclaw-sandbox.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -191,22 +191,15 @@ network_policies:
binaries:
- { path: /usr/local/bin/openclaw }

# npm registry — needed for `openclaw plugins install` and `npm install`.
# Read-only: agents only fetch packages, never publish.
npm_registry:
name: npm_registry
endpoints:
- host: registry.npmjs.org
port: 443
protocol: rest
enforcement: enforce
tls: terminate
rules:
- allow: { method: GET, path: "/**" }
binaries:
- { path: /usr/local/bin/openclaw }
- { path: /usr/local/bin/npm }
- { path: /usr/local/bin/node }
# NOTE: registry.npmjs.org and the npm/node binaries used to live
# here as `npm_registry` and were therefore granted to every sandbox
# regardless of whether the user picked the `npm` preset during
# onboard. That created the regression in #1458 where a sandbox
# onboarded with NO policies could still run `npm install` (while
# `pip install` was correctly rejected). The entry has been removed
# from the base policy; users who need npm should select the `npm`
# preset (`presets/npm.yaml`) during onboard or apply it later via
# `openshell policy set`. See #1458.

# ── Messaging — pre-allowed for OpenClaw agent notifications ────
# Restricted to node processes to prevent arbitrary data exfiltration
Expand Down
17 changes: 17 additions & 0 deletions test/validate-blueprint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,21 @@ describe("base sandbox policy", () => {
expect(hasGet).toBe(true);
}
});

it("regression #1458: base policy does not silently grant npm registry access", () => {
// Until #1458, registry.npmjs.org and the npm/node binaries lived
// in network_policies.npm_registry, so a sandbox onboarded with
// ZERO policy presets could still run `npm install` (while
// `pip install` was correctly rejected because PyPI was only in
// the pypi preset). Removing the entry restores parity: neither
// npm nor pypi are reachable until the user opts into the
// matching preset. This assertion blocks a re-add by name AND a
// smuggle-in via a renamed key that still references the npm
// registry host.
const np = policy.network_policies as Record<string, unknown> | undefined;
expect(np && typeof np === "object" && "npm_registry" in np).toBe(false);

const npmHosts = findEndpoints((h) => h === "registry.npmjs.org");
expect(npmHosts).toEqual([]);
});
});