Skip to content

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

Merged
ericksoa merged 4 commits into
mainfrom
fix/messaging-binaries-restriction
Mar 24, 2026
Merged

fix(security): add binaries restrictions to all messaging and preset policies#645
ericksoa merged 4 commits into
mainfrom
fix/messaging-binaries-restriction

Conversation

@ericksoa

@ericksoa ericksoa commented Mar 22, 2026

Copy link
Copy Markdown
Contributor

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 reinforced 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 every network policy preset includes the required executable-level allowlist.

@coderabbitai

coderabbitai Bot commented Mar 22, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added explicit binaries: allowlists to the sandbox base policy and multiple preset network policies (restricting which executables may contact allowed endpoints) and introduced tests that assert each 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/protocols and 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 vitest suites that parse openclaw-sandbox.yaml and scan all policies/presets/*.yaml files to assert each network_policies block/file contains a binaries: section; failures report offending blocks/files.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through YAML fields today,

I tucked the binaries in their place,
So node and pip must show their way,
Before they leap from sandboxed space.
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 binaries restrictions to messaging and preset policies to prevent data exfiltration, which is the core objective of this security-focused PR.
Linked Issues check ✅ Passed The PR addresses issue #272 by adding binaries restrictions to all affected preset policies and the baseline telegram entry, though using service-specific binaries rather than the suggested openclaw-only approach.
Out of Scope Changes check ✅ Passed All changes are directly scoped to addressing the security vulnerability in #272: adding binaries restrictions to network policies and implementing regression tests to prevent recurrence.
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
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix/messaging-binaries-restriction

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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

Comment thread test/security-binaries-restriction.test.js

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

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
Copy Markdown
Collaborator

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
Copy Markdown
Collaborator

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
Copy Markdown
Collaborator

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)) {

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

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 Potential vulnerability, unsafe behavior, or access risk priority: high 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

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Binary path restrictions are consistent with existing baseline entries (openclaw_docs, npm_registry). The test enforces that all future network_policies entries and presets include a binaries: section.

Two notes for awareness (not blocking):

  1. The restriction is path-based. An attacker with write access to /usr/local/bin could replace or symlink an allowed binary. This is defense-in-depth, not a hard boundary — consistent with how the existing policies use this field.
  2. node -e allows arbitrary HTTP requests that satisfy the /usr/local/bin/node path check. Inherent to interpreter-based restrictions.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
test/security-binaries-restriction.test.js (1)

54-60: Minor inconsistency with baseline test regex.

The baseline test (line 43) uses /^\s+binaries:/ which accepts inline values (e.g., binaries: [/usr/bin/node]), while this preset test uses /^\s+binaries:\s*$/m which requires binaries: to be on its own line. This is fine if all presets use the multi-line list format, but could cause false negatives if someone adds a preset with inline syntax.

For consistency, consider aligning with the baseline approach:

Optional: align regex with baseline test
     for (const file of presets) {
       const content = fs.readFileSync(path.join(PRESETS_DIR, file), "utf-8");
-      if (!/^\s+binaries:\s*$/m.test(content)) {
+      if (!/^\s+binaries:/m.test(content)) {
         missing.push(file);
       }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/security-binaries-restriction.test.js` around lines 54 - 60, The preset
test currently uses a stricter regex (/^\s+binaries:\s*$/m) that requires
"binaries:" to be on its own line; update the check in the loop that reads
PRESETS_DIR (where presets, missing, and content are used) to use the same
relaxed pattern as the baseline (e.g., match /^\s+binaries:/ with the m flag) so
inline values like "binaries: [/usr/bin/node]" are accepted; locate the for loop
over presets and replace the regex used in the if condition accordingly to align
behavior with the baseline test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/security-binaries-restriction.test.js`:
- Around line 54-60: The preset test currently uses a stricter regex
(/^\s+binaries:\s*$/m) that requires "binaries:" to be on its own line; update
the check in the loop that reads PRESETS_DIR (where presets, missing, and
content are used) to use the same relaxed pattern as the baseline (e.g., match
/^\s+binaries:/ with the m flag) so inline values like "binaries:
[/usr/bin/node]" are accepted; locate the for loop over presets and replace the
regex used in the if condition accordingly to align behavior with the baseline
test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 993cdcd6-d3ab-48be-a3ad-5037cccdfc9a

📥 Commits

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

📒 Files selected for processing (1)
  • test/security-binaries-restriction.test.js

@ericksoa ericksoa merged commit de2554f into main Mar 24, 2026
5 checks passed
jessesanford pushed a commit to jessesanford/NemoClaw that referenced this pull request Mar 24, 2026
…policies (NVIDIA#645)

* fix(security): add binaries restrictions to all messaging and preset 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 NVIDIA#272

* fix: add interpreter binaries to npm/pypi presets, strengthen test regex

* fix: convert node:test to vitest in security-binaries-restriction.test.js

---------

Co-authored-by: Carlos Villela <cvillela@nvidia.com>
temrjan pushed a commit to temrjan/NemoClaw that referenced this pull request Mar 25, 2026
…policies (NVIDIA#645)

* fix(security): add binaries restrictions to all messaging and preset 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 NVIDIA#272

* fix: add interpreter binaries to npm/pypi presets, strengthen test regex

* fix: convert node:test to vitest in security-binaries-restriction.test.js

---------

Co-authored-by: Carlos Villela <cvillela@nvidia.com>
@cv cv deleted the fix/messaging-binaries-restriction branch March 25, 2026 22:47
jacobtomlinson pushed a commit to jacobtomlinson/NemoClaw that referenced this pull request Apr 30, 2026
…policies (NVIDIA#645)

* fix(security): add binaries restrictions to all messaging and preset 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 NVIDIA#272

* fix: add interpreter binaries to npm/pypi presets, strengthen test regex

* fix: convert node:test to vitest in security-binaries-restriction.test.js

---------

Co-authored-by: Carlos Villela <cvillela@nvidia.com>
@wscurran wscurran added bug-fix PR fixes a bug or regression and removed priority: high labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PR fixes a bug or regression security Potential vulnerability, unsafe behavior, or access risk

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

4 participants