Skip to content

Harden pooled sandbox isolation - #14

Closed
Wauplin wants to merge 1 commit into
mainfrom
security/harden-pool-isolation
Closed

Harden pooled sandbox isolation#14
Wauplin wants to merge 1 commit into
mainfrom
security/harden-pool-isolation

Conversation

@Wauplin

@Wauplin Wauplin commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Related to https://huggingface.slack.com/archives/C03Q18WK18T/p1788160539575999, let's see what we want to do first

Summary

  • resolve pooled file API paths component-by-component from an open sandbox home descriptor, never following symlinks or performing path-based ownership changes
  • mint a random capability for each pooled sandbox and reserve the host credential for management; the rolling-upgrade compatibility path is explicitly rejected for pooled proxy requests
  • make host and dedicated route surfaces mutually exclusive, require authentication in host mode, and add scoped token recovery for stateless reconnect
  • bump sbx-server to 0.6.0 and document the revised protocol

Rollout

Deploy this server before the companion huggingface_hub change. Existing clients keep working for non-proxy scoped calls, while pooled proxy calls require the upgraded client. Existing pool host jobs must be recycled after publishing the new bucket binary; otherwise they keep running the old process.

Companion client PR: huggingface/huggingface_hub#4782

Validation

  • cargo test
  • cargo build --release
  • cargo clippy --all-targets (three pre-existing style warnings)
  • live root container regression covering final/intermediate symlink read and write attempts, sibling ownership, cross-sandbox credentials, host proxy credentials, and unscoped host routes

@Wauplin

Wauplin commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator Author

Closing in favour of a set of smaller PRs, one per finding, so each can be reviewed and reverted on its own. Nothing here is being dropped — the work is redistributed:

this PR replacement
fd-relative file API (ScopedRoot, openat + O_NOFOLLOW, fd-based ownership) #16, which also fixes the port proxy, whose socket-symlink escape this PR did not cover (proxy.rs was untouched)
route_mode_allowed — host and dedicated route surfaces mutually exclusive next PR, together with fail-closed auth in both modes (this PR only required SBX_TOKEN in host mode)
per-sandbox capability tokens + GET /v1/sandboxes/{id}/token its own PR, with the client change, so the rolling-upgrade window is explicit and retirable

Thanks for the ScopedRoot design — #16 keeps its shape (descriptor walk, O_NOFOLLOW per component, /proc/self/fd for APIs that only take a name) and extends it with an S_ISREG check on reads, unlinkat-based deletion, and a shared fsutil module the proxy reuses.

Also worth recording: #16 verified both escapes end-to-end against main before fixing them, so the regression script is known to fail on the vulnerable build rather than only passing on the fixed one.

@Wauplin Wauplin closed this Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant