claude-sandbox-traps

Claude Code 샌드박스 설정: 자동화 스크립트를 격리 환경에서 돌리기

Claude Code 샌드박스 한 줄 요약

Claude Code 샌드박스를 무감독 자동화에 쓸 거면 /sandbox만 켜고 끝내면 안 돼요. 2026-04-18 기준 공식 문서는 allowUnsandboxedCommands 기본값을 true로 두고 있어서, 실패한 명령이 샌드박스 밖으로 다시 뛰는 길이 열려 있거든요. 최소 기준은 failIfUnavailable: true, allowUnsandboxedCommands: false, denyReadRead(~/**)를 같이 넣는 거예요. WSL2는 2026-03-07에 보고된 v2.1.71 회귀 이슈가 not planned로 닫혀 있으니, 여기서 막히면 Docker Sandboxes나 nono, VM으로 한 단계 올리는 쪽이 더 안전해요.

샌드박스 켰으니까 됐겠지 하고 auto-allow로 밤새 돌려놨다가, 아침에 로그 보고 식겁한 적이 있어요. Claude Code 샌드박스는 분명 유용한데 기본값만 믿으면 빈틈이 남거든요. 공식 문서는 OS 수준 격리를 강조하지만, 실제로는 escape hatch(샌드박스 밖으로 다시 빠져나가는 우회 경로)가 켜져 있고 denyRead도 한 번 더 잠가야 해요. 저도 처음엔 /sandbox만 켜면 홈 디렉터리 읽기까지 다 막아주는 줄 알았는데 아니더라고요. 문제는 이런 틈이 짧은 실험보다 무감독 자동화에서 크게 터진다는 점이에요. 실패한 명령이 밖으로 재시도되거나, WSL2에서 샌드박스가 아예 비활성화된 채로 지나가면 그때부터는 그냥 평소 셸이랑 다를 게 없죠. 그리고 로컬 사용 환경(surface)인 CLI, 데스크톱, VS Code, JetBrains가 같은 설정을 공유한다는 점도 중요해요. 한 번 제대로 잠가두면 창만 바뀌고 기준은 그대로인 셈이죠. 설치 자체가 아직 낯설면 Claude Code 사용법: 설치부터 첫 실행까지 5분 가이드부터 먼저 보고 와도 좋아요.

Claude Code 샌드박스가 적용되는 사용 환경부터 정리

Claude Code 샌드박스는 Claude 전체에 한 번에 걸리는 스위치가 아니에요. 로컬 사용 환경과 클라우드 사용 환경을 먼저 나눠야 어떤 설정이 어디까지 먹는지 안 헷갈려요.

웹에서 보이는 Claude까지 같은 settings.json으로 잠긴다고 생각한 건 아니죠?

사용 환경 Claude가 실제로 도는 곳 /sandbox 직접 제어 이 글에서 보는 범위
CLI 내 Mac, Linux, WSL2 터미널 가능 핵심
Desktop 내 로컬 머신 가능 핵심
VS Code 내 로컬 머신 가능 핵심
JetBrains 내 로컬 머신 가능 핵심
Web Anthropic 관리 클라우드 불가 비교만
Mobile Claude 앱의 cloud session 또는 Remote Control 불가 비교만
Chrome 브라우저 통합 불가 비교만
Slack Anthropic cloud 불가 비교만
GitHub Actions / GitLab CI/CD 러너, 컨테이너, VM마다 다름 환경별 비교만

공식 Platforms and integrations 문서에 따르면 Claude Code는 사용 환경이 달라도 같은 엔진을 쓰고, 로컬 사용 환경은 설정과 프로젝트 메모리, MCP 연결을 공유해요. 그래서 CLI에서 잠근 설정이 데스크톱, VS Code, JetBrains에도 같이 묻어가죠. UI 기준으로 어디까지 이어지는지 먼저 감 잡고 싶다면 Claude Code 데스크톱 앱 사용법: CLI에서 앱으로 워크플로 옮기기를 같이 보면 정리가 빨라요.

Claude Code 공식 Platforms 문서에 정리된 Desktop, VS Code, JetBrains, Web, Mobile 사용 환경 비교 표
로컬과 클라우드 사용 환경을 먼저 나누면 설정 범위가 바로 보여요 (출처: Claude Code 공식 문서)

왜 샌드박스 없이 자동화 돌리면 안 되는지

샌드박스는 귀찮은 옵션이 아니라 최소 안전장치예요. 파일 경계와 네트워크 경계를 같이 안 잡으면, 무감독 자동화는 그냥 내 셸 권한을 에이전트한테 빌려주는 거랑 비슷해져요.

설마 홈 디렉터리를 그대로 열어 둔 상태로 auto-allow를 켜둘 건 아니죠?

그런데 공식 문서 기본값만 믿으면 사실상 그거랑 크게 다를 게 없어요. 2025-10-20에 올라온 Anthropic의 sandboxing 엔지니어링 글은 파일시스템과 네트워크를 같이 막아야 prompt injection 때 SSH 키 같은 민감한 파일이 밖으로 안 새나간다고 설명해요. 같은 글에서 내부 사용 기준 permission prompt가 84% 줄었다고도 적어뒀고요. 그러니까 이건 보안만의 문제가 아니에요. 사람이 덜 눌러도 되는 자동화를 만들기 위한 기본선에 가까워요.

삭제 사고도 이미 있었어요. 2025-12-07에 Reddit에 올라온 홈 디렉터리 삭제 사례는 GIGAZINE이 2025-12-16에 따로 정리했어요. 그 뒤로 2026-01까지 비슷한 삭제 경험담이 더 붙었고, 공통점은 샌드박스 없이 로컬 파일을 직접 건드리게 뒀다는 거였어요.

무감독 작업 전 체크는 이 정도는 꼭 보세요.

  • 작업 폴더 밖 읽기를 막았는지 본다
  • 작업 폴더 밖 쓰기를 막았는지 본다
  • 네트워크 allowlist나 차단 정책이 있는지 본다
  • escape hatch를 껐는지 본다
  • 실패 로그를 어디서 볼지 정해둔다

경계만 잡고 끝내면 또 불안하더라고요. 오래 돌리는 세션은 결국 로그를 봐야 하니까, 발행 파이프라인처럼 길게 돌릴 거면 Claude Code Monitor 도구로 배포 로그 실시간 추적하기 같은 흐름도 같이 붙여두는 편이 낫죠.

Claude Code 공식 문서의 Why sandboxing matters 섹션 — approval fatigue, reduced productivity, limited autonomy를 나열
공식 문서도 매번 승인 누르면 주의력이 떨어진다는 걸 먼저 꼽아요 (출처: Claude Code 공식 문서)

Claude Code 샌드박스 기본값의 세 가지 함정

Claude Code 샌드박스가 불안한 이유는 기능이 없어서가 아니에요. 기본값과 문서 읽는 순서 때문에 착각하기 쉬운 함정이 세 개 있거든요.

샌드박스 켰는데 Claude가 왜 계속 읽고, 왜 다시 시도하지 싶었다면 보통 이 세 가지에서 걸려요.

함정 2026-04-18 기준 상태 바로 할 일
escape hatch 기본 활성화 allowUnsandboxedCommands 기본값이 true false로 명시
denyRead만 믿기 sandbox는 Bash 경계, Read 도구는 permissions.deny도 필요 Read(~/**) 같이 넣기
WSL2 회귀 GitHub Issue #31708(Claude Code 샌드박스 비활성 보고)이 not planned로 닫힘, 마지막 정상 버전은 이슈 본문 기준 v2.1.69 최신 버전 재테스트, 안 되면 다른 격리층 사용

공식 Sandboxing 문서Settings 문서를 같이 보면, 실패한 명령은 dangerouslyDisableSandbox로 다시 시도할 수 있고 allowUnsandboxedCommands: false일 때만 그 길이 완전히 닫혀요. 여기가 첫 번째 함정이에요. “샌드박스 켰다”와 “밖으로 절대 못 나간다”는 다른 말이거든요.

두 번째는 읽기 차단이에요. Permissions 문서Read deny 규칙이 Claude의 내장 Read, Grep, Glob 계열에 적용되고, Bash subprocess는 OS-level sandbox가 막는다고 적어둬요. 그러니까 sandbox.filesystem.denyRead만 넣으면 Bash는 막혀도 Read 도구는 별도로 잠가야 해요.

세 번째는 WSL2예요. 공식 문서는 WSL2를 지원 대상으로 적지만, 2026-03-07에 올라온 Issue #31708v2.1.71에서 ⚠ sandbox disabled가 남고 /sandbox 화면에 Dependencies 탭만 보이는 회귀를 기록해요. 로컬 WSL2가 계속 말썽이면 Claude Code on the Web 사용법: 브라우저에서 돌리는 AI 코딩 에이전트처럼 cloud session으로 잠깐 우회하는 쪽이 더 빠를 때도 있어요.

Claude Code 공식 문서의 Configure sandboxing 섹션 — sandbox.filesystem.allowWrite 설정 JSON 예시
공식 문서가 보여주는 JSON 뼈대 자체가 기본값 함정을 피하는 첫 템플릿이에요 (출처: Claude Code 공식 문서)

Claude Code 샌드박스 settings.json 제대로 잠그는 법

최소 목표는 세 가지예요. 샌드박스가 안 켜지면 그냥 멈추고, Claude가 자기 마음대로 밖으로 못 나가게 막고, 홈 디렉터리 읽기를 Bash와 Read 도구 둘 다에서 잠그는 거죠.

설정 한 줄 아끼다가 홈 디렉터리 전체를 열어둘 이유는 없죠?

아래처럼 프로젝트 단위 .claude/settings.json부터 잡는 걸 권해요.

# 프로젝트 단위 설정 파일 만들기
mkdir -p .claude
${EDITOR:-vi} .claude/settings.json

# 저장 후 새 세션에서 상태 다시 보기
claude
/sandbox

# 출력 예시
# sandbox enabled
{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "autoAllowBashIfSandboxed": true,
    "allowUnsandboxedCommands": false,
    "excludedCommands": ["docker *"],
    "filesystem": {
      "denyRead": ["~/"],
      "allowRead": ["."]
    }
  },
  "permissions": {
    "deny": [
      "Read(~/**)"
    ]
  }
}

이 설정에서 중요한 포인트만 짚으면 이래요.

  • failIfUnavailable: true: 샌드박스가 안 켜졌는데 그냥 진행하는 걸 막아요
  • allowUnsandboxedCommands: false: escape hatch를 원천 차단해요
  • denyRead: ["~/"]: Bash와 그 자식 프로세스가 홈 디렉터리를 읽지 못하게 막아요
  • Read(~/**): Claude의 내장 Read 계열 도구를 같이 막아요
  • allowRead: ["."]: 프로젝트 루트만 다시 열어요

여기서 .이 어디를 뜻하느냐도 함정이에요. 공식 문서 기준으로 프로젝트 안 .claude/settings.json에서 .은 프로젝트 루트예요. 반대로 사용자 홈의 ~/.claude/settings.json에 넣으면 .~/.claude를 뜻하니까, 이 예시는 프로젝트 파일에 두는 게 덜 헷갈려요. 고정 규칙을 더 세게 걸고 싶다면 Claude Code Hooks 완벽 가이드 – 자동화 훅 설정법처럼 훅으로 한 번 더 막는 것도 괜찮아요.

Claude Code 공식 문서의 Enable sandboxing 섹션 — /sandbox 명령과 sandbox.failIfUnavailable: true 설명
failIfUnavailable: true는 샌드박스 실패 시 그냥 넘어가지 않게 잠그는 핵심 옵션이에요 (출처: Claude Code 공식 문서)

샌드박스 안에서 깨지는 명령과 우회 레시피

샌드박스는 안전하지만 모든 CLI가 바로 맞물리진 않아요. 초반에 제일 많이 부딪히는 건 .git, watchman, Docker daemon, 프록시/TLS 쪽이거든요.

왜 하필 처음 세팅할 때 필요한 명령만 제일 잘 깨질까요?

상황 왜 막히나 가장 현실적인 우회
git init, git clone .git 보호 영역과 초기화 흐름이 충돌 Claude 시작 전에 먼저 끝내기
일부 uv 명령 .git marker나 캐시 경로 접근에서 실패 프로젝트 초기화는 먼저 수동 실행
jest watchman이 sandbox와 호환 안 됨 jest --no-watchman
docker host daemon socket이 경계 밖에 있음 docker * 분리 또는 Docker Sandboxes 사용

공식 문서는 watchman 비호환과 docker * 분리를 팁으로 적어두고 있어요. 근데 Issue #22620을 보면 excludedCommands가 일부 도구에서 기대처럼 바로 unsandboxed로 안 뛰는 사례도 있었어요. 그래서 uvgit 계열은 “Claude가 시작된 뒤 우회”보다 “Claude 시작 전에 먼저 초기화”가 덜 꼬이더라고요.

제가 제일 무난하게 쓰는 순서는 이거예요.

# 저장소와 기본 뼈대는 Claude 밖에서 먼저 만들기
mkdir demo-app && cd demo-app
git init

# 그다음 Claude 시작
claude

# 테스트는 watchman 없이 돌리기
npm test -- --no-watchman

# 출력 예시
# PASS src/app.test.ts

길게 돌리다가 중간에 어디서 막혔는지 폰으로 바로 이어서 보고 싶을 땐 Claude Code Remote Control 사용법: 폰에서 이어받고 VPS에서 돌리기 조합도 꽤 쓸 만해요. 재실행보다 상태 확인이 먼저인 상황이 많거든요.

Claude Code 공식 문서의 What sandboxing does not cover — 내장 Read/Edit/Write 도구와 Computer use는 OS sandbox가 아닌 permission 시스템으로 막힌다는 설명
공식 문서도 “sandbox가 모든 도구를 다 막지는 않는다”를 따로 경고해둬요 (출처: Claude Code 공식 문서)

네이티브 샌드박스로 부족할 때 선택 기준

Claude Code 샌드박스 네이티브 설정으로도 개인 작업은 대부분 커버돼요. 근데 무감독 자동화 기준이면 저는 “잠근 native → Docker Sandboxes나 nono → VM” 순으로 올려요. 리셋 비용과 host 노출 범위를 같이 봐야 덜 후회하거든요.

격리 강도 사다리 비교표

근데 진짜 Docker나 VM까지 가야 하나 싶다면, 아래 표에서 고르면 돼요.

방식 격리 경계 Windows escape hatch 언제 쓰면 좋나
Claude Code 네이티브 sandbox Seatbelt(macOS), bubblewrap(Linux) WSL2만 사실상 가능 기본값으로는 있음 개인 프로젝트, 빠른 세팅
Docker Sandboxes microVM + 별도 Docker daemon 공식 docs 기준 가능 Claude 쪽 escape hatch 의존도 낮음 Docker까지 돌리는 자동화
nono 커널 강제 격리, Landlock/Seatbelt 미지원 없음 host 파일을 진짜 강하게 막고 싶을 때
devcontainer 컨테이너 + 네트워크 규칙 Docker 환경에 좌우 Claude bypass 설정에 따라 다름 팀 공용 개발 환경 맞추기
VM 게스트 OS 전체 가능 게스트 밖으로는 사실상 없음 신뢰 못 하는 코드, 실수 비용이 큰 작업

Docker Sandboxes, nono, devcontainer, VM 결이 다른 이유

여기서 결이 좀 갈려요.

  • Docker Sandboxes는 공식 Docker docs 기준으로 2026-04-18 현재 Experimental이에요. 대신 sbx run claude 한 줄로 microVM 안에서 별도 Docker daemon까지 쓸 수 있는 점이 강해요.
  • nono는 공식 docs공식 사이트 기준으로 macOS Seatbelt, Linux Landlock를 쓰고, “once applied, cannot be loosened”라는 식의 커널 강제 격리를 내세워요.
  • devcontainer는 공식 문서가 unattended operation 쪽을 밀어주지만, 같은 저장소의 Issue #19978에서 best-practices와 충돌이 지적됐어요.
  • VM은 제일 무겁지만 사고 나면 지우고 다시 만들면 끝나는 경계가 생겨요. 이게 꽤 커요.

Docker Sandboxes와 nono 실행 명령 감각

실행 감각만 보면 이런 식이에요.

# Docker Sandboxes에서 Claude 실행
sbx login
cd ~/my-project
sbx run claude
# nono에서 Claude 실행
nono run --profile claude-code -- claude

# 더 빡세게 하려면 네트워크까지 막기
nono run --profile claude-code --net-block -- claude

# 출력 예시
# Sandbox active. Restrictions are now in effect

nono는 한 가지 주의가 있어요. 기본 claude-code profile이 편하긴 한데, docs에 보면 network.block = false라서 네트워크가 기본 허용이에요. escape hatch가 없는 대신 네트워크는 따로 닫아야 한다는 뜻이죠.

가격까지 같이 보면 선택이 빨라져요

가격도 빼면 안 돼요. 2026-04-18 기준 Claude 공식 가격 페이지는 Pro 월 $20 또는 연간 환산 월 $17, Max 5x 월 $100, Max 20x 월 $200, Team Standard seat 좌석당 월 $25 또는 연간 환산 월 $20, Team Premium seat 좌석당 월 $125 또는 연간 환산 월 $100이라고 적어둬요. Docker 공식 가격 페이지는 Personal $0, Pro 월 $11 또는 연간 환산 월 $9, Team 월 $16 또는 연간 환산 월 $15, Business 월 $24예요. 근데 Docker Sandboxes가 정확히 어느 플랜에 포함되는지는 가격 페이지에 따로 박혀 있지 않아서, 발행 전에는 그 부분을 다시 보는 게 안전해요. 원격 실행까지 넓혀 볼 생각이면 Claude Code Ultraplan으로 클라우드에서 대규모 리팩터링 돌리기도 이어서 보면 로컬 격리와 원격 실행을 어디서 나눌지 감이 더 빨리 잡혀요.

Docker Sandboxes 공식 문서의 Get started — macOS에서 `brew install docker/tap/sbx` 뒤 `sbx login`과 `sbx run claude`로 진입하는 명령 화면
Docker Sandboxes는 현재 Experimental이지만 sbx run claude 한 줄이면 microVM 안으로 바로 들어가요 (출처: Docker 공식 문서)

자주 묻는 질문

Q1: macOS에서 샌드박스 없이 Claude Code 써도 되나요?

A: 추천하지 않아요. 2025-12-07에 올라온 홈 디렉터리 삭제 사례가 2025-12-16 GIGAZINE 기사로도 정리됐고, 사고 패턴이 전부 “로컬 셸 권한을 그대로 맡긴 상태”였거든요. 짧은 실험이어도 allowUnsandboxedCommands: false는 먼저 넣는 게 좋아요.

Q2: WSL2에서 bubblewrap이 다 깔렸는데도 왜 sandbox disabled로 뜨나요?

A: 2026-03-07에 열린 GitHub 이슈 #31708이 딱 그 증상이에요. 이슈 본문 기준 마지막 정상 버전은 v2.1.69, 문제 버전은 v2.1.71이었고 not planned로 닫혔어요. 최신 버전에서 다시 재현되는지 먼저 보고, 계속 막히면 Docker Sandboxes나 VM으로 우회하는 게 덜 스트레스예요.

Q3: denyRead: ["~/"]를 넣었는데 Claude가 홈 파일을 읽어요.

A: denyRead는 OS-level sandbox 경계예요. Bash와 그 자식 프로세스는 막아도, Claude의 내장 Read 계열 도구는 permissions.deny 쪽 규칙도 같이 있어야 해요. 그래서 denyReadRead(~/**)를 같이 쓰는 거죠.

Q4: git, uv, jest가 샌드박스 안에서 자꾸 깨져요.

A: 초반 초기화 명령은 샌드박스가 제일 까다롭게 보는 구간이라 그래요. git init, 일부 uv 명령은 Claude 시작 전에 먼저 끝내고, jest--no-watchman으로 바꾸면 부딪히는 횟수가 줄어요. 무조건 sandbox 안에서 다 해결하려고 하면 더 오래 걸릴걸요.

Q5: devcontainer 안에서 --dangerously-skip-permissions를 써도 안전한가요?

A: 무조건 안전하다고 보긴 어려워요. 공식 devcontainer 문서는 unattended operation을 허용한다고 적지만, best-practices 문서는 인터넷 없는 격리 환경에서만 쓰라고 해요. 외부 연결이 열려 있으면 “컨테이너 안”이라는 말만으로는 충분하지 않다고 보고 들어가는 편이 맞아요.

Similar Posts

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다