Skip to content

Commit 90e3280

Browse files
dguidoclaude
andauthored
Mount .devcontainer/ read-only to prevent container escape on rebuild (#13)
A process inside the container could modify .devcontainer/devcontainer.json to inject malicious mounts or initializeCommand entries that execute on the host during the next rebuild. Bind-mounting .devcontainer/ as read-only blocks this privilege escalation vector. Uses startswith() for the jq filter to be precise and consistent with other mount filters, and documents the SYS_ADMIN guard requirement. Based on PR #12 with review feedback from @dguido addressed. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 96e3ca2 commit 90e3280

2 files changed

Lines changed: 11 additions & 2 deletions

File tree

devcontainer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
"source=claude-code-bashhistory-${devcontainerId},target=/commandhistory,type=volume",
4747
"source=claude-code-config-${devcontainerId},target=/home/vscode/.claude,type=volume",
4848
"source=claude-code-gh-${devcontainerId},target=/home/vscode/.config/gh,type=volume",
49-
"source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,readonly"
49+
"source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,readonly",
50+
"source=${localWorkspaceFolder}/.devcontainer,target=/workspace/.devcontainer,type=bind,readonly"
5051
],
5152
"containerEnv": {
5253
"NODE_OPTIONS": "--max-old-space-size=4096",

install.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ get_workspace_folder() {
8282

8383
# Extract custom mounts from devcontainer.json to a temp file
8484
# Returns the temp file path, or empty string if no custom mounts
85+
#
86+
# Security: .devcontainer/ is mounted read-only inside the container to prevent
87+
# a compromised process from injecting malicious mounts or commands into
88+
# devcontainer.json that execute on the host during rebuild. This protection
89+
# requires that SYS_ADMIN is never added to runArgs (it would allow remounting
90+
# read-write).
8591
extract_mounts_to_file() {
8692
local devcontainer_json="$1"
8793
local temp_file
@@ -98,7 +104,9 @@ extract_mounts_to_file() {
98104
(startswith("source=claude-code-bashhistory-") | not) and
99105
(startswith("source=claude-code-config-") | not) and
100106
(startswith("source=claude-code-gh-") | not) and
101-
(startswith("source=${localEnv:HOME}/.gitconfig,") | not)
107+
(startswith("source=${localEnv:HOME}/.gitconfig,") | not) and
108+
# Security: read-only .devcontainer mount prevents container escape on rebuild
109+
(startswith("source=${localWorkspaceFolder}/.devcontainer,") | not)
102110
)
103111
) | if length > 0 then . else empty end
104112
' "$devcontainer_json" 2>/dev/null) || true

0 commit comments

Comments
 (0)