Skip to content

fix: support npm global installs in chroot mode#1336

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/support-nodejs-global-tools
Draft

fix: support npm global installs in chroot mode#1336
Copilot wants to merge 3 commits intomainfrom
copilot/support-nodejs-global-tools

Conversation

Copy link
Contributor

Copilot AI commented Mar 17, 2026

npm install -g fails inside the agent container because /usr is mounted read-only (/usr:/host/usr:ro), and npm's default global prefix writes to /usr/local/lib/node_modules/ and /usr/local/bin/.

Changes

  • containers/agent/entrypoint.sh: Set NPM_CONFIG_PREFIX=$HOME/.npm-global and prepend $HOME/.npm-global/bin to PATH in the generated chroot script, redirecting global installs to the writable home volume
  • tests/integration/chroot-package-managers.test.ts: Add test for npm install -g semver + binary execution

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI linked an issue Mar 17, 2026 that may be closed by this pull request
Copilot AI and others added 2 commits March 17, 2026 20:32
Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix issue with installing node.js global tools fix: support npm global installs in chroot mode Mar 17, 2026
Copilot AI requested a review from Mossaka March 17, 2026 20:35
@Mossaka
Copy link
Collaborator

Mossaka commented Mar 17, 2026

@copilot
why is /usr mounted as read-only. What are the security justifications behind it? Can you trace the history of the commits and documentation to figure that out?

@Mossaka
Copy link
Collaborator

Mossaka commented Mar 18, 2026

@copilot why is /usr mounted as read-only. What are the security justifications behind it? Can you trace the history of the commits and documentation to figure that out?

Copy link
Contributor Author

Copilot AI commented Mar 18, 2026

@copilot why is /usr mounted as read-only. What are the security justifications behind it? Can you trace the history of the commits and documentation to figure that out?

/usr is mounted read-only as part of a selective mounting security model introduced in PR #448 (feat(cli): add --enable-chroot for transparent host binary execution) by @Mossaka. The security justifications are:

  1. Principle of least privilege — The agent only needs to read system binaries (/usr/bin/python3, /usr/bin/node, etc.) and libraries (/usr/lib/). It never needs to write to system paths. Mounting read-only prevents a compromised agent from tampering with host system binaries.

  2. Selective mounting over full filesystem — Rather than mounting the entire host filesystem (/:/host:rw), chroot mode selectively mounts only the paths needed: system dirs (/usr, /bin, /sbin, /lib, /lib64, /opt) as read-only, and only $HOME and /tmp as read-write. This was explicitly noted in the original PR feat(cli): add --enable-chroot for transparent host binary execution #448 commit message as a "security improvement."

  3. Credential exfiltration prevention — PR feat: implement selective mounting to prevent credential exfiltration #681 (feat: implement selective mounting to prevent credential exfiltration) further hardened this model. The threat model (documented in docs/selective-mounting.md) addresses prompt injection attacks where a compromised AI agent could modify system binaries or plant backdoors if system paths were writable.

  4. Defense-in-depth layers documented in docs-site/src/content/docs/reference/security-architecture.md:

    • System paths read-only (prevents binary tampering)
    • Capabilities dropped (CAP_NET_ADMIN, CAP_SYS_CHROOT) before user command
    • Docker socket hidden (prevents container escape)
    • Credential files hidden via /dev/null overlays

The read-only constraint on /usr is what causes npm install -g to fail — npm's default global prefix writes to /usr/local/lib/node_modules/ and /usr/local/bin/. This PR works around it by redirecting npm's global prefix to $HOME/.npm-global (writable) while preserving the security boundary.

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.

Support for node.js global tools

2 participants