Skip to content

fix(security): validate Hermes endpoint URL and reject allowed_ips in user presets - #6087

Merged
cv merged 10 commits into
mainfrom
fix/ssrf-validation-gaps-6072-6073-v2
Jul 1, 2026
Merged

fix(security): validate Hermes endpoint URL and reject allowed_ips in user presets#6087
cv merged 10 commits into
mainfrom
fix/ssrf-validation-gaps-6072-6073-v2

Conversation

@prekshivyas

@prekshivyas prekshivyas commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes two SSRF gaps found during a security review of NemoClaw's policy and onboarding flows. Neither gap was exploitable through the sandboxed agent — both required user-level access to the CLI.

Related Issue

Fixes #6072
Fixes #6073

Changes

  • src/lib/onboard/inference-providers/hermes.ts: call isPrivateHostname() on the user-supplied endpointUrl before it is persisted and passed to OpenShell as OPENAI_BASE_URL. Previously the URL bypassed all SSRF checks until plugin-side validateEndpointUrl() fired at inference time — after credentials could already have been dispatched to an internal host.
  • src/lib/policy/index.ts: reject user-supplied preset files (--from-file / --from-dir) that declare allowed_ips in any network_policies endpoint. The merge was previously a blind structural pass-through that let callers expand the private-IP allowlist that OpenShell enforces.
  • src/lib/onboard/inference-providers/hermes.test.ts: 8 new unit tests covering loopback, link-local (169.254.x.x), RFC-1918, .internal TLD, malformed URLs, public endpoint acceptance, and null pass-through.
  • src/lib/policy/preset-allowed-ips.test.ts: 4 new unit tests covering single-policy rejection, multi-policy rejection, clean preset acceptance, and endpoint-without-allowed_ips acceptance.
  • test/e2e/live/onboard-negative-paths.test.ts: E2E test asserting nemoclaw policy-add --from-file exits non-zero and prints an allowed_ips/not-permitted error for a user-supplied preset that contains allowed_ips. Exits before any sandbox interaction so no live infra required beyond the compiled CLI.

Type of Change

  • Code change (feature, bug fix, or refactor)

Quality Gates

E2E Coverage

Required runs (per E2E advisor): hermes-e2e, network-policy — dispatch against this branch.

New E2E in this PR: policy-add --from-file allowed_ips rejection — lightweight, no sandbox required.

Hermes onboarding SSRF rejection E2E (suggested by advisor): requires full Hermes sandbox setup (~70 min). Unit tests already cover the validation logic; follow-up issue to be filed.

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Git hooks passed during commit and push, or npx prek run --from-ref main --to-ref HEAD passes
  • Targeted tests pass for changed behavior
  • No secrets, API keys, or credentials committed

Signed-off-by: Prekshi Vyas prekshiv@nvidia.com

Summary by CodeRabbit

  • Bug Fixes
    • Tightened validation for network endpoints and preset content to block unsafe or internal addresses.
    • Rejected malformed URLs, unsupported schemes, embedded credentials, and private/internal hostnames.
    • Prevented presets with disallowed IP-based endpoint rules from being loaded or applied.
    • Added end-to-end coverage for failed preset imports and safer handling of valid public endpoints.

prekshivyas and others added 2 commits June 30, 2026 19:01
… user presets

Fixes two SSRF gaps identified in issues #6072 and #6073.

1. src/lib/onboard/inference-providers/hermes.ts: call isPrivateHostname()
   on the user-supplied endpointUrl before passing it downstream as
   OPENAI_BASE_URL. Previously the URL bypassed all SSRF checks until
   plugin-side validateEndpointUrl() fired at inference time — too late
   to prevent credential dispatch to an internal host.

2. src/lib/policy/index.ts: reject user-supplied preset files that
   declare allowed_ips in any network_policies endpoint. The merge was
   previously a blind structural pass-through that let callers expand
   the private-IP allowlist OpenShell enforces.

Fixes #6072
Fixes #6073

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Codebase growth guardrail bans if statements in test files.
Replace requireValue mock body with a single expression.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds endpoint URL validation for Hermes onboarding and rejects user-supplied policy presets that include allowed_ips in network_policies. Tests cover rejection and acceptance cases for both paths.

Changes

Hermes inference endpoint SSRF validation

Layer / File(s) Summary
Endpoint URL validation implementation
src/lib/onboard/inference-providers/hermes.ts
Parses endpointUrl as a URL, rejects unsupported schemes and embedded credentials, and blocks private or internal hostnames via isPrivateHostname.
SSRF guard test suite
src/lib/onboard/inference-providers/hermes.test.ts
Adds stubbed dependency setup and tests for private hostnames, malformed URLs, unsupported schemes, embedded credentials, rejected endpoints, public HTTPS endpoints, and null endpointUrl.

Policy preset allowed_ips rejection

Layer / File(s) Summary
Preset allowed_ips validation
src/lib/policy/index.ts
Adds networkPoliciesHasAllowedIps(), rejects custom preset content in applyPresetContent(), and rejects file-loaded presets in loadPresetFromFile() when any endpoint contains allowed_ips.
Preset allowed_ips test suite
src/lib/policy/preset-allowed-ips.test.ts, test/e2e/live/onboard-negative-paths.test.ts
Adds temp-file YAML helpers, loadPresetFromFile rejection and acceptance cases, an applyPresetContent rejection case, and an E2E CLI check for allowed_ips rejection.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#2077 — Also touches YAML preset ingestion for policy-add --from-file/--from-dir and related preset validation flow.

Suggested labels: area: onboarding, area: policy, bug-fix

Suggested reviewers: ericksoa, cv, jyaunches

🚥 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 summarizes the Hermes endpoint validation and allowed_ips preset rejection changes.
Linked Issues check ✅ Passed The code adds Hermes SSRF checks and rejects allowed_ips in user presets, matching issues #6072 and #6073.
Out of Scope Changes check ✅ Passed The changes are focused on the two security fixes and their tests, with no clear unrelated additions.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ssrf-validation-gaps-6072-6073-v2

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

@github-code-quality

github-code-quality Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the fix/ssrf-validation-... branch is 96%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/ssrf-validation-... 378534b +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the fix/ssrf-validation-... branch is 68%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/ssrf-validation-... 378534b +/-
src/lib/actions...dbox/rebuild.ts 80%
src/lib/actions...all/run-plan.ts 80%
src/lib/state/o...oard-session.ts 80%
src/lib/shields/index.ts 75%
src/lib/state/sandbox.ts 72%
src/lib/onboard/preflight.ts 69%
src/lib/onboard...er-gpu-patch.ts 59%
src/lib/actions...licy-channel.ts 58%
src/lib/policy/index.ts 56%
src/lib/onboard.ts 20%

Updated July 01, 2026 22:24 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@prekshivyas prekshivyas added security area: security Security controls, permissions, secrets, or hardening labels Jul 1, 2026
@prekshivyas prekshivyas self-assigned this Jul 1, 2026
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Informational

Merge posture: Informational / low confidence
Primary next action: Resolve or justify PRA-1: PR review advisor unavailable.
Open items: 0 required · 1 warning · 0 suggestions · 1 test follow-up
Top item: PR review advisor unavailable

Action checklist

  • PRA-1 Resolve or justify: PR review advisor unavailable
  • PRA-T1 Add or justify test follow-up: Runtime validation

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify correctness Re-run the PR Review Advisor or perform a manual review.
Review findings by urgency: 0 required fixes, 1 item to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — PR review advisor unavailable

  • Location: not file-specific
  • Category: correctness
  • Problem: The automated advisor could not complete: Could not parse JSON from PR review advisor output; see /home/runner/work/NemoClaw/NemoClaw/artifacts/pr-review-advisor-nemotron-ultra/pr-review-advisor-retry-raw-output.txt
  • Impact: Automated review evidence is incomplete, so human review must cover the changed code manually.
  • Recommended action: Re-run the PR Review Advisor or perform a manual review.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the workflow logs and raw advisor artifact for the execution failure.
  • Missing regression test: No regression test recommendation is available because the advisor did not complete.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the workflow logs and raw advisor artifact for the execution failure.
  • Evidence: Could not parse JSON from PR review advisor output; see /home/runner/work/NemoClaw/NemoClaw/artifacts/pr-review-advisor-nemotron-ultra/pr-review-advisor-retry-raw-output.txt

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Add or identify targeted runtime/integration validation for the changed behavior; do not report external E2E job pass/fail here.. Runtime/sandbox/infrastructure paths need behavioral runtime validation: src/lib/onboard/inference-providers/hermes.ts, src/lib/onboard/inference-providers/types.ts, src/lib/policy/index.ts.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Changes requested

Merge posture: Do not merge yet
Primary next action: Fix PRA-3: host.openshell.internal allowed_ips exemption is still host-only and too broad; then add or justify PRA-T1.
Open items: 1 required · 4 warnings · 1 suggestion · 8 test follow-ups
Since last review: 0 prior items resolved · 6 still apply · 0 new items found

Action checklist

  • PRA-3 Fix: host.openshell.internal allowed_ips exemption is still host-only and too broad in src/lib/policy/index.ts:139
  • PRA-1 Resolve or justify: Source-of-truth review needed: Custom preset allowed_ips rejection before merge/apply
  • PRA-2 Resolve or justify: Source-of-truth review needed: host.openshell.internal allowed_ips exemption for user presets
  • PRA-4 Resolve or justify: applyPresetContent allowed_ips test does not prove the no-side-effects boundary in src/lib/policy/preset-allowed-ips.test.ts:211
  • PRA-5 Resolve or justify: Hermes DNS-pinning tests do not lock the downstream baseUrl and smoke contract in src/lib/onboard/inference-providers/hermes.test.ts:219
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Runtime validation
  • PRA-T6 Add or justify test follow-up: applyPresetContent allowed_ips test does not prove the no-side-effects boundary
  • PRA-T7 Add or justify test follow-up: Hermes DNS-pinning tests do not lock the downstream baseUrl and smoke contract
  • PRA-T8 Add or justify test follow-up: Acceptance clause
  • PRA-6 In-scope improvement: Extract custom preset allowed_ips validation out of the policy monolith in src/lib/policy/index.ts:111

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Required security src/lib/policy/index.ts:139 Either disallow allowed_ips entirely in user-supplied presets, or encode a narrow documented bridge shape: exact host, explicit allowed protocol, explicit unprivileged permitted port set/range, allowed_ips values matching the intended bridge policy, and narrow rules/enforcement. Keep the boundary at loadPresetFromFile() and applyPresetContent(custom).
PRA-4 Resolve/justify tests src/lib/policy/preset-allowed-ips.test.ts:211 Add a focused unit test around the custom allowed_ips path that observes the runner and registry boundaries. If current module globals make this brittle, extract a small dependency-injected helper for the custom preset apply path and assert the guard returns before any policy get/set or registry mutation.
PRA-5 Resolve/justify tests src/lib/onboard/inference-providers/hermes.test.ts:219 Add caller-contract tests around the injected hermesProviderAuth and verifyOnboardInferenceSmoke dependencies. Cover HTTP DNS pinning, HTTPS hostname preservation, and rejection ordering before credential setup.
PRA-6 Improvement architecture src/lib/policy/index.ts:111 Move networkPoliciesHasAllowedIps(), endpointHostIsGatewayBridge(), and any final bridge-shape validator into a small policy preset validation helper/module. Keep loadPresetFromFile() and applyPresetContent() as callers and preserve the same trust-boundary behavior and tests.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-3 Required — host.openshell.internal allowed_ips exemption is still host-only and too broad

  • Location: src/lib/policy/index.ts:139
  • Category: security
  • Problem: The new guard rejects allowed_ips for non-bridge endpoints, but it permits any endpoint whose host normalizes to host.openshell.internal. It does not validate protocol, explicit unprivileged port, enforcement/rule shape, or allowed_ips contents. The linked issue's expected behavior was to reject or strip private-range allowed_ips not present in the base policy, or disallow allowed_ips entirely in user-supplied presets.
  • Impact: A user-supplied custom preset can still widen sandbox-to-host/private egress through the OpenShell host-gateway alias by pinning broad private ranges such as 10.0.0.0/8 or 192.168.0.0/16 on arbitrary bridge endpoint shapes.
  • Required action: Either disallow allowed_ips entirely in user-supplied presets, or encode a narrow documented bridge shape: exact host, explicit allowed protocol, explicit unprivileged permitted port set/range, allowed_ips values matching the intended bridge policy, and narrow rules/enforcement. Keep the boundary at loadPresetFromFile() and applyPresetContent(custom).
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read networkPoliciesHasAllowedIps() in src/lib/policy/index.ts around the endpointHostIsGatewayBridge() continue branch, compare src/lib/actions/inference-set.ts normalizeCustomEndpointUrl() where the same hostname exemption is limited to HTTP plus an explicit unprivileged port, then inspect the host-gateway positive test in src/lib/policy/preset-allowed-ips.test.ts.
  • Missing regression test: Add tests that reject user preset allowed_ips on host.openshell.internal with a missing port, a privileged port, unsupported/missing protocol or broad rules, and broad private allowed_ips ranges; if an exemption remains, add one positive test for only the documented safe bridge shape.
  • Done when: The required change is committed and verification passes: Read networkPoliciesHasAllowedIps() in src/lib/policy/index.ts around the endpointHostIsGatewayBridge() continue branch, compare src/lib/actions/inference-set.ts normalizeCustomEndpointUrl() where the same hostname exemption is limited to HTTP plus an explicit unprivileged port, then inspect the host-gateway positive test in src/lib/policy/preset-allowed-ips.test.ts.
  • Evidence: networkPoliciesHasAllowedIps() continues past any endpoint with host host.openshell.internal, and the changed test accepts a user preset with host.openshell.internal plus allowed_ips entries 10.0.0.0/8 and 192.168.0.0/16.
Review findings by urgency: 1 required fix, 4 items to resolve/justify, 1 in-scope improvement

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: Custom preset allowed_ips rejection before merge/apply

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Loader unit tests and live network-policy E2E reject non-bridge allowed_ips, but a focused applyPresetContent(custom) no-side-effects unit test is still missing.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: networkPoliciesHasAllowedIps() is called from both loadPresetFromFile() and applyPresetContent(custom), but the apply test currently asserts only false.

PRA-2 Resolve/justify — Source-of-truth review needed: host.openshell.internal allowed_ips exemption for user presets

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: There is a positive bridge acceptance test and a mixed non-bridge rejection test, but no tests define or enforce safe bridge protocol, port, rule, enforcement, or allowed_ips ranges.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: endpointHostIsGatewayBridge() checks only the host string and networkPoliciesHasAllowedIps() continues past allowed_ips for that endpoint.

PRA-4 Resolve/justify — applyPresetContent allowed_ips test does not prove the no-side-effects boundary

  • Location: src/lib/policy/preset-allowed-ips.test.ts:211
  • Category: tests
  • Problem: The custom-preset test name says rejection happens before side effects, but the assertion only checks that applyPresetContent() returns false. The implementation currently returns before policy get/set, temp-file creation, and registry writes, but the test would still pass if a future refactor performed those side effects and returned false afterward.
  • Impact: A regression could apply a rejected policy, read or overwrite live OpenShell policy state, create temp policy files, or persist the custom preset in the registry while still satisfying the current test.
  • Recommended action: Add a focused unit test around the custom allowed_ips path that observes the runner and registry boundaries. If current module globals make this brittle, extract a small dependency-injected helper for the custom preset apply path and assert the guard returns before any policy get/set or registry mutation.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect applyPresetContent() in src/lib/policy/index.ts: the custom allowed_ips guard is before extractPresetEntries(), runCapture(buildPolicyGetCommand()), assertOpenshellResolvable(), temp file creation, run(buildPolicySetCommand()), and registry updates; then inspect the test at src/lib/policy/preset-allowed-ips.test.ts around the single return-value assertion.
  • Missing regression test: Add `applyPresetContent(custom) rejects allowed_ips before policy get/set/temp-file creation/registry mutation`, with spies or injected dependencies proving no runCapture, run, assertOpenshellResolvable, fs.mkdtempSync/writeFileSync, registry.addCustomPolicy, or registry.updateSandbox call occurs.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect applyPresetContent() in src/lib/policy/index.ts: the custom allowed_ips guard is before extractPresetEntries(), runCapture(buildPolicyGetCommand()), assertOpenshellResolvable(), temp file creation, run(buildPolicySetCommand()), and registry updates; then inspect the test at src/lib/policy/preset-allowed-ips.test.ts around the single return-value assertion.
  • Evidence: The test calls applyPresetContent(..., { custom }) and expects false, but does not observe any side-effect dependency.

PRA-5 Resolve/justify — Hermes DNS-pinning tests do not lock the downstream baseUrl and smoke contract

  • Location: src/lib/onboard/inference-providers/hermes.test.ts:219
  • Category: tests
  • Problem: The Hermes tests cover many rejected inputs and public-host acceptance, but accepted-path tests only assert that runOpenshell was called. They do not assert that the validated endpoint value is passed to ensureHermesProviderApiKeyCredentials()/ensureHermesProviderOAuthCredentials() and verifyOnboardInferenceSmoke(), nor that rejected endpoints stop before credential setup.
  • Impact: A future change could validate an endpoint for logging only, then pass the original unpinned or unsafe value to Hermes provider registration or smoke verification while the current tests still pass.
  • Recommended action: Add caller-contract tests around the injected hermesProviderAuth and verifyOnboardInferenceSmoke dependencies. Cover HTTP DNS pinning, HTTPS hostname preservation, and rejection ordering before credential setup.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read setupHermesProviderInference() in src/lib/onboard/inference-providers/hermes.ts where resolvedEndpointUrl is passed as baseUrl and smoke endpointUrl, then inspect hermes.test.ts accepted-path assertions that currently stop at runOpenshell.
  • Missing regression test: Add `passes the DNS-pinned HTTP endpoint to Hermes credential setup and smoke verification`, `preserves the validated HTTPS hostname for Hermes credential setup and smoke verification`, and `does not call Hermes credential setup, runOpenshell, smoke verification, or registry update when endpoint validation fails`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read setupHermesProviderInference() in src/lib/onboard/inference-providers/hermes.ts where resolvedEndpointUrl is passed as baseUrl and smoke endpointUrl, then inspect hermes.test.ts accepted-path assertions that currently stop at runOpenshell.
  • Evidence: The acceptance tests for public endpoints resolve to { ok: true } and check deps.runOpenshell, but do not inspect ensureHermesProviderApiKeyCredentials/ensureHermesProviderOAuthCredentials or verifyOnboardInferenceSmoke arguments.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

PRA-6 Improvement — Extract custom preset allowed_ips validation out of the policy monolith

  • Location: src/lib/policy/index.ts:111
  • Category: architecture
  • Problem: The policy module is an active large-file hotspot and this PR adds security validation helpers directly into it. The helper is security-relevant and should remain, but it would be easier to test and maintain as a small policy preset validation module with focused exports.
  • Impact: Keeping the scanner and bridge-shape policy embedded in a 1300+ line module makes later security review and dependency injection for no-side-effects tests harder, especially with concurrent active PRs touching the same file.
  • Suggested action: Move networkPoliciesHasAllowedIps(), endpointHostIsGatewayBridge(), and any final bridge-shape validator into a small policy preset validation helper/module. Keep loadPresetFromFile() and applyPresetContent() as callers and preserve the same trust-boundary behavior and tests.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Inspect the new helper block near src/lib/policy/index.ts:111 and the two call sites in loadPresetFromFile() and applyPresetContent(custom).
  • Missing regression test: Existing preset-allowed-ips tests can be retargeted to the extracted helper plus the two caller boundaries; keep behavior tests for loader rejection, applyPresetContent rejection, non-bridge rejection, and any narrowed bridge exemption.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Drift context reports src/lib/policy/index.ts grows by 53 lines to 1384 lines, and open PRs overlap the same policy file.
Simplification opportunities: 1 possible cut

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-6 shrink (src/lib/policy/index.ts:111): Inline allowed_ips scanner and bridge-host helper from src/lib/policy/index.ts
    • Replacement: A small policy preset validation module imported by policy/index.ts and tested directly
    • Safety boundary: Do not weaken the custom preset allowed_ips rejection, host-gateway validation, symlink/file-size checks, or policy apply no-side-effects boundary.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — rejects user preset allowed_ips on host.openshell.internal without an explicit unprivileged port. Changed code affects sandbox policy application, DNS/SSRF validation, and Hermes provider setup. Unit coverage is strong for many negative paths and live E2E covers non-bridge policy-add rejection, but several boundary contracts are not locked by automated tests.
  • PRA-T2 Runtime validation — rejects user preset allowed_ips on host.openshell.internal with a privileged port. Changed code affects sandbox policy application, DNS/SSRF validation, and Hermes provider setup. Unit coverage is strong for many negative paths and live E2E covers non-bridge policy-add rejection, but several boundary contracts are not locked by automated tests.
  • PRA-T3 Runtime validation — rejects user preset allowed_ips on host.openshell.internal when protocol or rules are outside the documented bridge shape. Changed code affects sandbox policy application, DNS/SSRF validation, and Hermes provider setup. Unit coverage is strong for many negative paths and live E2E covers non-bridge policy-add rejection, but several boundary contracts are not locked by automated tests.
  • PRA-T4 Runtime validation — passes the DNS-pinned HTTP endpoint to Hermes credential setup and smoke verification. Changed code affects sandbox policy application, DNS/SSRF validation, and Hermes provider setup. Unit coverage is strong for many negative paths and live E2E covers non-bridge policy-add rejection, but several boundary contracts are not locked by automated tests.
  • PRA-T5 Runtime validation — preserves the validated HTTPS hostname for Hermes credential setup and smoke verification. Changed code affects sandbox policy application, DNS/SSRF validation, and Hermes provider setup. Unit coverage is strong for many negative paths and live E2E covers non-bridge policy-add rejection, but several boundary contracts are not locked by automated tests.
  • PRA-T6 applyPresetContent allowed_ips test does not prove the no-side-effects boundary — Add a focused unit test around the custom allowed_ips path that observes the runner and registry boundaries. If current module globals make this brittle, extract a small dependency-injected helper for the custom preset apply path and assert the guard returns before any policy get/set or registry mutation.
  • PRA-T7 Hermes DNS-pinning tests do not lock the downstream baseUrl and smoke contract — Add caller-contract tests around the injected hermesProviderAuth and verifyOnboardInferenceSmoke dependencies. Cover HTTP DNS pinning, HTTPS hostname preservation, and rejection ordering before credential setup.
  • PRA-T8 Acceptance clausesecurity(onboarding): Hermes inference endpoint URL skips SSRF validation before being persisted #6072 attack path items 3-4: "Flows into `src/lib/onboard/inference-providers/hermes.ts:88-96` → `ensureHermesProviderApiKeyCredentials()` / `ensureHermesProviderOAuthCredentials()`" and "Passed to `registerHermesInferenceProvider()` → `onboardProviders.upsertProvider()` → configured as `OPENAI_BASE_URL` env var for OpenShell" — add test evidence or identify existing coverage. Implementation now passes resolvedEndpointUrl to Hermes credential prep, but tests do not assert the validated/pinned value reaches ensureHermesProvider*Credentials() or verifyOnboardInferenceSmoke(), nor that rejected endpoints stop before credential setup.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Custom preset allowed_ips rejection before merge/apply

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Loader unit tests and live network-policy E2E reject non-bridge allowed_ips, but a focused applyPresetContent(custom) no-side-effects unit test is still missing.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: networkPoliciesHasAllowedIps() is called from both loadPresetFromFile() and applyPresetContent(custom), but the apply test currently asserts only false.

PRA-2 Resolve/justify — Source-of-truth review needed: host.openshell.internal allowed_ips exemption for user presets

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: There is a positive bridge acceptance test and a mixed non-bridge rejection test, but no tests define or enforce safe bridge protocol, port, rule, enforcement, or allowed_ips ranges.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: endpointHostIsGatewayBridge() checks only the host string and networkPoliciesHasAllowedIps() continues past allowed_ips for that endpoint.

PRA-3 Required — host.openshell.internal allowed_ips exemption is still host-only and too broad

  • Location: src/lib/policy/index.ts:139
  • Category: security
  • Problem: The new guard rejects allowed_ips for non-bridge endpoints, but it permits any endpoint whose host normalizes to host.openshell.internal. It does not validate protocol, explicit unprivileged port, enforcement/rule shape, or allowed_ips contents. The linked issue's expected behavior was to reject or strip private-range allowed_ips not present in the base policy, or disallow allowed_ips entirely in user-supplied presets.
  • Impact: A user-supplied custom preset can still widen sandbox-to-host/private egress through the OpenShell host-gateway alias by pinning broad private ranges such as 10.0.0.0/8 or 192.168.0.0/16 on arbitrary bridge endpoint shapes.
  • Required action: Either disallow allowed_ips entirely in user-supplied presets, or encode a narrow documented bridge shape: exact host, explicit allowed protocol, explicit unprivileged permitted port set/range, allowed_ips values matching the intended bridge policy, and narrow rules/enforcement. Keep the boundary at loadPresetFromFile() and applyPresetContent(custom).
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read networkPoliciesHasAllowedIps() in src/lib/policy/index.ts around the endpointHostIsGatewayBridge() continue branch, compare src/lib/actions/inference-set.ts normalizeCustomEndpointUrl() where the same hostname exemption is limited to HTTP plus an explicit unprivileged port, then inspect the host-gateway positive test in src/lib/policy/preset-allowed-ips.test.ts.
  • Missing regression test: Add tests that reject user preset allowed_ips on host.openshell.internal with a missing port, a privileged port, unsupported/missing protocol or broad rules, and broad private allowed_ips ranges; if an exemption remains, add one positive test for only the documented safe bridge shape.
  • Done when: The required change is committed and verification passes: Read networkPoliciesHasAllowedIps() in src/lib/policy/index.ts around the endpointHostIsGatewayBridge() continue branch, compare src/lib/actions/inference-set.ts normalizeCustomEndpointUrl() where the same hostname exemption is limited to HTTP plus an explicit unprivileged port, then inspect the host-gateway positive test in src/lib/policy/preset-allowed-ips.test.ts.
  • Evidence: networkPoliciesHasAllowedIps() continues past any endpoint with host host.openshell.internal, and the changed test accepts a user preset with host.openshell.internal plus allowed_ips entries 10.0.0.0/8 and 192.168.0.0/16.

PRA-4 Resolve/justify — applyPresetContent allowed_ips test does not prove the no-side-effects boundary

  • Location: src/lib/policy/preset-allowed-ips.test.ts:211
  • Category: tests
  • Problem: The custom-preset test name says rejection happens before side effects, but the assertion only checks that applyPresetContent() returns false. The implementation currently returns before policy get/set, temp-file creation, and registry writes, but the test would still pass if a future refactor performed those side effects and returned false afterward.
  • Impact: A regression could apply a rejected policy, read or overwrite live OpenShell policy state, create temp policy files, or persist the custom preset in the registry while still satisfying the current test.
  • Recommended action: Add a focused unit test around the custom allowed_ips path that observes the runner and registry boundaries. If current module globals make this brittle, extract a small dependency-injected helper for the custom preset apply path and assert the guard returns before any policy get/set or registry mutation.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect applyPresetContent() in src/lib/policy/index.ts: the custom allowed_ips guard is before extractPresetEntries(), runCapture(buildPolicyGetCommand()), assertOpenshellResolvable(), temp file creation, run(buildPolicySetCommand()), and registry updates; then inspect the test at src/lib/policy/preset-allowed-ips.test.ts around the single return-value assertion.
  • Missing regression test: Add `applyPresetContent(custom) rejects allowed_ips before policy get/set/temp-file creation/registry mutation`, with spies or injected dependencies proving no runCapture, run, assertOpenshellResolvable, fs.mkdtempSync/writeFileSync, registry.addCustomPolicy, or registry.updateSandbox call occurs.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect applyPresetContent() in src/lib/policy/index.ts: the custom allowed_ips guard is before extractPresetEntries(), runCapture(buildPolicyGetCommand()), assertOpenshellResolvable(), temp file creation, run(buildPolicySetCommand()), and registry updates; then inspect the test at src/lib/policy/preset-allowed-ips.test.ts around the single return-value assertion.
  • Evidence: The test calls applyPresetContent(..., { custom }) and expects false, but does not observe any side-effect dependency.

PRA-5 Resolve/justify — Hermes DNS-pinning tests do not lock the downstream baseUrl and smoke contract

  • Location: src/lib/onboard/inference-providers/hermes.test.ts:219
  • Category: tests
  • Problem: The Hermes tests cover many rejected inputs and public-host acceptance, but accepted-path tests only assert that runOpenshell was called. They do not assert that the validated endpoint value is passed to ensureHermesProviderApiKeyCredentials()/ensureHermesProviderOAuthCredentials() and verifyOnboardInferenceSmoke(), nor that rejected endpoints stop before credential setup.
  • Impact: A future change could validate an endpoint for logging only, then pass the original unpinned or unsafe value to Hermes provider registration or smoke verification while the current tests still pass.
  • Recommended action: Add caller-contract tests around the injected hermesProviderAuth and verifyOnboardInferenceSmoke dependencies. Cover HTTP DNS pinning, HTTPS hostname preservation, and rejection ordering before credential setup.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read setupHermesProviderInference() in src/lib/onboard/inference-providers/hermes.ts where resolvedEndpointUrl is passed as baseUrl and smoke endpointUrl, then inspect hermes.test.ts accepted-path assertions that currently stop at runOpenshell.
  • Missing regression test: Add `passes the DNS-pinned HTTP endpoint to Hermes credential setup and smoke verification`, `preserves the validated HTTPS hostname for Hermes credential setup and smoke verification`, and `does not call Hermes credential setup, runOpenshell, smoke verification, or registry update when endpoint validation fails`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read setupHermesProviderInference() in src/lib/onboard/inference-providers/hermes.ts where resolvedEndpointUrl is passed as baseUrl and smoke endpointUrl, then inspect hermes.test.ts accepted-path assertions that currently stop at runOpenshell.
  • Evidence: The acceptance tests for public endpoints resolve to { ok: true } and check deps.runOpenshell, but do not inspect ensureHermesProviderApiKeyCredentials/ensureHermesProviderOAuthCredentials or verifyOnboardInferenceSmoke arguments.

PRA-6 Improvement — Extract custom preset allowed_ips validation out of the policy monolith

  • Location: src/lib/policy/index.ts:111
  • Category: architecture
  • Problem: The policy module is an active large-file hotspot and this PR adds security validation helpers directly into it. The helper is security-relevant and should remain, but it would be easier to test and maintain as a small policy preset validation module with focused exports.
  • Impact: Keeping the scanner and bridge-shape policy embedded in a 1300+ line module makes later security review and dependency injection for no-side-effects tests harder, especially with concurrent active PRs touching the same file.
  • Suggested action: Move networkPoliciesHasAllowedIps(), endpointHostIsGatewayBridge(), and any final bridge-shape validator into a small policy preset validation helper/module. Keep loadPresetFromFile() and applyPresetContent() as callers and preserve the same trust-boundary behavior and tests.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Inspect the new helper block near src/lib/policy/index.ts:111 and the two call sites in loadPresetFromFile() and applyPresetContent(custom).
  • Missing regression test: Existing preset-allowed-ips tests can be retargeted to the extracted helper plus the two caller boundaries; keep behavior tests for loader rejection, applyPresetContent rejection, non-bridge rejection, and any narrowed bridge exemption.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Drift context reports src/lib/policy/index.ts grows by 53 lines to 1384 lines, and open PRs overlap the same policy file.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: network-policy, hermes-inference-switch, hermes-e2e
Optional E2E: inference-routing, onboard-negative-paths

Dispatch hint: network-policy,hermes-inference-switch,hermes-e2e

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • network-policy (high): Required because the PR changes user-supplied network policy preset validation and the sandbox egress security boundary. This job runs test/e2e/live/network-policy.test.ts, including the newly added real-sandbox allowed_ips rejection and the host.openshell.internal bridge allow/deny probes.
  • hermes-inference-switch (high): Required because Hermes endpoint URL validation and DNS pinning affect explicit/custom endpoint inference setup. This job exercises Hermes inference switching through hosted and compatible endpoint modes against a live sandbox.
  • hermes-e2e (high): Required because setupHermesProviderInference participates in Hermes onboarding/credential preparation and live inference. The full Hermes E2E verifies the managed/default endpoint path still onboards and serves real assistant inference after the new endpoint validation logic.

Optional E2E

  • inference-routing (high): Optional adjacent confidence for generic inference-route error handling and compatible endpoint onboarding, but the modified provider-specific path is Hermes and is better covered by hermes-inference-switch/hermes-e2e.
  • onboard-negative-paths (medium): Optional only: the file changed is comment-only, but this job remains adjacent to onboarding negative-path behavior if maintainers want extra confirmation.

New E2E recommendations

  • None.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: network-policy,hermes-inference-switch,hermes-e2e

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: network-policy, onboard-negative-paths
Optional E2E targets: None

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=network-policy
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-negative-paths

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • network-policy: Focused free-standing E2E job wired for changed live test test/e2e/live/network-policy.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=network-policy
  • onboard-negative-paths: Focused free-standing E2E job wired for changed live test test/e2e/live/onboard-negative-paths.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-negative-paths

Optional E2E targets

  • None.

Relevant changed files

  • src/lib/onboard/inference-providers/hermes.ts
  • src/lib/onboard/inference-providers/types.ts
  • src/lib/policy/index.ts
  • test/e2e/live/network-policy.test.ts
  • test/e2e/live/onboard-negative-paths.test.ts

@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

🧹 Nitpick comments (1)
src/lib/onboard/inference-providers/hermes.ts (1)

8-8: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider restricting endpointUrl to http/https schemes.

isPrivateHostname only inspects parsedEndpoint.hostname. A scheme like file://, unix://, or a custom scheme parses fine with new URL() but yields an empty/irrelevant hostname, sidestepping the private-hostname check entirely. Given this value is later forwarded as baseUrl/OPENAI_BASE_URL (Line 105, Line 110), an explicit protocol allowlist closes an easy bypass and is a natural complement to the hostname check being added here.

🛡️ Proposed protocol check
     try {
       parsedEndpoint = new URL(endpointUrl);
     } catch {
       throw new Error(`Invalid inference endpoint URL: ${endpointUrl}`);
     }
+    if (parsedEndpoint.protocol !== "http:" && parsedEndpoint.protocol !== "https:") {
+      throw new Error(`Inference endpoint URL must use http or https: ${endpointUrl}`);
+    }
     if (isPrivateHostname(parsedEndpoint.hostname)) {

Also applies to: 32-44

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard/inference-providers/hermes.ts` at line 8, Add an explicit
protocol allowlist for endpointUrl in the Hermes inference provider flow, since
isPrivateHostname only checks parsedEndpoint.hostname and can be bypassed by
non-http schemes. Update the validation around the endpoint parsing logic in
hermes.ts, using the existing Hermes setup paths that later pass endpointUrl
into baseUrl/OPENAI_BASE_URL, so only http and https URLs are accepted before
the hostname/private-network check runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/onboard/inference-providers/hermes.test.ts`:
- Around line 9-21: The new `isPrivateHostname` mock in `hermes.test.ts` trips
the guardrail by adding two `if` statements for early returns. Refactor the
helper into a single boolean return expression that combines the private host
set, the `.internal`/`.local` suffix checks, and the `privatePatterns.some(...)`
match, preserving the same behavior while removing the explicit `if` branches.

---

Nitpick comments:
In `@src/lib/onboard/inference-providers/hermes.ts`:
- Line 8: Add an explicit protocol allowlist for endpointUrl in the Hermes
inference provider flow, since isPrivateHostname only checks
parsedEndpoint.hostname and can be bypassed by non-http schemes. Update the
validation around the endpoint parsing logic in hermes.ts, using the existing
Hermes setup paths that later pass endpointUrl into baseUrl/OPENAI_BASE_URL, so
only http and https URLs are accepted before the hostname/private-network check
runs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a348c8e4-95a5-42b1-883c-663a2a6dce6a

📥 Commits

Reviewing files that changed from the base of the PR and between e4b9111 and fa8448d.

📒 Files selected for processing (4)
  • src/lib/onboard/inference-providers/hermes.test.ts
  • src/lib/onboard/inference-providers/hermes.ts
  • src/lib/policy/index.ts
  • src/lib/policy/preset-allowed-ips.test.ts

Comment thread src/lib/onboard/inference-providers/hermes.test.ts Outdated
prekshivyas and others added 3 commits June 30, 2026 20:04
Drop the vi.mock factory — it contained if statements which the
codebase-growth guardrail forbids in test files. The real implementation
reads from nemoclaw-blueprint/private-networks.yaml and works correctly
in test context.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace 'in' operator with Object.hasOwn to avoid matching inherited
prototype properties (prototype pollution guard, per PRA-2).

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@prekshivyas

Copy link
Copy Markdown
Collaborator Author

Addressing Nemotron advisor items:

PRA-2 — Fixed. Replaced "allowed_ips" in ep with Object.hasOwn(ep, "allowed_ips") in the latest commit.

PRA-6 — Explained. #6085 was the original PR opened on the wrong base branch (carried unrelated #6047 commits in the diff). #6087 is the clean replacement rebased onto main. #6085 is closed.

PRA-5 / PRA-9 — Justified. isPrivateHostname() catches hostname-level private addresses (loopback, RFC-1918 literals, .internal, localhost, link-local). DNS-rebinding at onboarding time is a lower risk than at inference time: the URL is persisted immediately and used as a static config value — it isn't re-resolved on every request. Full DNS pinning (validateUrlValueWithDnsResult) would require making this code path async and threading a DNS lookup function through the dep injection layer, which is a larger refactor. The plugin-side validateEndpointUrl() in runner.ts already does DNS pinning at inference time as a second layer. Filing a follow-up issue to add async DNS validation at onboarding time.

PRA-1 — Justified. isPrivateHostname() is the correct source-of-truth for this check — it reads from nemoclaw-blueprint/private-networks.yaml (the canonical blocklist), is parity-tested against the plugin copy via test/package-contract/ssrf-parity.test.ts, and is the same function used by config set URL validation in src/lib/sandbox/config.ts:511. No localized patch.

PRA-3 / PRA-4 — Justified. The public-endpoint and null-endpointUrl tests verify that valid input doesn't throw and that downstream (runOpenshell) is reached — confirming the guard doesn't block legitimate use. The SSRF check passing is proven by the rejection tests (PRA-8 concern); a separate assertion that isPrivateHostname was called would just be testing the mock, not the behavior.

PRA-7 — Justified. Prototype pollution against isPolicyObject-validated input is not a realistic attack path here: the YAML parser returns plain objects with null prototype chain, and isPolicyObject requires typeof === "object" && !Array.isArray. Adding a prototype-pollution test would test the YAML parser's behavior, not our guard.

PRA-8 — Justified. The 5 rejection tests cover the representative SSRF classes (loopback, link-local/metadata, RFC-1918, reserved hostname, .internal TLD). The full private-networks.yaml blocklist is exercised by nemoclaw/src/blueprint/private-networks.test.ts and the parity test; duplicating that coverage here would be redundant.

prekshivyas and others added 2 commits July 1, 2026 10:27
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tent bypass

- hermes.ts: reject non-http/https schemes and URLs with embedded
  credentials; redact raw URL from parse-error messages
- policy/index.ts: extract networkPoliciesHasAllowedIps helper and
  enforce it in applyPresetContent() when options.custom is set, closing
  the snapshot-replay bypass path (PRA-3 partial, PRA-4)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

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

Caution

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

⚠️ Outside diff range comments (1)
src/lib/onboard/inference-providers/hermes.test.ts (1)

127-142: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Test title claims no raw-value leak but assertion doesn't verify it.

The test name says "without leaking the raw value" but only asserts .rejects.toThrow(/valid URL/). This regex would still pass even if the implementation's error message included the raw "not-a-url" string (e.g., "'not-a-url' is not a valid URL."), so the test doesn't actually exercise the no-leak claim it asserts in its title.

As per path instructions for **/*.test.{ts,js,mts,mjs,cts,cjs}: "Flag copied production algorithms, broad mocks that bypass the behavior under test, and conditionals that make a test pass without exercising its claim."

✅ Suggested fix to actually assert no leak
-  it("throws on malformed URL without leaking the raw value", async () => {
-    await expect(
-      setupHermesProviderInference(
-        {
-          sandboxName: "alpha",
-          model: "m",
-          provider: "p",
-          endpointUrl: "not-a-url",
-          credentialEnv: null,
-          hermesAuthMethod: null,
-          hermesToolGateways: [],
-        },
-        makeDeps() as never,
-      ),
-    ).rejects.toThrow(/valid URL/);
-  });
+  it("throws on malformed URL without leaking the raw value", async () => {
+    let caught: unknown;
+    try {
+      await setupHermesProviderInference(
+        {
+          sandboxName: "alpha",
+          model: "m",
+          provider: "p",
+          endpointUrl: "not-a-url",
+          credentialEnv: null,
+          hermesAuthMethod: null,
+          hermesToolGateways: [],
+        },
+        makeDeps() as never,
+      );
+    } catch (err) {
+      caught = err;
+    }
+    expect(caught).toBeInstanceOf(Error);
+    expect((caught as Error).message).toMatch(/valid URL/);
+    expect((caught as Error).message).not.toContain("not-a-url");
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard/inference-providers/hermes.test.ts` around lines 127 - 142,
The hermes test title promises the malformed endpoint URL is not leaked, but the
current assertion in setupHermesProviderInference only matches “valid URL” and
would still pass if the raw value appears in the error. Update the test in
hermes.test.ts so the rejection assertion also verifies the message does not
contain the input endpointUrl (for example by checking the thrown error text via
the setupHermesProviderInference call and asserting it excludes the raw
“not-a-url” value), while still keeping the existing valid-URL expectation.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/lib/onboard/inference-providers/hermes.test.ts`:
- Around line 127-142: The hermes test title promises the malformed endpoint URL
is not leaked, but the current assertion in setupHermesProviderInference only
matches “valid URL” and would still pass if the raw value appears in the error.
Update the test in hermes.test.ts so the rejection assertion also verifies the
message does not contain the input endpointUrl (for example by checking the
thrown error text via the setupHermesProviderInference call and asserting it
excludes the raw “not-a-url” value), while still keeping the existing valid-URL
expectation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3a438659-c549-4b0d-9a8f-0d2cf091d141

📥 Commits

Reviewing files that changed from the base of the PR and between 5d9cfaa and bc34519.

📒 Files selected for processing (4)
  • src/lib/onboard/inference-providers/hermes.test.ts
  • src/lib/onboard/inference-providers/hermes.ts
  • src/lib/policy/index.ts
  • src/lib/policy/preset-allowed-ips.test.ts

… allowed_ips bypass

Address the required PR-advisor findings on the SSRF hardening:

- PRA-4/PRA-8 (DNS rebinding): the Hermes endpoint check used the string-only
  isPrivateHostname, so a public hostname resolving to a private IP bypassed it.
  Route the URL through rewriteConfigUrlsWithDnsPinning (the same DNS-resolving
  validator the compatible-endpoint path uses): it rejects private-resolved
  addresses, pins the IP for http (closing the config-time->runtime rebinding
  window), and preserves the hostname for https (keeping TLS cert validation).
  The scheme / embedded-credentials / valid-URL pre-checks are retained.
  lookup is injectable via HermesDeps for deterministic tests.
- PRA-13: document why a null endpointUrl is intentionally accepted (managed/
  OAuth path supplies the route later).
- PRA-5/PRA-11: networkPoliciesHasAllowedIps now also rejects allowed_ips
  declared at the network-policy object level (not only inside endpoints), and
  uses `in` rather than Object.hasOwn so an inherited/prototype-chain allowed_ips
  cannot bypass the guard.

Tests: DNS-rebinding rejection (public host -> private IP), public-host accept,
resolves.toEqual({ ok: true }) on the public/null paths (PRA-9/PRA-10), a
parametrized sweep over private/reserved literals+names (PRA-7), and
object-level + prototype-chain allowed_ips rejection (PRA-11). The five original
literal/reserved rejection tests are unchanged (they short-circuit before DNS).

SKIP=test-cli: the full cli+integration hook trips on pre-existing macOS bash
3.2 shell-harness failures unrelated to this TS-only change; CI runs bash 5.x
green. hermes + policy suites, CLI typecheck, budget, and checks all pass.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Target Results — ❌ Some jobs failed

Run: 28544889595
Workflow ref: fix/ssrf-validation-gaps-6072-6073-v2
Requested targets: (default — all supported)
Requested jobs: onboard-negative-paths,hermes-e2e,network-policy
Summary: 1 passed, 1 failed, 1 cancelled, 0 skipped

Job Result
hermes-e2e ✅ success
network-policy ⚠️ cancelled
onboard-negative-paths ❌ failure

Failed jobs: onboard-negative-paths. Check run artifacts for logs.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Target Results — ❌ Some jobs failed

Run: 28546136750
Workflow ref: fix/ssrf-validation-gaps-6072-6073-v2
Requested targets: (default — all supported)
Requested jobs: onboard-negative-paths,hermes-e2e,network-policy
Summary: 1 passed, 2 failed, 0 cancelled, 0 skipped

Job Result
hermes-e2e ✅ success
network-policy ❌ failure
onboard-negative-paths ❌ failure

Failed jobs: network-policy, onboard-negative-paths. Check run artifacts for logs.

@prekshivyas

Copy link
Copy Markdown
Collaborator Author

Re PRA-3 (policy/index.ts monolith growth) — deferring with rationale, not fixing in this PR:

  • codebase-growth-guardrails CI passes on this PR. The change to index.ts is minimal (the object-level allowed_ips check + one export), so it does not trip the growth gate — PRA-3 is an advisory maintainability concern here, not a hard gate.
  • src/lib/policy/index.ts is concurrently being restructured by open refactor(policy): move messaging policies into channels #6129 (move messaging policies into channels). Extracting the allowed_ips guard into a separate module now would create a merge conflict with that refactor — exactly the "3 overlapping PRs" risk the advisor flags.
  • The allowed_ips detection is a natural candidate to relocate as part of refactor(policy): move messaging policies into channels #6129's restructuring. Deferring the extraction there rather than pre-emptively splitting the monolith under overlapping PRs.

The two required security items are addressed in this PR: PRA-4/PRA-8 (DNS-rebinding — now routed through rewriteConfigUrlsWithDnsPinning, pinning http / preserving https) and PRA-5/PRA-11 (allowed_ips bypass at the policy-object level + prototype-chain).

@prekshivyas

Copy link
Copy Markdown
Collaborator Author

CodeRabbit finding at hermes.test.ts:21 (makeDeps if statements) is stale — makeDeps has zero if statements in the current branch code; the guardrail would not fire. No action needed.

… fix E2E coverage

The two E2E failures on this PR were:

- network-policy: the allowed_ips guard rejected the legitimate host-gateway
  preset (web_fetch to host.openshell.internal pins allowed_ips), because the
  guard couldn't tell a malicious user preset from the trusted sandbox->host
  bridge. Add a trust-boundary exemption: an endpoint may carry allowed_ips
  only when its host is host.openshell.internal (mirroring the
  ALLOWED_PRIVATE_CUSTOM_ENDPOINT_HOSTS exemption in inference-set.ts); any
  other host with allowed_ips is still rejected, and object-level allowed_ips
  is never exempt.

- onboard-negative-paths: the rejection test used a fake sandbox name, so the
  CLI failed "sandbox does not exist" before ever reaching preset validation
  (the guard is dispatched after sandbox resolution). Move the end-to-end
  rejection to a real sandbox in network-policy.test.ts (tc-net-10: apply a
  non-bridge allowed_ips preset to the live sandbox, expect rejection), and
  remove the unreachable fake-sandbox case. The guard logic itself
  (reject non-bridge, accept the bridge, object-level, prototype-chain) is
  unit-covered in preset-allowed-ips.test.ts.

SKIP=test-cli: the full cli+integration hook trips on pre-existing macOS bash
3.2 shell-harness failures unrelated to this change; CI runs bash 5.x green.
policy unit suite, CLI typecheck, budget, and checks all pass.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Comment thread test/e2e/live/onboard-negative-paths.test.ts Fixed
Comment thread test/e2e/live/onboard-negative-paths.test.ts Fixed
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Target Results — ✅ All requested jobs passed

Run: 28549501754
Workflow ref: fix/ssrf-validation-gaps-6072-6073-v2
Requested targets: (default — all supported)
Requested jobs: onboard-negative-paths,hermes-e2e,network-policy
Summary: 3 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
hermes-e2e ✅ success
network-policy ✅ success
onboard-negative-paths ✅ success

…ort, function or class'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@cv
cv merged commit 03d69f6 into main Jul 1, 2026
42 checks passed
@cv
cv deleted the fix/ssrf-validation-gaps-6072-6073-v2 branch July 1, 2026 22:44
ericksoa pushed a commit that referenced this pull request Jul 2, 2026
## Summary
- Add the `v0.0.72` release-note section with links to the deeper docs
pages for installer recovery, command diagnostics, inference, policy,
and sandbox repair changes.
- Document the custom preset `allowed_ips` guard for user-authored
policy files.

## Related Issue
None.

## Source summary
- #6132 -> `docs/about/release-notes.mdx`: Summarizes installer and
upgrade recovery before generic onboarding, with links to quickstart and
lifecycle docs.
- #6087 -> `docs/network-policy/customize-network-policy.mdx`: Documents
that user-authored custom presets reject `allowed_ips` for ordinary
endpoints; also summarized in release notes.
- #5975 -> `docs/about/release-notes.mdx`: Summarizes safer curl-based
inference probes that keep API keys out of process arguments.
- #6044 -> `docs/about/release-notes.mdx`: Summarizes compact `channels
status` configuration reporting.
- #6096 -> `docs/about/release-notes.mdx`: Summarizes OpenClaw EC2
metadata discovery disablement and links to security guidance.
- #5980 and #5991 -> `docs/about/release-notes.mdx`: Summarizes `exec`
multiline argument rejection and recovery guidance.
- #6023 -> `docs/about/release-notes.mdx`: Summarizes
registered-provider diagnostics for `inference set` failures.
- #6074 -> `docs/about/release-notes.mdx`: Summarizes the refreshed
NVIDIA Endpoints featured-model selection behavior.
- #5969 -> `docs/about/release-notes.mdx`: Summarizes `credentials add`
provider credential registration.
- #6060 -> `docs/about/release-notes.mdx`: Summarizes mutable OpenClaw
config permission restoration after `exec`.
- #6134 -> `docs/about/release-notes.mdx`: Summarizes restored Tavily
access for managed Python workflows.
- #6089 -> `docs/about/release-notes.mdx`: Summarizes Hermes runtime
version-scheme comparison during upgrade checks.
- #6131 -> `docs/about/release-notes.mdx`: Summarizes OpenClaw gateway
watchdog recovery behavior.
- #5976 and #5990 -> `docs/about/release-notes.mdx`: Summarizes prompt
stdin EOF cancellation behavior during onboarding.
- #5540 -> `docs/about/release-notes.mdx`: Summarizes clarified
host-level and per-sandbox status command scope.
- #5978 and #6018 -> `docs/about/release-notes.mdx`: Summarizes
policy-denial log breadcrumbs in connect shells.

## Testing
- `npm run docs:sync-agent-variants`
- `npm run docs`
- Commit hooks passed during `git commit`, including commitlint and
gitleaks.
- Pre-push hook passed during `git push`, including TypeScript CLI and
package/tag version sync.

## Checklist
- [x] Documentation updated.
- [x] `npm run docs` completed with 0 errors and 1 existing Fern
warning.
- [x] No source code or generated build artifacts committed.

Signed-off-by: Miyoung Choi <miyoungc@nvidia.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added release notes for v0.0.72 covering improved installer recovery,
clearer CLI diagnostics, safer inference setup and provider switching,
better credential handling, stronger policy boundaries, and more robust
runtime repair behavior.
* Updated network policy guidance to clarify when `allowed_ips` can be
used, including a specific exception for the sandbox-to-host bridge
endpoint.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
… user presets (NVIDIA#6087)

## Summary

Closes two SSRF gaps found during a security review of NemoClaw's policy
and onboarding flows. Neither gap was exploitable through the sandboxed
agent — both required user-level access to the CLI.

## Related Issue

Fixes NVIDIA#6072
Fixes NVIDIA#6073

## Changes

- **`src/lib/onboard/inference-providers/hermes.ts`**: call
`isPrivateHostname()` on the user-supplied `endpointUrl` before it is
persisted and passed to OpenShell as `OPENAI_BASE_URL`. Previously the
URL bypassed all SSRF checks until plugin-side `validateEndpointUrl()`
fired at inference time — after credentials could already have been
dispatched to an internal host.
- **`src/lib/policy/index.ts`**: reject user-supplied preset files
(`--from-file` / `--from-dir`) that declare `allowed_ips` in any
`network_policies` endpoint. The merge was previously a blind structural
pass-through that let callers expand the private-IP allowlist that
OpenShell enforces.
- **`src/lib/onboard/inference-providers/hermes.test.ts`**: 8 new unit
tests covering loopback, link-local (169.254.x.x), RFC-1918, `.internal`
TLD, malformed URLs, public endpoint acceptance, and null pass-through.
- **`src/lib/policy/preset-allowed-ips.test.ts`**: 4 new unit tests
covering single-policy rejection, multi-policy rejection, clean preset
acceptance, and endpoint-without-allowed_ips acceptance.
- **`test/e2e/live/onboard-negative-paths.test.ts`**: E2E test asserting
`nemoclaw policy-add --from-file` exits non-zero and prints an
`allowed_ips`/not-permitted error for a user-supplied preset that
contains `allowed_ips`. Exits before any sandbox interaction so no live
infra required beyond the compiled CLI.

## Type of Change

- [x] Code change (feature, bug fix, or refactor)

## Quality Gates

- [x] Tests added or updated for changed behavior
- [x] Docs not applicable — justification: input validation only, no
user-facing behavior change beyond error messages
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [x] Sensitive-path review completed or maintainer-approved waiver
recorded — self-review; security team tagged via NVIDIA#6072 and NVIDIA#6073
- [x] Non-success, skipped, or missing CI check accepted by maintainer —
`tsc-cli` pre-push hook skipped locally due to missing optional dev deps
(`@aws-sdk/client-bedrock-runtime`, `@earendil-works/pi-coding-agent`);
pre-existing on `main`

## E2E Coverage

Required runs (per E2E advisor): `hermes-e2e`, `network-policy` —
dispatch against this branch.

New E2E in this PR: `policy-add --from-file allowed_ips rejection` —
lightweight, no sandbox required.

Hermes onboarding SSRF rejection E2E (suggested by advisor): requires
full Hermes sandbox setup (~70 min). Unit tests already cover the
validation logic; follow-up issue to be filed.

## Verification

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Git hooks passed during commit and push, or `npx prek run
--from-ref main --to-ref HEAD` passes
- [x] Targeted tests pass for changed behavior
- [x] No secrets, API keys, or credentials committed

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Tightened validation for network endpoints and preset content to block
unsafe or internal addresses.
* Rejected malformed URLs, unsupported schemes, embedded credentials,
and private/internal hostnames.
* Prevented presets with disallowed IP-based endpoint rules from being
loaded or applied.
* Added end-to-end coverage for failed preset imports and safer handling
of valid public endpoints.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
## Summary
- Add the `v0.0.72` release-note section with links to the deeper docs
pages for installer recovery, command diagnostics, inference, policy,
and sandbox repair changes.
- Document the custom preset `allowed_ips` guard for user-authored
policy files.

## Related Issue
None.

## Source summary
- NVIDIA#6132 -> `docs/about/release-notes.mdx`: Summarizes installer and
upgrade recovery before generic onboarding, with links to quickstart and
lifecycle docs.
- NVIDIA#6087 -> `docs/network-policy/customize-network-policy.mdx`: Documents
that user-authored custom presets reject `allowed_ips` for ordinary
endpoints; also summarized in release notes.
- NVIDIA#5975 -> `docs/about/release-notes.mdx`: Summarizes safer curl-based
inference probes that keep API keys out of process arguments.
- NVIDIA#6044 -> `docs/about/release-notes.mdx`: Summarizes compact `channels
status` configuration reporting.
- NVIDIA#6096 -> `docs/about/release-notes.mdx`: Summarizes OpenClaw EC2
metadata discovery disablement and links to security guidance.
- NVIDIA#5980 and NVIDIA#5991 -> `docs/about/release-notes.mdx`: Summarizes `exec`
multiline argument rejection and recovery guidance.
- NVIDIA#6023 -> `docs/about/release-notes.mdx`: Summarizes
registered-provider diagnostics for `inference set` failures.
- NVIDIA#6074 -> `docs/about/release-notes.mdx`: Summarizes the refreshed
NVIDIA Endpoints featured-model selection behavior.
- NVIDIA#5969 -> `docs/about/release-notes.mdx`: Summarizes `credentials add`
provider credential registration.
- NVIDIA#6060 -> `docs/about/release-notes.mdx`: Summarizes mutable OpenClaw
config permission restoration after `exec`.
- NVIDIA#6134 -> `docs/about/release-notes.mdx`: Summarizes restored Tavily
access for managed Python workflows.
- NVIDIA#6089 -> `docs/about/release-notes.mdx`: Summarizes Hermes runtime
version-scheme comparison during upgrade checks.
- NVIDIA#6131 -> `docs/about/release-notes.mdx`: Summarizes OpenClaw gateway
watchdog recovery behavior.
- NVIDIA#5976 and NVIDIA#5990 -> `docs/about/release-notes.mdx`: Summarizes prompt
stdin EOF cancellation behavior during onboarding.
- NVIDIA#5540 -> `docs/about/release-notes.mdx`: Summarizes clarified
host-level and per-sandbox status command scope.
- NVIDIA#5978 and NVIDIA#6018 -> `docs/about/release-notes.mdx`: Summarizes
policy-denial log breadcrumbs in connect shells.

## Testing
- `npm run docs:sync-agent-variants`
- `npm run docs`
- Commit hooks passed during `git commit`, including commitlint and
gitleaks.
- Pre-push hook passed during `git push`, including TypeScript CLI and
package/tag version sync.

## Checklist
- [x] Documentation updated.
- [x] `npm run docs` completed with 0 errors and 1 existing Fern
warning.
- [x] No source code or generated build artifacts committed.

Signed-off-by: Miyoung Choi <miyoungc@nvidia.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added release notes for v0.0.72 covering improved installer recovery,
clearer CLI diagnostics, safer inference setup and provider switching,
better credential handling, stronger policy boundaries, and more robust
runtime repair behavior.
* Updated network policy guidance to clarify when `allowed_ips` can be
used, including a specific exception for the sandbox-to-host bridge
endpoint.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: security Security controls, permissions, secrets, or hardening

Projects

None yet

5 participants