Skip to content

fix(security): add binaries restrictions to all messaging and preset policies#645

Open
ericksoa wants to merge 2 commits intomainfrom
fix/messaging-binaries-restriction
Open

fix(security): add binaries restrictions to all messaging and preset policies#645
ericksoa wants to merge 2 commits intomainfrom
fix/messaging-binaries-restriction

Conversation

@ericksoa
Copy link
Contributor

@ericksoa ericksoa commented Mar 22, 2026

Summary

Add binaries: restrictions to all messaging entries in the baseline sandbox policy and all policy presets, preventing arbitrary processes (curl, wget, python) from reaching external APIs for data exfiltration.

Credit to @gn00295120 whose work on #611 identified the exfiltration risk from unrestricted messaging endpoints in the baseline policy. This PR takes an alternative approach — adding binary restrictions rather than removing messaging from the baseline — to preserve the out-of-box experience for hobbyist users while closing the exfiltration vector.

Changes

Baseline policy (openclaw-sandbox.yaml):

  • Telegram and Discord entries now restricted to /usr/local/bin/node

All presets (presets/*.yaml):

  • Telegram, Discord, Slack → /usr/local/bin/node
  • Docker → /usr/bin/docker
  • Hugging Face → /usr/local/bin/python3, /usr/local/bin/node
  • Jira, Outlook → /usr/local/bin/node
  • npm → /usr/local/bin/npm, /usr/local/bin/yarn
  • PyPI → /usr/local/bin/pip, /usr/local/bin/pip3

Regression test (test/security-binaries-restriction.test.js):

  • Verifies every baseline network_policies entry has a binaries: section
  • Verifies every preset YAML has a binaries: section
  • Prevents future entries from being added without restrictions

Closes #272

Test plan

  • node --test test/security-binaries-restriction.test.js — 2/2 pass
  • npm test — 189/189 pass
  • Manual: verify messaging integrations still work (OpenClaw runs as node)

Summary by CodeRabbit

  • Chores

    • Clarified agent notification scope and exfiltration restrictions; added executable-level allowlists for multiple service integrations (Telegram, Discord, Docker registries, HuggingFace, Jira, npm/yarn, Outlook Graph, PyPI, Slack).
  • Tests

    • Added automated checks to ensure each network policy preset includes the required executable-level allowlist.

@coderabbitai
Copy link

coderabbitai bot commented Mar 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b484a0d9-f180-4a38-9ed0-37eb22ffeac2

📥 Commits

Reviewing files that changed from the base of the PR and between 198e3d3 and 77c03c3.

📒 Files selected for processing (11)
  • nemoclaw-blueprint/policies/openclaw-sandbox.yaml
  • nemoclaw-blueprint/policies/presets/discord.yaml
  • nemoclaw-blueprint/policies/presets/docker.yaml
  • nemoclaw-blueprint/policies/presets/huggingface.yaml
  • nemoclaw-blueprint/policies/presets/jira.yaml
  • nemoclaw-blueprint/policies/presets/npm.yaml
  • nemoclaw-blueprint/policies/presets/outlook.yaml
  • nemoclaw-blueprint/policies/presets/pypi.yaml
  • nemoclaw-blueprint/policies/presets/slack.yaml
  • nemoclaw-blueprint/policies/presets/telegram.yaml
  • test/security-binaries-restriction.test.js
✅ Files skipped from review due to trivial changes (8)
  • nemoclaw-blueprint/policies/presets/docker.yaml
  • nemoclaw-blueprint/policies/presets/jira.yaml
  • nemoclaw-blueprint/policies/presets/slack.yaml
  • nemoclaw-blueprint/policies/presets/discord.yaml
  • nemoclaw-blueprint/policies/presets/outlook.yaml
  • nemoclaw-blueprint/policies/presets/npm.yaml
  • test/security-binaries-restriction.test.js
  • nemoclaw-blueprint/policies/presets/telegram.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • nemoclaw-blueprint/policies/presets/pypi.yaml
  • nemoclaw-blueprint/policies/presets/huggingface.yaml

📝 Walkthrough

Walkthrough

Added binaries allowlists to the sandbox base policy and multiple preset network policies to restrict which executables may contact allowed endpoints; added tests that assert every preset and the base sandbox policy include a binaries: section. (50 words)

Changes

Cohort / File(s) Summary
Base policy
nemoclaw-blueprint/policies/openclaw-sandbox.yaml
Clarified comments to reference "OpenClaw agent notifications" and added binaries entries to the telegram and discord network policy blocks, restricting those endpoints to /usr/local/bin/node.
Messaging & productivity presets
nemoclaw-blueprint/policies/presets/discord.yaml, nemoclaw-blueprint/policies/presets/slack.yaml, nemoclaw-blueprint/policies/presets/telegram.yaml, nemoclaw-blueprint/policies/presets/outlook.yaml, nemoclaw-blueprint/policies/presets/jira.yaml
Added binaries: lists (predominantly permitting /usr/local/bin/node) to each preset’s network_policies entry; endpoint hosts/ports/rules unchanged.
Package manager & language runtimes
nemoclaw-blueprint/policies/presets/npm.yaml, nemoclaw-blueprint/policies/presets/pypi.yaml
Added binaries: entries for package manager executables (npm/npx/yarn/node for npm; pip/pip3/python3 for pypi); existing endpoint rules unchanged.
Registry & ML presets
nemoclaw-blueprint/policies/presets/docker.yaml, nemoclaw-blueprint/policies/presets/huggingface.yaml
Added binaries: allowlists: /usr/bin/docker for docker registries and /usr/local/bin/python3 plus /usr/local/bin/node for huggingface; no endpoint rule changes.
Tests
test/security-binaries-restriction.test.js
New tests that scan openclaw-sandbox.yaml and all policies/presets/*.yaml files to assert each network_policies block/file contains a binaries: section; reports offending blocks/files on failure.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through YAML fields today,

and nudged the binaries tucked away.
Now node and pip must show their face,
before they leave the sandboxed place.
Hop—secure, neat, and full of grace 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding binary restrictions to messaging and preset policies to prevent data exfiltration.
Linked Issues check ✅ Passed PR addresses all security requirements from #272: adds binaries restrictions to all affected presets (slack, discord, telegram, outlook, huggingface, docker, jira, npm, pypi) and base telegram entry, with appropriate binary paths and includes regression test.
Out of Scope Changes check ✅ Passed All changes are directly scoped to #272 requirements: adding binaries restrictions to policies and a test to prevent regressions; no unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/messaging-binaries-restriction

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
nemoclaw-blueprint/policies/presets/npm.yaml (1)

12-28: ⚠️ Potential issue | 🟠 Major

Switch npm/yarn endpoints to access: full instead of TLS termination.

binaries hardening is good, but this preset should not rely on protocol: rest + tls: terminate for npm/yarn registry traffic. That mode can break CONNECT-based flows.

🔧 Proposed fix
 network_policies:
   npm_yarn:
     name: npm_yarn
     endpoints:
       - host: registry.npmjs.org
         port: 443
-        protocol: rest
-        enforcement: enforce
-        tls: terminate
-        rules:
-          - allow: { method: GET, path: "/**" }
+        access: full
       - host: registry.yarnpkg.com
         port: 443
-        protocol: rest
-        enforcement: enforce
-        tls: terminate
-        rules:
-          - allow: { method: GET, path: "/**" }
+        access: full
     binaries:
       - { path: /usr/local/bin/npm }
       - { path: /usr/local/bin/yarn }

Based on learnings: In NemoClaw package-manager presets (including npm), use access: full instead of protocol: rest + tls: terminate because TLS termination can break CONNECT-based proxying.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nemoclaw-blueprint/policies/presets/npm.yaml` around lines 12 - 28, The
npm/yarn registry entries currently use "protocol: rest" with "tls: terminate",
which breaks CONNECT-based flows; update the entries for host:
registry.npmjs.org and host: registry.yarnpkg.com to remove or stop relying on
"protocol: rest" + "tls: terminate" and instead set the policy to use "access:
full" (preserving enforcement: enforce and the existing rules/binaries). Ensure
you replace the tls/protocol fields with access: full for both
registry.npmjs.org and registry.yarnpkg.com entries so CONNECT traffic is
allowed.
nemoclaw-blueprint/policies/presets/pypi.yaml (1)

14-25: ⚠️ Potential issue | 🟠 Major

Use CONNECT-compatible access mode for the PyPI preset.

This preset still uses protocol: rest + tls: terminate, which is fragile for package-manager traffic and can break installs/auth flows. Switch these endpoints to access: full and rely on the new binaries allowlist for process-level restriction.

Suggested patch
       - host: pypi.org
         port: 443
-        protocol: rest
+        access: full
         enforcement: enforce
-        tls: terminate
-        rules:
-          - allow: { method: GET, path: "/**" }
       - host: files.pythonhosted.org
         port: 443
-        protocol: rest
+        access: full
         enforcement: enforce
-        tls: terminate
-        rules:
-          - allow: { method: GET, path: "/**" }

Based on learnings: In nemoclaw-blueprint/policies/presets/, package-manager presets such as PyPI that use CONNECT tunneling should use access: full instead of tls: terminate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nemoclaw-blueprint/policies/presets/pypi.yaml` around lines 14 - 25, Update
the PyPI preset entries that currently specify protocol: rest and tls: terminate
to use CONNECT-compatible access by replacing those keys with access: full for
the hosts (notably the blocks containing host: files.pythonhosted.org and the
other PyPI host block), and remove the protocol/tls lines; keep the existing
enforcement and rules and rely on the binaries allowlist for process-level
restriction instead of terminating TLS.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/security-binaries-restriction.test.js`:
- Around line 60-67: The substring check using includes("binaries:") is too
weak; instead parse each preset with a real YAML parser (e.g., js-yaml's load)
and assert the parsed object contains a "binaries" key (or use a strict
line-regex like /^\s*binaries:\s*/m if you cannot add a dependency). Update the
loop that reads presets (variables: presets, PRESETS_DIR, missing, currently
using includes("binaries:")) to try yaml.load(content) and push the file to
missing when the resulting object is falsy or does not have
Object.prototype.hasOwnProperty.call(parsed, "binaries"); fall back to the regex
check only if yaml parsing fails.

---

Outside diff comments:
In `@nemoclaw-blueprint/policies/presets/npm.yaml`:
- Around line 12-28: The npm/yarn registry entries currently use "protocol:
rest" with "tls: terminate", which breaks CONNECT-based flows; update the
entries for host: registry.npmjs.org and host: registry.yarnpkg.com to remove or
stop relying on "protocol: rest" + "tls: terminate" and instead set the policy
to use "access: full" (preserving enforcement: enforce and the existing
rules/binaries). Ensure you replace the tls/protocol fields with access: full
for both registry.npmjs.org and registry.yarnpkg.com entries so CONNECT traffic
is allowed.

In `@nemoclaw-blueprint/policies/presets/pypi.yaml`:
- Around line 14-25: Update the PyPI preset entries that currently specify
protocol: rest and tls: terminate to use CONNECT-compatible access by replacing
those keys with access: full for the hosts (notably the blocks containing host:
files.pythonhosted.org and the other PyPI host block), and remove the
protocol/tls lines; keep the existing enforcement and rules and rely on the
binaries allowlist for process-level restriction instead of terminating TLS.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 98245e1e-c12f-43de-90dd-12e522f9eb2b

📥 Commits

Reviewing files that changed from the base of the PR and between 054f3e6 and 7778759.

📒 Files selected for processing (11)
  • nemoclaw-blueprint/policies/openclaw-sandbox.yaml
  • nemoclaw-blueprint/policies/presets/discord.yaml
  • nemoclaw-blueprint/policies/presets/docker.yaml
  • nemoclaw-blueprint/policies/presets/huggingface.yaml
  • nemoclaw-blueprint/policies/presets/jira.yaml
  • nemoclaw-blueprint/policies/presets/npm.yaml
  • nemoclaw-blueprint/policies/presets/outlook.yaml
  • nemoclaw-blueprint/policies/presets/pypi.yaml
  • nemoclaw-blueprint/policies/presets/slack.yaml
  • nemoclaw-blueprint/policies/presets/telegram.yaml
  • test/security-binaries-restriction.test.js

