Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

userEnvProbe (and --secrets-file) put container env values, incl. secrets, on the host `docker exec` argv

Đang mở
#1,317 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
68/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
docker, typescript
Lĩnh vực
cli, devops, security

Hướng nghiên cứu

Start in src/spec-shutdown/dockerUtils.ts at toDockerExecArgs, then trace remoteEnv from probeUserEnv and the secrets merge in src/spec-common/injectHeadless.ts. Run the supplied Docker reproduction for both userEnvProbe and --secrets-file. Done means lifecycle hooks and devcontainer exec still receive their environment while secret values no longer appear in host docker exec argv.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Summary

When userEnvProbe is enabled (the default, loginInteractiveShell), the CLI reads the container user's whole environment (cat /proc/self/environ) and passes every variable back to docker exec as a -e NAME=VALUE argument. This happens on every lifecycle hook (onCreateCommand, postCreateCommand, postStartCommand, …) and on every devcontainer exec.

So any secret that is already in the container's environment ends up in plaintext on the host process command line, where any local user can read it with ps. That includes secrets injected with runArgs: ["--env-file", …], containerEnv or an image ENV. Those variables are already part of the container's Config.Env, which docker exec inherits, so re-sending them on the command line gains nothing.

The --secrets-file feature has the same problem, even with "userEnvProbe": "none". Lifecycle commands merge the secrets into the exec env (const env = { ...(await remoteEnv), ...(await secrets) }), so each secret appears as -e NAME=VALUE on the host argv while the hook runs.

Where

On main (3e363f63a712d30a741174f6d1a7e75f47fe3fc1):

  • src/spec-shutdown/dockerUtils.ts toDockerExecArgs (~L400-415): Object.keys(env).forEach(key => execArgs.push('-e', ${key}=${env[key]}))
  • src/spec-common/injectHeadless.ts probeUserEnv (~L777-789, cat /proc/self/environ) feeds remoteEnv. runLifecycleCommand (~L518) merges remoteEnv and secrets into that env.
  • In the published 0.89.0 bundle (dist/spec-node/devContainersSpecCLI.js) the same logic is the minified function KN: r&&Object.keys(r).forEach(a=>g.push("-e",${a}=${r[a]})).
Repro (dummy values only)

@devcontainers/cli 0.89.0, Docker Desktop on macOS, image alpine:3.

mkdir probe && cd probe
umask 077
printf 'ARGV_PROBE_VAR=DUMMY_NOT_SECRET\n' > dummy.env
printf '{"image":"alpine:3","overrideCommand":true,"runArgs":["--env-file","%s/dummy.env"]}\n' "$PWD" > .devcontainer.json
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . sleep 6 &
sleep 3; ps -axww -o command | grep '^docker exec'

Observed (other values elided):

docker exec -i -u root -e HOSTNAME=… -e SHLVL=… -e HOME=… -e PAGER=… -e LC_COLLATE=… -e PATH=… -e LANG=… -e CHARSET=… -e ARGV_PROBE_VAR=DUMMY_NOT_SECRET -w /workspaces/probe <id> sleep 6
Arm docker exec argv contains ARGV_PROBE_VAR=DUMMY_NOT_SECRET Var visible inside the container
default userEnvProbe yes (1 process) yes
"userEnvProbe": "none" no (0) yes (inherited from Config.Env)

--secrets-file arm: config {"image":"alpine:3","overrideCommand":true,"userEnvProbe":"none","postStartCommand":"sleep 8"} with --secrets-file secrets.json containing {"SECRETSFILE_PROBE_VAR":"DUMMY_NOT_SECRET_2"}. While the hook ran, the host showed docker exec -i -u root -e SECRETSFILE_PROBE_VAR=DUMMY_NOT_SECRET_2 -w /workspaces/probe-secretsfile <id> /bin/sh -c sleep 8.

We found this in a real setup where Doppler secrets were injected with --env-file. Every secret showed up in the host process table during devcontainer up and devcontainer exec.

Suggested fix

Any of these, in order of preference:

  1. Pass variables by name, not by value. Use docker exec -e NAME (no =), so docker reads the value from the CLI process's own environment, and spawn the docker child with { ...process.env, ...env }. Values never appear on argv. This also covers --secrets-file and remoteEnv.
  2. Or use docker exec --env-file <tmpfile>, written mode 0600 and removed after the exec starts.
  3. At minimum, don't re-send probed variables whose value already equals the container's Config.Env value. docker exec inherits those, so dropping them changes nothing. Only the delta the login shell adds would remain (e.g. PATH), which is rarely sensitive.

Workaround for users: set "userEnvProbe": "none" and run commands that need the login environment through bash -lc. This does not help with --secrets-file.

Ngôn ngữ chính
TypeScript
Star
3k
Fork
463
Merge trung bình
13 giờ 28 phút
Pull request đã merge (30 ngày)
2

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của devcontainers/cli

Tất cả issue của devcontainers/cli

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.