Skip to content

fix(wasm-serve): enforce sandbox file containment, outbound SSRF guard, and 10MiB HTTP body limit - #760

Closed
thinhnx128 wants to merge 2 commits into
arakoodev:mainfrom
thinhnx128:security/wasm-host-sandbox-ssrf-and-body-limit
Closed

thinhnx128 wants to merge 2 commits into
arakoodev:mainfrom
thinhnx128:security/wasm-host-sandbox-ssrf-and-body-limit

Conversation

@thinhnx128

Copy link
Copy Markdown

Summary of Defensive Security Hardening for EdgeChains WASM Server (JS/wasm/crates/serve)

This PR hardens the WebAssembly host runtime in JS/wasm/crates/serve/src/binding.rs and JS/wasm/crates/serve/src/lib.rs:

1. Enforce Sandbox Path Containment in Host::read_file (CWE-22)

  • File: JS/wasm/crates/serve/src/binding.rs
  • Issue: Host::read_file previously passed guest-supplied paths directly to fs::read_to_string(&path) without canonical path validation.
  • Fix: Added validate_sandbox_file_path() to canonicalize both the configured sandbox root (EDGECHAINS_SANDBOX_DIR or current working directory) and the requested path, rejecting any path traversal outside the sandbox directory.

2. Block Internal Loopback, RFC1918 Private, and Cloud Metadata IPs in Host::send_request (CWE-918)

  • File: JS/wasm/crates/serve/src/binding.rs
  • Issue: Host::send_request allowed WASM guests to issue outbound HTTP requests to arbitrary internal addresses, including 127.0.0.1 and cloud metadata endpoints (169.254.169.254).
  • Fix: Added validate_outbound_url() and is_restricted_ip() to restrict schemes to http/https and reject loopback, link-local, RFC1918 private, and internal hostnames unless EDGECHAINS_ALLOW_PRIVATE_NETWORK=1 is explicitly enabled.

3. Enforce 10 MiB Inbound HTTP Request Body Limit & Remove Unchecked .unwrap() (CWE-400)

  • File: JS/wasm/crates/serve/src/lib.rs
  • Issue: WorkerCtx::handle_request previously called hyper::body::to_bytes(body).await.unwrap(), allowing unbounded request bodies to exhaust host memory (OOM) and panicking the worker thread on stream disconnects or malformed headers.
  • Fix: Added MAX_REQUEST_BODY_BYTES (10 MiB), checked Content-Length upfront, streamed body chunks with size enforcement (returning 413 Payload Too Large or 400 Bad Request), and replaced header parsing .unwrap() calls with safe pattern matching.

@thinhnx128

Copy link
Copy Markdown
Author

I have read the Arakoo CLA Document and I hereby sign the CLA

@thinhnx128

Copy link
Copy Markdown
Author

Note on CI: PR Build / js and CLAAssistant passed ✅. The Webassembly PR Build / wasm job failed at Set up job (0s) before checkout because .github/workflows/webassembly-pr-build.yml on the base branch uses on: pull_request_target and references the retired actions/cache@v2 (line 54). Commit f83c39a upgrades .github/workflows/webassembly-pr-build.yml to actions/cache@v4 so the workflow succeeds once merged into the base branch.

@thinhnx128

Copy link
Copy Markdown
Author

Closing this to reduce review load — it wasn't requested by the maintainers. Thanks for your time; happy to reopen if it's useful.

@thinhnx128 thinhnx128 closed this Nov 12, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Nov 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant