Skip to content

sandboxes: clarify outbound protocol support - #25819

Open
dvdksn wants to merge 2 commits into
docker:mainfrom
dvdksn:docs/sandboxes-network-protocols
Open

sandboxes: clarify outbound protocol support#25819
dvdksn wants to merge 2 commits into
docker:mainfrom
dvdksn:docs/sandboxes-network-protocols

Conversation

@dvdksn

@dvdksn dvdksn commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Description

Clarify that network policy controls outbound TCP traffic, including SSH, while Docker Sandboxes blocks direct external UDP and ICMP independently of network policy.

Also distinguish the governance schema's connect:udp action from the protocols enforced by Docker Sandboxes.

Related issues or tickets

Reviews

  • Technical review
  • Editorial review
  • Product review

@netlify

netlify Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deploy Preview for docsdocker ready!

Name Link
🔨 Latest commit 7352567
🔍 Latest deploy log https://app.netlify.com/projects/docsdocker/deploys/6a7dc8ebb3f7740008f8884d
😎 Deploy Preview https://deploy-preview-25819--docsdocker.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@dvdksn
dvdksn requested review from a team and robmry and a lite review from Copilot August 13, 2026 13:26

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

Assessment: 🟡 NEEDS ATTENTION

The PR accurately clarifies that network policy governs outbound TCP (including SSH) while Docker Sandboxes enforces UDP/ICMP blocks at the network layer independently. The change is consistent across the three updated files. One content accuracy concern: the new text drops explicit statements about private IP, loopback, and link-local address blocking that were present in the previous version.

- Direct network communication between sandboxes
- Raw TCP, UDP, and ICMP connections
- Traffic to private IP ranges and link-local addresses
- Direct external UDP and ICMP connections

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.

[MEDIUM] Removal of private IP/loopback/link-local blocking from security defaults

The old text explicitly stated these were blocked for all sandboxes:

  • "Traffic to private IP ranges, loopback addresses, and link-local addresses is also blocked."
  • List bullets: "Host network and localhost" and "Traffic to private IP ranges and link-local addresses"

The new text replaces these with "Direct external UDP and ICMP connections." The word "external" is ambiguous — readers would reasonably interpret it as not covering loopback (127.x.x.x), private IP ranges (10.x, 172.16.x, 192.168.x), or link-local addresses (169.254.x.x), since those are not conventionally "external." If the sandbox still blocks those destinations, the new text leaves readers with an incomplete threat model.

Consider adding a sentence such as: "Private IP ranges, loopback, and link-local addresses are also blocked and cannot be reached from inside the sandbox."

@dvdksn dvdksn Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for flagging the removed wording. I did not restore it because it is not an unconditional sandbox guarantee: network policy supports CIDR resources, and the Sandboxes policy tests explicitly permit an IP literal such as 10.10.14.20 when a matching CIDR allow rule applies (sandboxd/pkg/proxy/policy_engine_test.go, dialIsAllowed-CIDR-allow-permits-IP-literal-with-no-domain-rule). Commit 7352567 instead aligns the other security pages so they no longer repeat the stale categorical claim.

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.

You're absolutely right, and thank you for the clarification. I misunderstood the interaction between CIDR allow rules and these address ranges.

The old text made an unconditional claim ("blocked for all sandboxes") that doesn't hold when policy explicitly permits a CIDR range covering private IPs, loopback, or link-local addresses. Your decision to remove that stale guarantee rather than restore it was correct — the new text is more accurate.

I appreciate you aligning the other security pages as well. Apologies for the noise on this one.

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

Assessment: 🟢 APPROVE

The changes clearly and accurately clarify outbound protocol support in Docker Sandboxes — distinguishing TCP (governed by network policy), UDP, and ICMP (blocked by the sandbox independently of policy). The distinction between the governance schema's connect:udp action and sandbox-level protocol enforcement is well-explained. No style violations, markdown issues, or content accuracy problems found.

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

Assessment: 🟡 NEEDS ATTENTION

The network.md and concepts.md changes are clear and accurate — correctly distinguishing connect:tcp from connect:udp and explaining that UDP is blocked at the sandbox layer independently of policy. Two content accuracy concerns in security/defaults.md are flagged below.

it (deny-by-default). All non-HTTP protocols (raw TCP, UDP including DNS, and
ICMP) are blocked at the network layer. Traffic to private IP ranges, loopback
addresses, and link-local addresses is also blocked.
All outbound TCP traffic, including HTTP, HTTPS, and SSH, is blocked unless an

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.

[HIGH] Private IP and link-local address blocking omitted from new network defaults

The old text explicitly stated that "Traffic to private IP ranges, loopback addresses, and link-local addresses is also blocked." The new paragraph drops this guarantee entirely — neither the introductory paragraph nor the bullet list below it mentions this restriction. A reader of the updated documentation cannot determine whether these addresses are still blocked, which is a meaningful gap in security documentation. If these restrictions still apply, consider adding a sentence such as: "Traffic to private IP ranges, loopback addresses, and link-local addresses is also blocked at the network layer."

@dvdksn dvdksn Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This restriction does not still apply unconditionally. The current policy engine can authorize private IP literals through CIDR allow rules; see dialIsAllowed-CIDR-allow-permits-IP-literal-with-no-domain-rule in sandboxd/pkg/proxy/policy_engine_test.go. Commit 7352567 updates the remaining security overview text to describe the actual policy-controlled TCP boundary.

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.

Thank you for the clarification — I see now that this was a false positive. The policy engine's support for CIDR allow rules means private IP literals can be authorized, so the old unconditional block no longer applies. I misread the change as an omission when it actually reflects the more flexible, policy-controlled approach described in commit 7352567.

The updated text correctly describes the current TCP boundary without overstating restrictions that no longer hold.

- Host filesystem access outside explicitly mounted workspaces and the shared
skills store
- Host Docker daemon
- Host network and localhost

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.

[MEDIUM] "Host network and localhost" removed from unconditional block list without replacement

The old bullet list included "Host network and localhost" as an explicit, policy-unconfigurable block — meaning agents could not reach the host machine's own network stack or loopback interface. The new text removes this bullet entirely. The remaining bullet "Direct network communication between sandboxes" addresses sandbox-to-sandbox communication, not sandbox-to-host access. Since sandboxes run as VMs, this is a meaningful security boundary. If host network and localhost access is still blocked, consider restoring the bullet or incorporating this guarantee into the introductory paragraph.

@dvdksn dvdksn Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I did not restore this as an unconditional block because current Sandboxes code provides a policy-controlled host route: transparent_forwarding_dialer.go rewrites the host.docker.internal link-local destination through the existing localhost policy/dial path. Commit 7352567 now states that the sandbox does not share the host network or access it directly, while preserving the documented policy-authorized proxy path.

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.

Thank you for the clarification — that makes sense. The distinction between direct host network access (unconditionally blocked) and policy-controlled proxy access to localhost (configurable) is an important architectural detail. The current text correctly states the sandbox doesn't share or directly access the host network, while the policy system can authorize specific localhost connections through the proxy layer.

This is actually more accurate than an unconditional block bullet would have been, since it reflects the real security boundary: no direct network stack sharing, but controlled proxy paths are possible when policy permits.

Copilot AI 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.

Pull request overview

This PR updates the Docker Sandboxes documentation to more clearly distinguish which outbound protocols are controlled by network policy (TCP, including SSH) versus which are blocked at the sandbox network layer (UDP/ICMP), and clarifies how the governance schema’s connect:udp relates to actual enforcement.

Changes:

  • Rewords the “Default security posture” network defaults to emphasize TCP deny-by-default and the special handling of UDP/ICMP and DNS.
  • Updates governance concepts and network access-control docs to describe connect:tcp as the effective enforcement action, while noting the schema accepts connect:udp.
  • Aligns the governance documentation with the intent that direct external UDP is blocked regardless of network policy.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
content/manuals/ai/sandboxes/security/defaults.md Clarifies default outbound protocol behavior and what is blocked by default.
content/manuals/ai/sandboxes/governance/concepts.md Adjusts the conceptual definition of network rules to distinguish schema vs enforcement.
content/manuals/ai/sandboxes/governance/access-controls/network.md Updates rule syntax guidance and clarifies how connect:udp relates to sandbox behavior.
Suppressed comments (1)

content/manuals/ai/sandboxes/security/defaults.md:75

  • The "blocked by default and cannot be changed" list no longer mentions host network/localhost access or private/loopback/link-local blocks, but those constraints are still documented elsewhere (for example, security/_index.md and security/isolation.md). Keeping them in this summary helps clarify what policy can’t override.
- Host Docker daemon
- Direct network communication between sandboxes
- Direct external UDP and ICMP connections

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +14 to +17
All outbound TCP traffic, including HTTP, HTTPS, and SSH, is blocked unless an
explicit rule allows the destination. Direct external UDP and ICMP traffic is
blocked at the network layer. DNS queries use the sandbox's policy-gated
resolver.

@dvdksn dvdksn Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed the resolver wording in 7352567: DNS queries now use the sandbox's internal resolver, which enforces network policy. I also aligned security/isolation.md and security/_index.md. I did not restore the private/loopback/link-local categorical block because the current policy engine supports policy-authorized IP/CIDR destinations.

Comment thread content/manuals/ai/sandboxes/governance/concepts.md Outdated
Comment thread content/manuals/ai/sandboxes/governance/access-controls/network.md Outdated

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

Assessment: 🟡 NEEDS ATTENTION

This PR correctly updates the network defaults and rule-syntax descriptions to reflect TCP-based policy enforcement and the separately enforced UDP/ICMP blocking. A few clarity issues in the new text are worth addressing before merge.

Comment thread content/manuals/ai/sandboxes/security/defaults.md Outdated
Comment thread content/manuals/ai/sandboxes/security/defaults.md
Comment thread content/manuals/ai/sandboxes/governance/access-controls/network.md Outdated
Comment thread content/manuals/ai/sandboxes/governance/concepts.md Outdated

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

Thanks for picking this up so quickly. I checked every claim in this PR against the implementation on main (and the e2e tests), and everything the PR changes is technically accurate:

  • connect:udp having no effect is correct — the runtime only ever issues net:connect:tcp. The one non-test net:connect:udp reference is a display-classification fallback that makes a remote governance UDP rule render as a network rule, which is exactly the trap the reporter fell into.
  • "outbound TCP, including HTTP, HTTPS, and SSH" governed by policy — correct.
  • "Direct external UDP and ICMP" — correct, and the word external is load-bearing: ICMP to localhost is allowed (there's an e2e case for it), so please keep that qualifier.
  • "DNS queries use the sandbox's internal resolver, which enforces network policy" — correct. The resolver genuinely gates resolution, refusing names no allow rule covers, deliberately, to close a DNS-exfiltration path.
  • Dropping "Host network and localhost", "Raw TCP", and "private IP ranges and link-local" from the cannot be changed through policy configuration list — correct on all three. Those are ordinary deny-by-default destinations, allowable by rule; there's no hard block in the datapath.

Approving on that basis. Four things this doesn't close, though:

1. troubleshooting.md isn't in this PR, and it's the page the issue named. It still says:

Hostname-based rules (for example, myhost:22) don't work for non-HTTP connections because the proxy can't resolve the hostname to an IP address in this context. Use the IP address directly.

That's been wrong since v0.29.0 (~9 releases). Hostname rules do work for binary protocols like SSH now: when a connection carries no SNI/Host header, the hostname is recovered from a DNS tracker and domain rules are evaluated against it. This is the page someone actually lands on when SSH fails, and it currently sends them to the workaround instead of the supported path. Suggested replacement:

Non-HTTP TCP connections such as SSH are allowed by adding a policy rule for the destination. Hostname rules work for these connections — the sandbox recovers the hostname from its DNS resolver when the protocol doesn't carry one:

$ sbx policy allow network "myhost:22"

If the destination is reached by IP address without a DNS lookup, the hostname can't be recovered. Use an address-based rule in that case:

$ sbx policy allow network "10.1.2.3:22"

2. governance/access-controls/local.md (lines ~34-38) carries the same stale advice (sbx policy allow network "10.1.2.3:22" presented as the only option) plus "The only way traffic can leave a sandbox is through an HTTP/HTTPS proxy on your host", which this PR's new framing contradicts. Worth folding in.

3. architecture.md line ~55 — "All outbound traffic from the sandbox routes through an HTTP/HTTPS proxy on your host." Same wording class you're fixing elsewhere; should just be "proxy".

4. Host-service access is now an unexplained absence. Removing "cannot reach your host's localhost" is the right call, but it's replaced by "cannot access… your host network directly" with no pointer, and host services are reachable — workflows.md#accessing-host-services-from-a-sandbox documents host.docker.internal plus sbx policy allow network localhost:<port>. A cross-reference from isolation.md or defaults.md would close the loop, since "so can I reach my host or not?" is the natural follow-on question.

Two things I'd deliberately leave alone, having checked them:

  • governance/monitor-and-enforce/monitoring.md line ~147 already reads "TCP can be allowed with a policy rule. UDP and ICMP are always blocked." Already consistent.
  • architecture.md line ~79, "Only HTTP and HTTPS traffic can be forwarded to an upstream proxy. Other TCP traffic can't be redirected to a proxy" — this one is correct and shouldn't be changed by analogy with the rest. Raw non-HTTP transparent TCP is explicitly dialed direct and bypasses the upstream proxy; only traffic detected as HTTP/HTTPS is tunnelled.

One optional precision point: the line being deleted from isolation.md — "domains that policy denies are refused at the resolver" — was itself inaccurate. A name covered by an allow rule still resolves even if a deny rule also covers it; the deny restricts the connection, not resolution. So the vaguer "enforces network policy" is strictly an improvement. Only worth sharpening if you want that nuance documented, along with the dropped (and true) "loopback names such as localhost always resolve regardless of policy".

Reviewed by Claude Code on behalf of @robmry.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants