Skip to content

landjail: npm/npx fails with EACCES when installing packages at runtime (works with nsjail) #189

@garethw81

Description

@garethw81

Full disclosure, below is result of conversation with Coder blink. Testing was performed by me.

Summary

When using jail_type: landjail, npm/npx operations that occur at runtime inside the boundary jail (e.g., MCP tool installation via Codex) fail with EACCES errors. The same configuration works correctly with jail_type: nsjail.

Environment

  • Codex module: 4.3.0
  • Codex CLI: 0.114.0
  • Node: v24.13.0
  • npm: 11.6.2
  • Kernel: Linux 6.12.73
  • Boundary jail_type: landjail

Root Cause Analysis

The two jail types use fundamentally different approaches to route traffic through the boundary proxy:

nsjail (transparent interception)

  • Creates a separate network namespace with a veth pair
  • Uses iptables PREROUTING REDIRECT to transparently capture all TCP traffic and redirect it to the proxy port
  • Processes inside the jail do not need to be proxy-aware — any direct TCP connection (port 80, 443, etc.) is intercepted automatically
  • HTTP_PROXY/HTTPS_PROXY env vars are not set (not needed)

landjail (env-var-based proxy)

  • Uses Landlock V4 to restrict connect() syscalls — the child process can only connect to the proxy port (default 8080)
  • Sets HTTP_PROXY, HTTPS_PROXY, http_proxy, https_proxy env vars pointing to http://localhost:<proxy_port>
  • Processes must respect these proxy env vars to make network requests
  • Any process that attempts a direct TCP connection to a port other than the proxy port gets EACCES

Problem

When Codex launches MCP servers that use npx to auto-install npm packages (e.g., npx -y @zereight/mcp-gitlab), the npm fetch layer attempts direct HTTPS connections to registry.npmjs.org:443 instead of routing through the proxy. Landlock blocks these connections, resulting in:

http fetch GET https://registry.npmjs.org/@zereight%2fmcp-gitlab attempt 1 failed with EACCES
http fetch GET https://registry.npmjs.org/@zereight%2fmcp-gitlab attempt 2 failed with EACCES
http fetch GET https://registry.npmjs.org/@zereight%2fmcp-gitlab attempt 3 failed with EACCES

error code EACCES
error errno EACCES
error FetchError: request to https://registry.npmjs.org/@zereight%2fmcp-gitlab failed, reason:

The operation was rejected by your operating system.

This suggests that npm/npx is not respecting the HTTP_PROXY/HTTPS_PROXY environment variables when spawned as a subprocess inside the boundary jail. Possible causes:

  1. Codex's MCP server env configuration block may replace the process environment (stripping the proxy vars set by boundary) rather than merging with it
  2. npx may spawn sub-shells or child processes that don't inherit the proxy env vars
  3. npm's minipass-fetch may bypass proxy settings in certain execution paths

What was tested

The following workarounds were attempted and did not resolve the issue:

  • Setting npm config set proxy http://localhost:8080 and npm config set https-proxy http://localhost:8080
  • Explicitly setting HTTP_PROXY and HTTPS_PROXY env vars in the MCP server configuration
  • npm install -g @zereight/mcp-gitlab (failed due to permission issues)

The following did work as a workaround:

  • Pre-installing the package locally (npm install @zereight/mcp-gitlab) outside of the boundary jail before Codex starts, so the package is already on disk when the MCP server is launched

Expected Behavior

landjail should handle npm/npx network requests the same way nsjail does — either by ensuring proxy env vars are reliably propagated to all child processes, or by providing an alternative transparent interception mechanism.

Suggested Improvements

  1. Investigate why npm/npx ignores proxy env vars when spawned inside landjail and whether boundary can enforce proxy settings more reliably (e.g., via npm config files or additional env var propagation)
  2. Document the known limitation that landjail relies on proxy env var compliance, which may not work for all tools
  3. Consider whether landjail could use a supplementary mechanism (e.g., LD_PRELOAD-based connect() interception) to transparently route traffic for proxy-unaware tools

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions