Skip to content

fix(policy): block POST to sentry.io to prevent multi-tenant data exfiltration (#1437)#1565

Open
ColinM-sys wants to merge 1 commit intoNVIDIA:mainfrom
ColinM-sys:fix/1437-sentry-block-post-exfiltration
Open

fix(policy): block POST to sentry.io to prevent multi-tenant data exfiltration (#1437)#1565
ColinM-sys wants to merge 1 commit intoNVIDIA:mainfrom
ColinM-sys:fix/1437-sentry-block-post-exfiltration

Conversation

@ColinM-sys
Copy link
Copy Markdown

@ColinM-sys ColinM-sys commented Apr 7, 2026

Summary

Closes #1437.

The baseline sandbox network policy allowed POST to sentry.io with path: "/**". Because sentry.io is a multi-tenant SaaS — any client with a project ID can post to any Sentry project — this turned the host into a generic exfiltration channel: a compromised agent inside the sandbox could ship stack traces, environment variables, file contents, etc. to a Sentry project controlled by an attacker via the public envelope endpoint:

POST https://sentry.io/api/<any-project-id>/envelope/

Path-pattern restrictions cannot fix this on their own — the project ID is part of the URL and there is no server-side allowlist of legitimate projects from the policy engine's perspective.

This is a follow-up to #1214, which added protocol: rest to the sentry.io entry. That PR closed the wire-protocol gap; this PR closes the remaining HTTP-method-level gap.

Fix

Drop the method: POST, path: "/**" allow rule from the sentry.io endpoint in nemoclaw-blueprint/policies/openclaw-sandbox.yaml. GET stays allowed because GET has no request body and is harmless for exfiltration.

Side effect: Claude Code's crash telemetry to Sentry is silently dropped from inside the sandbox. That is the right tradeoff for a sandbox whose stated goal is preventing data egress, and the sandbox already blocks many similar telemetry channels by default.

A long inline comment in the YAML documents the rationale so a future contributor doesn't re-add the rule "to fix Sentry telemetry" without understanding why it was removed.

Test plan

  • New regression tests in test/validate-blueprint.test.ts walk every endpoint in every entry under network_policies and assert:
    1. At least one sentry.io endpoint still exists (so a future edit that removes the host entirely also gets noticed)
    2. No sentry.io endpoint has any POST allow rule
    3. sentry.io retains its GET allow rule
  • Negative case verified: stashed the YAML fix, re-ran the test against an unfixed main. The no POST allow rule assertion correctly fails, proving the test catches the bug.
  • Positive case verified: re-applied the YAML fix, re-ran the test. All 24 validate-blueprint tests pass, including the 2 new regressions.
  • No other test in the repo references sentry.io (grep -rn sentry test/ nemoclaw-blueprint/), so there is no risk of breaking unrelated coverage.

Why GET stays

GET requests cannot carry a request body. Exfiltration via GET is bounded by the URL length limit and stripped of any meaningful data structure. The realistic exfil channels (envelope, store, security report endpoints) all use POST. Keeping GET lets any read-only Sentry SDK code paths (e.g. fetching public DSN config) continue to work without re-introducing the exfiltration vector.

Summary by CodeRabbit

  • Bug Fixes

    • Tightened network access policies by restricting HTTP methods for external service communications, removing unnecessary request capabilities while maintaining essential monitoring operations
  • Tests

    • Added regression tests to validate that network policy restrictions are properly enforced across all configured endpoints

…iltration

sentry.io is a multi-tenant SaaS — any client with a project ID can POST
to any Sentry project, not just NemoClaw's. The baseline sandbox policy
allowed POST to sentry.io with path '/**', which turned the host into a
generic exfiltration channel: a compromised agent inside the sandbox
could ship stack traces, env vars, file contents, etc. to a Sentry
project controlled by an attacker via the public envelope endpoint
(https://sentry.io/api/<any-project-id>/envelope/). Path-pattern
restrictions cannot fix this because the project ID is part of the URL
and there is no server-side allowlist of legitimate projects.

This is a follow-up to NVIDIA#1214 (which added 'protocol: rest' for
sentry.io) — that PR closed the wire-protocol gap, this PR closes the
remaining HTTP-method-level gap.

Changes:

- nemoclaw-blueprint/policies/openclaw-sandbox.yaml: drop the
  'method: POST, path: /**' allow rule for sentry.io. GET stays
  allowed because GET has no request body and is harmless for exfil.
  Side effect: Claude Code's crash telemetry to Sentry is silently
  dropped. That is the correct tradeoff for a sandbox whose stated
  goal is preventing data egress, and the sandbox already blocks many
  similar telemetry channels by default.

- test/validate-blueprint.test.ts: walk every endpoint in
  network_policies, find sentry.io, and assert (a) at least one
  sentry.io entry exists, (b) no sentry.io entry has a POST allow
  rule, (c) the GET allow rule is preserved. Verified by stashing
  the policy fix and re-running: the test correctly fails on main
  with the unfixed policy, and passes with the fix in place.

Closes NVIDIA#1437
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 7, 2026

📝 Walkthrough

Walkthrough

The changes remove POST method access to sentry.io endpoints from the sandbox network policy to mitigate data exfiltration risk, and introduce regression tests to validate that sentry.io endpoints permit only GET requests.

Changes

Cohort / File(s) Summary
Policy Security Fix
nemoclaw-blueprint/policies/openclaw-sandbox.yaml
Removed POST rule for sentry.io/** endpoint, leaving only GET method allowed for that host.
Regression Tests
test/validate-blueprint.test.ts
Added helper function to traverse and filter network policy endpoints by host, plus two test cases asserting that sentry.io endpoints disallow POST and require at least one GET rule.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A hop, a skip, POST took a trip,
Away from Sentry, no more data slip!
GET stays secure, the tests now verify,
No exfiltration through the network sky. 🔒

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: blocking POST requests to sentry.io to prevent multi-tenant data exfiltration, which matches the primary objective of the changeset.
Linked Issues check ✅ Passed The pull request fully addresses issue #1437 by removing the POST rule for sentry.io in the policy file and adding regression tests to verify the fix persists.
Out of Scope Changes check ✅ Passed All changes are directly related to the issue objective: policy modification removes POST access to sentry.io and tests ensure the fix is maintained without unrelated alterations.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
test/validate-blueprint.test.ts (1)

122-130: Make the GET regression test self-contained.

If this test is run alone, it can pass vacuously when no sentry.io endpoint exists. Add a local non-empty assertion here too.

Suggested patch
   it("regression `#1437`: sentry.io retains GET (harmless, no body for exfil)", () => {
     const sentryEndpoints = findEndpoints((h) => h === "sentry.io");
+    expect(sentryEndpoints.length).toBeGreaterThan(0);
     for (const ep of sentryEndpoints) {
       const rules = Array.isArray(ep.rules) ? ep.rules : [];
       const hasGet = rules.some(
         (r) => r && r.allow && typeof r.allow.method === "string" && r.allow.method.toUpperCase() === "GET",
       );
       expect(hasGet).toBe(true);
     }
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/validate-blueprint.test.ts` around lines 122 - 130, The test currently
can pass vacuously if no sentry.io endpoints exist; update the regression test
in validate-blueprint.test.ts (the "regression `#1437`: sentry.io retains GET..."
case) to assert that the found sentryEndpoints is non-empty before checking
rules: use findEndpoints(...) result (sentryEndpoints) and add an assertion that
its length is > 0 (or that at least one endpoint object exists) so the
subsequent hasGet assertions are meaningful; keep the existing per-endpoint
hasGet check for each ep.rules to ensure a GET rule exists.
🤖 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/validate-blueprint.test.ts`:
- Around line 122-130: The test currently can pass vacuously if no sentry.io
endpoints exist; update the regression test in validate-blueprint.test.ts (the
"regression `#1437`: sentry.io retains GET..." case) to assert that the found
sentryEndpoints is non-empty before checking rules: use findEndpoints(...)
result (sentryEndpoints) and add an assertion that its length is > 0 (or that at
least one endpoint object exists) so the subsequent hasGet assertions are
meaningful; keep the existing per-endpoint hasGet check for each ep.rules to
ensure a GET rule exists.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 125af1fc-f730-4cc7-b414-1d65fc5ee6e5

📥 Commits

Reviewing files that changed from the base of the PR and between f07c788 and 1fd6e07.

📒 Files selected for processing (2)
  • nemoclaw-blueprint/policies/openclaw-sandbox.yaml
  • test/validate-blueprint.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sentry.io Allowed in Baseline Policy With POST to /** — Potential Data Exfiltration - IssueFinder - SN 13

1 participant