Copy link
Contributor

@cv cv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for closing the exfiltration vector — binary allowlisting is the right approach here. A few suggestions inline.

- allow: { method: GET, path: "/**" }
binaries:
- { path: /usr/local/bin/npm }
- { path: /usr/local/bin/yarn }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm, yarn, and npx are shell scripts / symlinks that spawn node under the hood. If the sandbox checks the actual process making the syscall, these entries won't match — node is the real caller. Same concern applies to pip/pip3 in the pypi preset (they're Python wrappers).

Can you verify how the sandbox engine resolves the binary? If it checks the top-level process, these are fine. If it checks the process making the network call, we need node and python3 here instead (or in addition).

Also, npx uses the same registries and should be included:

Suggested change
- { path: /usr/local/bin/yarn }
binaries:
- { path: /usr/local/bin/npm }
- { path: /usr/local/bin/npx }
- { path: /usr/local/bin/yarn }

- allow: { method: GET, path: "/**" }
binaries:
- { path: /usr/local/bin/pip }
- { path: /usr/local/bin/pip3 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same wrapper-script concern as npm — pip and pip3 are Python scripts that delegate to python3. If the sandbox checks the process making the actual network call, these won't match.

Suggested change
- { path: /usr/local/bin/pip3 }
binaries:
- { path: /usr/local/bin/pip }
- { path: /usr/local/bin/pip3 }
- { path: /usr/local/bin/python3 }


const missing = [];
for (const file of presets) {
const content = fs.readFileSync(path.join(PRESETS_DIR, file), "utf-8");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This substring check would pass if binaries: appeared in a YAML comment. The baseline test already does proper structure-aware parsing — this should be at least a regex match for a real YAML key:

Suggested change
const content = fs.readFileSync(path.join(PRESETS_DIR, file), "utf-8");
if (!/^\s+binaries:\s*$/m.test(content)) {

Copy link
Contributor

@cv cv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — good security hardening. Restricting network policies to specific binaries closes the exfiltration vector while preserving the out-of-box experience. Regression tests ensure future presets can't skip this.

@wscurran wscurran added security Something isn't secure priority: high Important issue that should be resolved in the next release labels Mar 23, 2026
…policies

Restrict messaging endpoints (Telegram, Discord) in the baseline sandbox
policy and all presets to specific binaries, preventing arbitrary processes
(curl, wget, python) from reaching messaging APIs for data exfiltration.

Closes #272
@cv cv force-pushed the fix/messaging-binaries-restriction branch from 198e3d3 to 77c03c3 Compare March 23, 2026 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: high Important issue that should be resolved in the next release security Something isn't secure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Network policy presets missing binaries restriction — any process can reach allowed endpoints

3 participants