Docker Sandboxes 到底是「把 AI Agent 放進 Docker」的新版包裝,還是真的多一道安全邊界?2026 年 8 月 10 日,一則 Docker Sandboxes 的 Hacker News 討論拿到 690 points、393 comments;約 16 小時後,一位 Claude 使用者也在問:公司要他在私人電腦跑 Agent,怎樣才能只開放工作資料夾?這兩組數字是 2026 年 8 月 13 日的需求快照,真正的問題其實相同:Agent 能碰到什麼,而不是產品名稱叫什麼。
本文會以截至 2026 年 8 月 13 日的最新穩定版 sbx v0.38.0,帶你建立一個全是假資料、可整台丟棄的安全實驗室,依序驗收檔案、網路、憑證與破壞性命令。先說清楚證據邊界:AlphaLab 這次的 macOS 測試機符合硬體需求,但沒有安裝 sbx,所以下列是依官方文件與穩定版 CLI 整理的可重現驗收;預期結果會明確標示,不會冒充本機已跑通的 microVM 結果。
先說結論:Docker Sandboxes 有 4 扇仍然能打開的門
🐳 記憶把手:隔離強度=microVM 邊界-你主動打開的 workspace、network、credentials、MCP/host bridge 四扇門。
microVM 保護的是主機底座,不會替你保護已掛載的檔案與已授權的外部帳號。
- 比一般 container 多一層:每個 sandbox 有獨立 Linux kernel、filesystem、network 與私人 Docker daemon;Agent 不必共用 host Docker socket。
- 但 workspace 預設可直接改:direct mount 是 host 資料夾的即時讀寫通道,Agent 刪檔,host 也會消失。
--clone防寫不防看:host repo 唯讀,但 repo root 裡的 untracked、gitignored、.env仍可從/run/sandbox/source讀到。- token 不露面,不等於帳號沒風險:proxy-managed secret 可把真值留在 host,但 Agent 仍能使用那份權限對允許的 API 做事。
- local stdio MCP 是關鍵旁門:Docker MCP Gateway 的本機 command 跑在 host,不在 microVM;它能碰什麼取決於該 host process 的權限。

microVM、一般 container、host sandbox 差在哪?
先把三者想成辦公空間。Host sandbox 是在同一棟房子內劃禁區,例如 Codex 在 macOS 使用 Seatbelt;Linux/WSL2 目前優先使用 bubblewrap,並搭配 seccomp 網路過濾,Landlock 則保留為明確啟用的 legacy fallback。它能很精準也很輕量,但仍依賴主機 OS 的政策。一般 container 像有獨立房門的隔間,Linux container 通常共享 host kernel;若再掛入 host Docker socket,裡面的程序就可能指揮 host daemon。Docker Sandboxes 則像另建一間有自己地基的工作室:hypervisor 隔開 kernel,Docker Engine 也留在 microVM 裡。
這不是「哪一種永遠安全」的排名。Host sandbox 的政策、container 的 capability/mount/socket,以及 microVM 開了哪些通道,都會改變結果。Docker 的 官方架構比較能證明 microVM 與私人 daemon 的設計;OpenAI 的 Codex sandboxing 文件則說明 host-native 控制。若想先補齊 Agent 為何需要外層執行架構,可先讀 AI Agent Harness 是什麼。

Docker Sandboxes 最短上手:先固定穩定版
macOS 需要 Sonoma 14 以上與 Apple silicon;Windows 需要 Windows 11 x86_64 與 Hypervisor Platform;Ubuntu 24.04 以上則需要 KVM。Docker Desktop 並非必要條件。macOS 的官方安裝流程是:
brew trust docker/tap
brew install docker/tap/sbx
sbx login
sbx version
本文採用 v0.38.0 官方文件的獨立 sbx CLI;下文不使用預覽期的 docker sandbox 指令。首次登入(以及執行 sbx policy reset 後)會要求選 Open、Balanced 或 Locked Down;Balanced 是 default-deny 加上一批常見開發網域,不是斷網。要跑 Claude Code/Codex,最短指令分別是:
cd /path/to/your-project
sbx run --name work-claude claude
# 另一個專案或 sandbox
sbx run --name work-codex codex
Docker 的 Claude 模板預設以 claude --dangerously-skip-permissions 啟動,Codex 模板預設以 codex --dangerously-bypass-approvals-and-sandbox 啟動。這是刻意把內層提示交給外層 microVM 與 policy,不是雙重保護。兩款工具本身的定位差異,可搭配 Claude Code vs Codex 客觀比較閱讀;安全上則應把 Docker 的 mount、network、credential 與 MCP 設定視為真正控制面。
實驗 1:用誘餌檔驗證檔案邊界
不要拿真密鑰或日常 repo 做實驗。以下只建立兩個無害 canary:一個在 workspace 內,另一個在未掛載的同層資料夾;再放一條指向外部的 symlink。
LAB_ROOT="$(mktemp -d /tmp/sbx-boundary.XXXXXX)" || exit 1
test -n "$LAB_ROOT" && test -d "$LAB_ROOT" || exit 1
LAB_ID="${LAB_ROOT##*.}"
LAB_WS="$LAB_ROOT/workspace"
LAB_OUT="$LAB_ROOT/outside"
LAB_NAME="sbx-boundary-$LAB_ID"
LAB_SBX_CLEAN=0
mkdir -p "$LAB_WS" "$LAB_OUT"
printf 'workspace-original\n' > "$LAB_WS/inside.txt"
printf 'outside-canary\n' > "$LAB_OUT/outside.txt"
ln -s "$LAB_OUT/outside.txt" "$LAB_WS/outside-link"
OUTSIDE_SHA="$(shasum -a 256 "$LAB_OUT/outside.txt" | awk '{print $1}')"
sbx create --name "$LAB_NAME" shell "$LAB_WS"
後續所有實驗 block 都要在同一個 terminal session 依序執行,才能沿用上述變數;唯一名稱也避免誤接到舊 sandbox。
先跑三項驗收。預期:① workspace 內檔可讀;② symlink 不能跨出 mount;③ 在 sandbox 寫入的新檔會立刻出現在 host。
: "${LAB_NAME:?Run the setup block first}"
: "${LAB_WS:?Run the setup block first}"
sbx exec "$LAB_NAME" sh -lc 'cat "$1"' sh "$LAB_WS/inside.txt"
if sbx exec "$LAB_NAME" sh -lc 'cat "$1"' sh "$LAB_WS/outside-link"; then
echo 'FAIL: symlink escaped workspace'
else
echo 'PASS: symlink escape blocked'
fi
sbx exec "$LAB_NAME" sh -lc \
'printf "from-sandbox\n" > "$1"' sh "$LAB_WS/host-visible.txt"
test "$(cat "$LAB_WS/host-visible.txt")" = 'from-sandbox' && echo PASS
接著成對測試破壞性命令。正例只刪 VM 私有的精確假路徑,預期外部 canary hash 不變;誠實反例只刪 direct mount 裡剛建立的假檔,預期 host 同一檔也消失。全程不碰真專案,也不在 VM 使用寬範圍 rm -rf。
: "${LAB_NAME:?Run the setup block first}"
: "${LAB_WS:?Run the setup block first}"
: "${LAB_OUT:?Run the setup block first}"
: "${OUTSIDE_SHA:?Run the setup block first}"
sbx exec "$LAB_NAME" sh -lc \
'sudo mkdir -p /opt/sbx-disposable-probe &&
sudo touch /opt/sbx-disposable-probe/file &&
sudo rm -f /opt/sbx-disposable-probe/file &&
sudo rmdir /opt/sbx-disposable-probe'
test "$(shasum -a 256 "$LAB_OUT/outside.txt" | awk '{print $1}')" \
= "$OUTSIDE_SHA" && echo 'PASS: VM-only deletion stayed inside'
printf 'delete-me\n' > "$LAB_WS/shared-delete-me.txt"
sbx exec "$LAB_NAME" rm -f "$LAB_WS/shared-delete-me.txt"
test ! -e "$LAB_WS/shared-delete-me.txt" && echo 'PASS: direct mount deletion reached host'
因此真正要審的不只 git diff。.git/hooks/、CI workflow、IDE task、package.json scripts、.claude/ 與 .codex/ 都可能改變後續行為;Git hook 通常不會出現在一般 diff。若你會開 auto mode,先搭配 Claude Code Auto Mode 安全實驗室建立獨立驗收器。
--clone 比 direct mount 安全嗎?防寫,不防讀
官方 isolation 文件明確指出:clone mode 會在 microVM 建私人 clone,host repo 只讀掛在 /run/sandbox/source。這能避免 Agent 改壞 host working tree,卻仍讓它讀到整個 Git root,包括 untracked、gitignored 與 .env。所以密鑰應移出 repo root,而不是只加進 .gitignore。
: "${LAB_ROOT:?Run the setup block first}"
: "${LAB_NAME:?Run the setup block first}"
CLONE_REPO="$LAB_ROOT/clone-repo"
CLONE_NAME="$LAB_NAME-clone"
mkdir -p "$CLONE_REPO"
git -C "$CLONE_REPO" init -q
printf '.env\n' > "$CLONE_REPO/.gitignore"
printf 'tracked-original\n' > "$CLONE_REPO/tracked.txt"
printf 'DECOY_NOT_A_SECRET\n' > "$CLONE_REPO/.env"
git -C "$CLONE_REPO" add .gitignore tracked.txt
git -C "$CLONE_REPO" -c user.name='Sandbox Lab' \
-c user.email='sandbox@example.invalid' commit -qm init
CLONE_SHA="$(shasum -a 256 "$CLONE_REPO/tracked.txt" | awk '{print $1}')"
sbx create --clone --name "$CLONE_NAME" shell "$CLONE_REPO"
sbx exec "$CLONE_NAME" sh -lc \
'test -r /run/sandbox/source/.env && echo "PASS: ignored .env is readable"'
if sbx exec "$CLONE_NAME" sh -lc \
'printf x >> /run/sandbox/source/tracked.txt'; then
echo 'FAIL: source mount is writable'
else
echo 'PASS: source mount rejected the write'
fi
test "$(shasum -a 256 "$CLONE_REPO/tracked.txt" | awk '{print $1}')" \
= "$CLONE_SHA" && echo 'PASS: host source hash unchanged'
sbx rm --force "$CLONE_NAME"
較嚴格的日常基線是 --clone 加 --no-share-skills。後者避免支援的 Agent 共用那個預設可讀寫、跨 sandbox 持久存在的 skills store:
sbx run --clone --no-share-skills --name work-claude claude /path/to/project
--clone 與 --no-share-skills 都只在建立時生效。先用 sbx ls 確認名稱未存在;既有 sandbox 要換新名稱或移除後重建,重新執行 sbx run 不會替舊 VM 改邊界。
額外 mount 也要列入清單:~/docs:ro 只防寫,Agent 仍能讀;sbx cp 會主動搬資料,--publish 則把 VM service 接到 host port。它們都是正當功能,也是你親手開的跨界通道。
實驗 2:封鎖網域不能只看設定,要查三層證據
網路驗收要同時看 authorizer 決策、實際 request 與 policy log。以下規則只套用到測試 sandbox,不改全域 policy。先用 sbx policy ls 確認沒有組織治理;組織治理啟用時,local allow/deny 都可能不生效,需請管理員調整 org policy。非組織治理環境的預期是:第一輪 example.com 被拒,移除 deny、明確 allow 後才可通過。
: "${LAB_NAME:?Run the setup block first}"
if sbx exec "$LAB_NAME" sh -lc 'command -v curl >/dev/null'; then
sbx policy deny network --sandbox "$LAB_NAME" example.com
sbx policy check network --sandbox "$LAB_NAME" example.com
if sbx exec "$LAB_NAME" sh -lc 'curl -I --max-time 8 https://example.com'; then
echo 'FAIL: denied request succeeded'
else
echo 'EXPECTED: denied request failed; confirm the reason in policy log'
fi
sbx policy log "$LAB_NAME" --limit 20
sbx policy rm network --sandbox "$LAB_NAME" --resource example.com
sbx policy allow network --sandbox "$LAB_NAME" example.com
sbx policy check network --sandbox "$LAB_NAME" example.com
if sbx exec "$LAB_NAME" sh -lc 'curl -I --max-time 8 https://example.com'; then
echo 'PASS: allowed request succeeded'
else
echo 'CHECK: org policy, DNS, proxy or connectivity still blocked the request'
fi
sbx policy log "$LAB_NAME" --limit 20
sbx policy rm network --sandbox "$LAB_NAME" --resource example.com
else
echo 'SKIP: install curl in the disposable VM, then rerun this block'
fi
網域 allowlist 只限制「送去哪裡」,不限制「送什麼」;Balanced 內的 wildcard 也可能比你想像得寬。另有一個截至 v0.38.0 的官方文件差異:部分頁面稱 raw TCP 被封鎖,local policy 文件卻描述可用目的 IP 與 port 允許非 HTTP TCP。因此本文不把 raw TCP 寫成絕對結論;在你的環境仍要用 sbx policy check 加 runtime request 驗證。UDP/ICMP 則是目前文件一致列為不可解鎖。
別漏掉 control-plane telemetry
這不屬於 Agent 自己的 egress,但仍是 host 送出的產品資料。Docker 的 FAQ截至 2026 年 8 月列出 command name、成功/失敗、執行時間與 Docker username,並說不傳 prompt、session 內容或程式碼;若政策不允許,可在啟動 sbx 前設定 SBX_NO_TELEMETRY=1。

實驗 3:憑證不印真值,只驗證是否跨界
Docker 的 proxy-managed credentials會把真 token 留在 host credential store,VM 通常只看見 proxy-managed sentinel;host proxy 對相符網域才注入 header。以下是 v0.38 的 API-key 新語法,屬於日常工作設定,不是前面的假資料 lab;建立真實認證時優先用 sandbox scope:
sbx secret set anthropic --sandbox work-claude
sbx secret set openai --sandbox work-codex
若 Codex 改用 OAuth,v0.38 官方命令是 global scope 的 sbx secret set openai --oauth,不要誤寫成 sandbox-scoped OAuth。拋棄工作 sandbox 時,也要另外移除剛才建立的 scoped credentials:
sbx secret rm anthropic --sandbox work-claude
sbx secret rm openai --sandbox work-codex
驗收時不要 env 或 echo $KEY。先用無害 decoy 證明 host env 不會自動繼承,再證明明確傳給 sbx exec -e 的值確實會進 VM:
: "${LAB_NAME:?Run the setup block first}"
ALPHALAB_HOST_ONLY_DECOY=not-a-secret \
sbx exec "$LAB_NAME" sh -lc \
'test -z "${ALPHALAB_HOST_ONLY_DECOY+x}" && echo "PASS: not inherited"'
sbx exec -e ALPHALAB_EXPLICIT_DECOY=visible "$LAB_NAME" sh -lc \
'test "$ALPHALAB_EXPLICIT_DECOY" = visible && echo "PASS: explicit env crossed"'
這個設計仍有三個剩餘風險。第一,custom kit 的 OAuth 可設 passthrough: true,真 token 會進 VM;用 sbx exec -e 或 /etc/sandbox-persistent.sh 明確放入的值也會被 Agent 看見。第二,forwarded SSH agent 雖不交出私鑰 bits,sandbox process 仍可要求它簽章;第三,Agent 看不到 token,仍可用被授予的 API 身分讀資料、開 PR 或發 issue。正確策略是短效、低權限、sandbox-scoped、可撤銷,並先讀 AI Agent 密鑰安全完整指南。
MCP 邊界:remote static 可以收窄,local stdio 可能直接回到 host
Docker MCP Gateway在 host-side boundary 管理 server 與 OAuth。Remote MCP 跑在遠端;但用 --command 或 --local 註冊的 stdio MCP 是host process。如果那個 command 能讀個人資料夾、連 host network 或操作 host Docker,它就繞過了 microVM 的檔案與 daemon 邊界。
嚴格 profile 先盤點 sbx mcp ls,避免 local stdio,並用 static mode 只掛明確需要的 remote server。以下官方 Notion 範例會開啟 OAuth,只在你願意授權的低權限測試帳號執行;啟動 Claude 仍需事先完成它自己的認證,那不屬於 Notion MCP cleanup。唯一名稱、假 workspace 與清理命令一併保留:
: "${LAB_ID:?Run the setup block first}"
: "${LAB_WS:?Run the setup block first}"
: "${LAB_NAME:?Run the setup block first}"
MCP_REG="notion-boundary-$LAB_ID"
MCP_SBX="$LAB_NAME-mcp"
sbx mcp ls # 先確認本輪唯一名稱尚未存在
sbx mcp add "$MCP_REG" --url https://mcp.notion.com/mcp
sbx run claude --name "$MCP_SBX" --static-mcp "$MCP_REG" "$LAB_WS"
# 示範完成後,清 VM、Notion MCP OAuth 與 host registration
MCP_CLEAN=1
sbx rm --force "$MCP_SBX" || MCP_CLEAN=0
sbx mcp auth rm "$MCP_REG" || MCP_CLEAN=0
sbx mcp rm "$MCP_REG" || MCP_CLEAN=0
if test "$MCP_CLEAN" = 1; then
echo 'PASS: MCP demo artifacts removed'
else
echo 'STOP: at least one MCP artifact still needs cleanup' >&2
fi
省略 --static-mcp 會進入 dynamic mode,Agent 可探索與掛入已註冊 server。這不是壞功能,但權限面更大。若你還在決定哪些能力值得掛成 MCP,可先看 MCP vs CLI Token A/B Test,再把「效率」與「host escape hatch」分開評估。

Snapshot、重建與清除:哪些東西其實不會回復?
sbx stop 只是暫停,packages、images、config 與 VM state 都保留;sbx rm 才刪除 sandbox VM。若要把目前狀態保存成可重用的 snapshot,官方命令是 sbx template save;Templates 頁目前仍把這組自訂環境能力標為 Early Access:
: "${LAB_ID:?Run the setup block first}"
: "${LAB_NAME:?Run the setup block first}"
: "${LAB_WS:?Run the setup block first}"
TEMPLATE_TAG="sbx-boundary-$LAB_ID:v1"
TEMPLATE_SBX="$LAB_NAME-template"
sbx stop "$LAB_NAME" &&
sbx template save "$LAB_NAME" "$TEMPLATE_TAG" &&
sbx rm --force "$LAB_NAME" &&
sbx run --name "$TEMPLATE_SBX" -t "$TEMPLATE_TAG" shell "$LAB_WS" &&
sbx rm --force "$TEMPLATE_SBX" &&
sbx template rm "$TEMPLATE_TAG" &&
LAB_SBX_CLEAN=1
Template 會保存整個 VM filesystem;若你曾手動把 token 寫進 VM,它也會一起被保存甚至匯出。先做 secret scan,只保存工具與依賴,認證繼續走 host proxy。更重要的是,sbx rm 不會回復 direct workspace、不會撤銷已送出的 API 動作,也不會自動刪 shared skills、host MCP registration/OAuth、saved template 或 global secret。Git 才是程式碼的 source of truth,template 只是可重建環境。
前一段只有在原 VM、重建 VM 與 template 都清理成功後,才會設定 LAB_SBX_CLEAN=1。最後再核對 parent 與六碼隨機 basename;任一條件不符,就拒絕刪 host 暫存目錄:
if test "${LAB_SBX_CLEAN:-0}" = 1; then
: "${LAB_ROOT:?Run the setup block first}"
LAB_PARENT="$(dirname -- "$LAB_ROOT")"
LAB_BASE="$(basename -- "$LAB_ROOT")"
if test "$LAB_PARENT" = '/tmp' && \
printf '%s\n' "$LAB_BASE" | grep -Eq '^sbx-boundary\.[A-Za-z0-9]{6}$'; then
rm -rf -- "$LAB_ROOT"
else
echo 'REFUSE: unexpected LAB_ROOT' >&2
fi
else
echo 'REFUSE: finish sandbox and template cleanup first' >&2
fi

團隊可直接採用的 6 條 Docker Sandboxes 基線
- 預設用 disposable repo+
--clone:先把.env與個人檔案移出 Git root;唯讀不代表不可外傳。 - 停用跨 sandbox shared skills:高風險任務加
--no-share-skills,需要的 skill 改成明確版本與 review。 - 網路從最小集合開始:先列出 provider、package registry 與 code host,逐一
policy check、runtime test、看 log;不把 Balanced 當 air gap。 - 身份比 token 字串更重要:用 sandbox-scoped、短效、低權限憑證;任務後撤銷 OAuth/token,檢查已建立的 PR 與外部動作。
- MCP 用 static remote 優先:local stdio 視為 trusted host integration;任何可碰 host Docker 的 MCP 都要升級審查。
- 結果視為 untrusted PR:除了 diff,再查
.git/hooks、CI、IDE task、Agent project config;保留 commit 後才rm並重建。
這些基線不是靠 prompt 提醒 Agent「小心一點」,而是把限制放進 Harness。若你要把 sandbox、policy、grader 與 stop condition 組成一套可執行流程,可接著讀 AI Agent Harness 實作教學。
Docker Sandboxes 常見問題 FAQ
Q1:Docker Sandboxes 就是一般 Docker container 嗎?
不是。它用 microVM 提供獨立 kernel、filesystem、network 與私人 Docker daemon;一般 container 的隔離模型不同。
Q2:用了 microVM 就絕對安全嗎?
不會。Hypervisor 強化執行層,但 workspace、允許的網路、credential 能力與 host MCP 都是刻意開放的通道。
Q3:--clone 會把 .env 藏起來嗎?
不會。它防止 Agent 寫回 host repo,但 repo root 的 untracked、gitignored 與 .env 仍能從唯讀 source mount 被看見。
Q4:Docker Sandboxes 預設完全不能上網嗎?
不一定。Open、Balanced、Locked Down,加上 kit 與組織政策,共同決定實際 egress;用 policy ls/check/log 查,不靠印象。
Q5:看不到真 token,外部帳號就安全了嗎?
不代表。Proxy 能隱藏字串,Agent 仍可運用已授權的帳號能力;scope、期限、可撤銷性才是關鍵。
Q6:MCP server 都在 microVM 裡嗎?
不是。Docker Gateway 的 local stdio MCP 跑在 host;remote MCP 在遠端,專案自己啟動的 MCP 又是另一條路,必須逐一盤點。
Q7:sbx stop 或 sbx rm 能乾淨回復嗎?
不能一概而論。stop 保留 VM state;rm 刪 VM,卻不逆轉 workspace、shared skills、host MCP、template 與外部 API 副作用。
Q8:Claude Code/Codex 內層 approval 還會再擋一次嗎?
Docker 內建模板預設不會。它們分別以 dangerous bypass flags 啟動;外層 microVM 與政策必須自己設對。
給新手的 5 個重點
- Docker Sandboxes 的價值是 microVM+私人 daemon,不是「Docker」三個字自帶安全。
- Direct mount 可即時改 host;clone mode 防寫,但不會隱藏 repo 內秘密。
- Network policy 要用 check、runtime request、log 三層驗收。
- Credential 的目標是保留真值並縮小身份權限;MCP 則要特別防 host-local command。
- Git 管程式碼,template 管環境;
rm後仍要清 host 與外部副作用。
想系統化學 Agent、tools、eval 與 automation,可從 AlphaLab AI 課程開始;更多實作案例收錄在 AI 專區。
接著閱讀
左右滑動查看更多推薦
結語:先關四扇門,再把 Agent 放進去
Docker Sandboxes 把 Claude Code/Codex 的執行環境移到獨立 microVM,確實比「container 掛 host socket」多一道重要邊界;但真正的安全結果,仍由 workspace、network、credentials 與 MCP 四扇門決定。把它當成一間可丟棄的工作室,而不是魔法保險箱,才不會在最需要隔離時反而把整串鑰匙遞進去。
今天的下一步很簡單:先在全是假資料的 throwaway repo 跑完檔案正反例與網路三層驗收,再建立一個 --clone --no-share-skills 的工作 sandbox。只有當「不該看見的看不見、不該送出的送不出、該清掉的真的清掉」,才讓真實 Agent 與最小權限憑證進場。






