업데이트로 돌아가기
New releaseJul 21, 2026

sandbox-runtime v0.0.66

임의의 프로세스에 대해 OS 수준에서 파일 시스템 및 네트워크 제한을 적용하는 가벼운 샌드박싱 도구로, 컨테이너가 필요하지 않습니다.

공유

Anthropic 샌드박스 런타임 (srt)

컨테이너 없이 OS 수준에서 임의의 프로세스에 파일시스템 및 네트워크 제한을 적용하기 위한 경량 샌드박싱 도구입니다.

srt는 네이티브 OS 샌드박싱 프리미티브(macOS의 sandbox-exec, Linux의 bubblewrap)와 프록시 기반 네트워크 필터링을 사용합니다. 에이전트, 로컬 MCP 서버, bash 명령 및 임의의 프로세스의 동작을 샌드박싱하는 데 사용할 수 있습니다.

베타 연구 미리보기

샌드박스 런타임은 더 안전한 AI 에이전트를 지원하기 위해 Claude Code용으로 개발된 연구 미리보기입니다. 더 넓은 생태계가 더 안전한 에이전트 시스템을 구축할 수 있도록 조기 오픈 소스 미리보기로 제공되고 있습니다. 초기 연구 미리보기이므로 API 및 구성 형식은 변경될 수 있습니다. AI 에이전트를 기본적으로 더 안전하게 만들기 위한 피드백과 기여를 환영합니다!

설치```bash

npm install -g @anthropic-ai/sandbox-runtime

## 기본 사용법```bash
# Network restrictions
$ srt "curl anthropic.com"
Running: curl anthropic.com
<html>...</html>  # Request succeeds

$ srt "curl example.com"
Running: curl example.com
Connection blocked by network allowlist  # Request blocked

# Filesystem restrictions
$ srt "cat README.md"
Running: cat README.md
# Anthropic Sandb...  # Current directory access allowed

$ srt "cat ~/.ssh/id_rsa"
Running: cat ~/.ssh/id_rsa
cat: /Users/ollie/.ssh/id_rsa: Operation not permitted  # Specific file blocked

개요

이 패키지는 CLI 도구와 라이브러리로 모두 사용할 수 있는 독립형 샌드박스 구현을 제공합니다. 일반적인 개발자 사용 사례에 맞춰 기본적으로 안전한(secure-by-default) 설계 철학을 따릅니다. 프로세스는 최소한의 접근 권한으로 시작하며, 필요한 구멍만 명시적으로 뚫어주는 방식입니다.

주요 기능:

  • 네트워크 제한: HTTP/HTTPS 및 기타 프로토콜을 통해 접근할 수 있는 호스트/도메인 제어
  • 파일시스템 제한: 읽기/쓰기가 가능한 파일/디렉터리 제어
  • Unix 소켓 제한: 로컬 IPC 소켓에 대한 접근 제어
  • 위반 모니터링: macOS에서 시스템의 샌드박스 위반 로그 저장소를 활용한 실시간 알림

사용 사례 예시: MCP 서버 샌드박싱

주요 사용 사례는 Model Context Protocol(MCP) 서버를 샌드박싱하여 그 기능을 제한하는 것입니다. 예를 들어, 파일시스템 MCP 서버를 샌드박싱하려면:

샌드박싱 없이 (.mcp.json):```json { "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem"] } } }

**샌드박싱 사용 시** (`.mcp.json`):```json
{
  "mcpServers": {
    "filesystem": {
      "command": "srt",
      "args": ["npx", "-y", "@modelcontextprotocol/server-filesystem"]
    }
  }
}

그런 다음 ~/.srt-settings.json에서 제한 사항을 구성합니다:```json { "filesystem": { "denyRead": [], "allowWrite": ["."], "denyWrite": ["~/sensitive-folder"] }, "network": { "allowedDomains": [], "deniedDomains": [] } }

이제 MCP 서버는 거부된 경로에 쓰는 것이 차단됩니다:```
> Write a file to ~/sensitive-folder
✗ Error: EPERM: operation not permitted, open '/Users/ollie/sensitive-folder/test.txt'

작동 방식

샌드박스는 프로세스 트리 전체에 적용되는 제한을 강제하기 위해 OS 수준의 프리미티브를 사용합니다:

  • macOS: 동적으로 생성된 Seatbelt 프로파일과 함께 sandbox-exec 사용
  • Linux: 네트워크 네임스페이스 격리를 통한 컨테이너화에 bubblewrap 사용
  • Windows: 샌드박스 처리된 프로세스를 전용 srt-sandbox 로컬 사용자 계정으로 실행하며, 해당 계정의 SID를 기준으로 한 Windows 필터링 플랫폼 이그레스 펜스와 작업 트리에 대한 세션별 명시적 ACE를 적용

0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305

이중 격리 모델

효과적인 샌드박싱을 위해서는 파일시스템 격리와 네트워크 격리가 모두 필요합니다. 파일 격리가 없으면 손상된 프로세스가 SSH 키나 기타 민감한 파일을 유출할 수 있습니다. 네트워크 격리가 없으면 프로세스가 샌드박스를 탈출하여 제한 없는 네트워크 액세스를 얻을 수 있습니다.

파일시스템 격리는 읽기 및 쓰기 제한을 강제합니다:

  • 읽기(거부 후 허용 패턴): 기본적으로 읽기 액세스는 모든 곳에서 허용됩니다. 넓은 영역(예: /Users)을 거부한 다음 그 안의 특정 경로(예: .)를 다시 허용할 수 있습니다. allowReaddenyRead보다 우선합니다 — 쓰기와 반대이며, 쓰기에서는 denyWriteallowWrite보다 우선합니다. allowRead 영역 내에 속하면서 더 구체적인 denyRead 항목(예: allowRead: ["."]와 함께 denyRead: ["**/.env"] 또는 ["./secrets"])은 여전히 거부 상태로 유지됩니다.
  • 쓰기(허용 전용 패턴): 기본적으로 쓰기 액세스는 모든 곳에서 거부됩니다. 경로(예: ., /tmp)를 명시적으로 허용해야 합니다. 허용 목록이 비어 있으면 쓰기 액세스가 없음을 의미합니다.

네트워크 격리(허용 전용 패턴): 기본적으로 모든 네트워크 액세스는 거부됩니다. 도메인을 명시적으로 허용해야 합니다. allowedDomains 목록이 비어 있으면 네트워크 액세스가 없음을 의미합니다. 네트워크 트래픽은 호스트에서 실행되는 프록시 서버를 통해 라우팅됩니다:

  • Linux: 요청은 Unix 도메인 소켓을 통해 파일시스템으로 라우팅됩니다. 샌드박스 처리된 프로세스의 네트워크 네임스페이스는 완전히 제거되므로 모든 네트워크 트래픽은 호스트에서 실행되는 프록시(샌드박스에 바인드 마운트된 Unix 소켓에서 수신)를 통과해야 합니다

  • macOS: Seatbelt 프로파일은 특정 localhost 포트에 대한 통신만 허용합니다. 프록시는 이 포트에서 수신하여 모든 네트워크 액세스를 위한 제어된 채널을 생성합니다

  • Windows: 시스템 전체 WFP 필터 세트는 srt-sandbox 계정에서 시작되는 모든 아웃바운드 연결을 프록시 포트 범위에 대한 루프백을 제외하고 차단합니다. 프록시는 해당 범위 내에서 수신하여 모든 네트워크 액세스를 위한 제어된 채널을 생성합니다

HTTP/HTTPS(HTTP 프록시를 통한) 및 기타 TCP 트래픽(SOCKS5 프록시를 통한) 모두 이러한 프록시에 의해 중재되며, 프록시는 도메인 허용 목록과 거부 목록을 강제합니다.

Claude Code의 샌드박싱에 대한 자세한 내용은 다음을 참조하세요:

아키텍처```

src/ ├── index.ts # Library exports ├── cli.ts # CLI entrypoint (srt command) ├── utils/ # Shared utilities │ ├── debug.ts # Debug logging │ ├── settings.ts # Settings reader (permissions + sandbox config) │ ├── platform.ts # Platform detection │ └── exec.ts # Command execution utilities └── sandbox/ # Sandbox implementation ├── sandbox-manager.ts # Main sandbox manager ├── sandbox-schemas.ts # Zod schemas for validation ├── sandbox-violation-store.ts # Violation tracking ├── sandbox-utils.ts # Shared sandbox utilities ├── http-proxy.ts # HTTP/HTTPS proxy for network filtering ├── socks-proxy.ts # SOCKS5 proxy for network filtering ├── linux-sandbox-utils.ts # Linux bubblewrap sandboxing ├── macos-sandbox-utils.ts # macOS sandbox-exec sandboxing └── windows-sandbox-utils.ts # Windows srt-win sandboxing

## 사용법

### CLI 도구로 사용

`srt` 명령(Anthropic Sandbox Runtime)은 모든 명령을 보안 경계로 감쌉니다:```bash
# Run a command in the sandbox
srt echo "hello world"

# With debug logging
srt --debug curl https://example.com

# Specify custom settings file
srt --settings /path/to/srt-settings.json npm install

라이브러리로 사용하기```typescript

import { SandboxManager, type SandboxRuntimeConfig, } from '@anthropic-ai/sandbox-runtime' import { spawn } from 'child_process'

// Define your sandbox configuration const config: SandboxRuntimeConfig = { network: { allowedDomains: ['example.com', 'api.github.com'], deniedDomains: [], }, filesystem: { denyRead: ['~/.ssh'], allowWrite: ['.', '/tmp'], denyWrite: ['.env'], }, }

// Initialize the sandbox (starts proxy servers, etc.) await SandboxManager.initialize(config)

// Wrap a command with sandbox restrictions const sandboxedCommand = await SandboxManager.wrapWithSandbox( 'curl https://example.com', )

// Execute the sandboxed command const child = spawn(sandboxedCommand, { shell: true, stdio: 'inherit' })

// Handle exit and cleanup after child process completes child.on('exit', async code => { console.log(Command exited with code ${code}) // Cleanup when done (optional, happens automatically on process exit) await SandboxManager.reset() })

**위반 귀속(`commandId` / `commandText`).** 래핑된 명령이 실행되는 동안 관찰된 위반(seatbelt 로그 라인, seccomp 이벤트, 프록시 거부)은 귀속 키 아래에 저장되며, `annotateStderrWithSandboxFailures(key, stderr)` / `getViolationsForCommand(key)`는 동일한 키로 이를 조회합니다. 기본적으로 키는 래핑된 문자열 자체입니다. 대신 불투명한 호출별 `commandId`(예: 도구 사용 ID)를 전달하여 이를 키로 사용할 수 있습니다 — 권장 사항: 키는 처음 100자에서 비교되므로, 접두사를 공유하는 긴 명령은 그렇지 않으면 교차 귀속되며, 동일한 텍스트를 다시 실행하면 이전 실행의 이벤트를 상속하게 됩니다. 실행하는 문자열이 호출이 *나타내는* 명령이 아닌 경우(예: 조합된 `source <snapshot> && eval '<cmd>'`를 래핑하는 경우), `commandText: '<cmd>'`도 전달하십시오: 이것은 `ignoreViolations` 명령 패턴이 매칭하는 대상이자 각 위반이 자체 `command`로 보고하는 내용입니다.```typescript
const wrapped = await SandboxManager.wrapWithSandbox(
  assembledCommand, // what actually runs
  undefined,
  undefined,
  undefined,
  { commandId: invocationId, commandText: rawCommand },
)
// ... run it ...
const annotated = SandboxManager.annotateStderrWithSandboxFailures(invocationId, stderr)

사용 가능한 내보내기```typescript

// Main sandbox manager export { SandboxManager } from '@anthropic-ai/sandbox-runtime'

// Violation tracking export { SandboxViolationStore } from '@anthropic-ai/sandbox-runtime'

// TypeScript types export type { SandboxRuntimeConfig, NetworkConfig, FilesystemConfig, IgnoreViolationsConfig, SandboxAskCallback, FsReadRestrictionConfig, FsWriteRestrictionConfig, NetworkRestrictionConfig, } from '@anthropic-ai/sandbox-runtime'

## 구성

### 설정 파일 위치

기본적으로 샌드박스 런타임은 `~/.srt-settings.json`에서 구성을 찾습니다. `--settings` 플래그를 사용하여 사용자 지정 경로를 지정할 수 있습니다:```bash
srt --settings /path/to/srt-settings.json <command>

전체 구성 예시```json

{ "network": { "allowedDomains": [ "github.com", ".github.com", "lfs.github.com", "api.github.com", "npmjs.org", ".npmjs.org" ], "deniedDomains": ["malicious.com"], "allowUnixSockets": ["/var/run/docker.sock"], "allowLocalBinding": false }, "filesystem": { "denyRead": ["~/.ssh"], "allowRead": [], "allowWrite": [".", "src/", "test/", "/tmp"], "denyWrite": [".env", "config/production.json"] }, "ignoreViolations": { "*": ["/usr/bin", "/System"], "git push": ["/usr/bin/nc"], "npm": ["/private/tmp"] }, "enableWeakerNestedSandbox": false, "enableWeakerNetworkIsolation": false, "allowAppleEvents": false }

### 구성 옵션

#### 네트워크 구성

**허용 전용 패턴(allow-only pattern)**을 사용합니다. 기본적으로 모든 네트워크 접근이 거부됩니다.

- `network.allowedDomains` - 허용된 도메인 배열(`*.example.com` 같은 와일드카드 지원). 빈 배열 = 네트워크 접근 없음. 선택적 `:port` 접미사(`api.example.com:443`, `*.example.com:8443`)는 해당 항목을 해당 대상 포트로 제한합니다. 포트가 없는 항목은 모든 포트와 일치합니다.
  - IPv6 리터럴은 RFC 3986 스타일로 대괄호로 묶어야 합니다: `[::1]`, `[2001:db8::1]:443`. 대괄호 없이 콜론이 여러 개인 항목은 모호하다고 판단되어 거부됩니다(`2001:db8::1:443` 자체는 유효한 주소입니다).
- `network.deniedDomains` - 거부된 도메인 배열(먼저 확인되며 `allowedDomains`보다 우선함). 동일한 `:port` 접미사를 사용하며, 단독 `*`(또는 `*:22`)는 모두 거부(all-deny)로 허용됩니다.
- `network.deniedDomainReasons` - 선택적 맵으로, `deniedDomains` 항목(정확한 문자열로 일치)을 해당 항목이 연결을 거부할 때 `<sandbox_violations>` 줄에 표시되는 모델 노출용 사유에 매핑합니다. 차단된 항목과 허용된 대안을 설명하세요(예: `{"github.com:22": "SSH pushes to GitHub are blocked; use an https:// remote"}`). 사유가 없는 항목은 일반 사유를 보고합니다. SSH 대상(포트 22)의 경우 사유는 인밴드(in-band)로도 전달됩니다. 무인증 SOCKS ProxyCommand(예: BSD `nc -X 5`)를 통해 터널링된 SSH 클라이언트는 키 교환 전 SSH 연결 끊김을 수신하며, 그 설명이 사유가 되고 OpenSSH가 이를 그대로 출력합니다. OpenSSH는 비ASCII 문자를 자르고 이스케이프 처리하므로, 이러한 사유는 약 400 ASCII 문자 미만으로 유지하고 명령형으로 시작하세요.
- `network.allowLocalBinding` - 로컬 포트 바인딩 허용(불리언, 기본값: false)

**TLS 종료(TLS termination)** (`network.tlsTerminate`, 실험적): 설정 시 HTTPS CONNECT가 프로세스 내에서 종료되어 SRT가 복호화된 요청을 볼 수 있습니다(그리고 `network.filterRequest`를 통해 필터링할 수 있습니다). 샌드박스 프로세스는 MITM CA(`caCertPath`/`caKeyPath`, 또는 생략 시 임시 CA)와 호스트의 일반 루트를 포함하는 신뢰 번들(trust bundle)을 가리키므로, 프록시가 발급한 인증서와 실제 업스트림 인증서가 모두 검증됩니다.

- `network.tlsTerminate.excludeDomains` - 종료되지 **않는** 도메인 패턴(`allowedDomains`와 동일한 구문). 일치하는 CONNECT는 대신 불투명하게 터널링됩니다. 여전히 도메인 허용 목록의 적용을 받지만, 샌드박스 내부의 클라이언트가 실제 업스트림과 자체 TLS 핸드셰이크를 완료하며, `filterRequest`/자격 증명 주입은 해당 HTTPS 트래픽에 적용되지 않습니다. TLS 종료가 근본적으로 깨뜨리는 두 가지 경우에 사용하세요:
  - **mTLS 업스트림** - 클라이언트 인증서를 보유한 것은 샌드박스 내부의 클라이언트뿐이므로, 프록시가 해당 클라이언트를 대신해 연결을 다시 시작할 수 없습니다.
  - **인증서 고정 클라이언트(Certificate-pinning clients)** - 업스트림의 신원을 스스로 검증하는 클라이언트(사용자 지정 CA, SAN 고정)로, MITM 인증서를 거부합니다.
- `network.tlsTerminate.extraCaCertPaths` - 해당 신뢰 번들에 추가되는 PEM CA 인증서 파일 경로로, MITM CA와 호스트의 일반 루트 뒤에 추가됩니다. 제외(비종료)된 호스트는 샌드박스 내부의 클라이언트가 검증하며, SRT가 설정하는 신뢰 환경 변수(`SSL_CERT_FILE`, `GIT_SSL_CAINFO`, ...)는 각 도구의 자체 신뢰 구성을 _대체_하므로, 사이트 로컬 루트(예: 내부 mTLS CA)는 번들에 포함되어야 하며 그렇지 않으면 해당 호스트는 절대 검증될 수 없습니다. 각 파일의 `CERTIFICATE` 블록만 번들에 복사됩니다(다른 내용, 예: 결합된 PEM의 개인 키는 샌드박스에 절대 노출되지 않음). 누락되었거나, 읽을 수 없거나, PEM `CERTIFICATE` 블록이 없는 파일은 건너뛰므로 일부 호스트에만 존재하는 경로를 나열해도 안전합니다.```json
{
  "network": {
    "allowedDomains": ["*.example.com", "internal-mtls.example.net"],
    "deniedDomains": [],
    "tlsTerminate": {
      "excludeDomains": ["internal-mtls.example.net"],
      "extraCaCertPaths": ["/etc/internal-mtls-roots.pem"]
    }
  }
}

Unix 소켓 설정 (플랫폼별 동작):

설정macOSLinux
allowUnixSockets: string[]소켓 경로 허용 목록무시됨 (seccomp는 경로로 필터링할 수 없음)
allowAllUnixSockets: boolean모든 소켓 허용seccomp 차단 비활성화

Unix 소켓은 두 플랫폼 모두에서 기본적으로 차단됩니다.

  • macOS: allowUnixSockets를 사용하여 특정 경로(예: ["/var/run/docker.sock"])를 허용하거나, allowAllUnixSockets: true를 사용하여 모든 소켓을 허용합니다.
  • Linux: 차단은 seccomp 필터(x64/arm64 전용)를 사용합니다. seccomp를 사용할 수 없으면 소켓이 제한 없이 열리며 경고가 표시됩니다. allowAllUnixSockets: true를 사용하여 차단을 명시적으로 비활성화합니다.

파일시스템 구성

두 가지 서로 다른 패턴을 사용합니다:

읽기 제한 (거부 후 허용 패턴) - 기본적으로 모든 읽기가 허용됨:

  • filesystem.denyRead - 읽기 접근을 거부할 경로 배열. 빈 배열 = 전체 읽기 접근 허용.
  • filesystem.allowRead - 거부된 영역 내에서 읽기 접근을 다시 허용할 경로 배열 (denyRead보다 우선함). 참고: 쓰기의 경우와 반대입니다. 쓰기에서는 denyWriteallowWrite보다 우선합니다.

쓰기 제한 (허용 전용 패턴) - 기본적으로 모든 쓰기가 거부됨:

  • filesystem.allowWrite - 쓰기 접근을 허용할 경로 배열. 빈 배열 = 쓰기 접근 없음.
  • filesystem.denyWrite - 허용된 경로 내에서 쓰기 접근을 거부할 경로 배열 (allowWrite보다 우선함)

경로 구문 (macOS):

macOS에서 경로는 .gitignore 구문과 유사한 git 스타일 glob 패턴을 지원합니다:

  • * - /를 제외한 모든 문자와 일치 (예: *.tsfoo.ts와 일치하지만 foo/bar.ts와는 불일치)
  • ** - /를 포함한 모든 문자와 일치 (예: src/**/*.tssrc/의 모든 .ts 파일과 일치)
  • ? - /를 제외한 단일 문자와 일치 (예: file?.txtfile1.txt와 일치)
  • [abc] - 집합 내의 모든 문자와 일치 (예: file[0-9].txtfile3.txt와 일치)

예시:

  • "allowWrite": ["src/"] - 전체 src/ 디렉터리에 대한 쓰기 허용
  • "allowWrite": ["src/**/*.ts"] - src/ 및 하위 디렉터리의 모든 .ts 파일에 대한 쓰기 허용
  • "denyRead": ["~/.ssh"] - SSH 디렉터리에 대한 읽기 거부
  • "denyRead": ["/Users"], "allowRead": ["."] - /Users 전체에 대한 읽기 거부, 단 현재 디렉터리는 다시 허용
  • "denyWrite": [".env"] - .env 파일에 대한 쓰기 거부 (현재 디렉터리가 허용된 경우에도)

경로 구문 (Linux):

Linux는 현재 glob 매칭을 지원하지 않습니다. 리터럴 경로만 사용하세요:

  • "allowWrite": ["src/"] - src/ 디렉터리에 대한 쓰기 허용
  • "denyRead": ["/home/user/.ssh"] - SSH 디렉터리에 대한 읽기 거부
  • "denyRead": ["/home"], "allowRead": ["."] - /home 전체에 대한 읽기 거부, 단 현재 디렉터리는 다시 허용

모든 플랫폼:

  • 경로는 절대 경로(예: /home/user/.ssh) 또는 현재 작업 디렉터리 기준 상대 경로(예: ./src)일 수 있습니다
  • ~는 사용자의 홈 디렉터리로 확장됩니다

기타 구성

  • ignoreViolations - 위반을 무시해야 하는 경로 배열에 명령 패턴을 매핑하는 객체
  • enableWeakerNestedSandbox - Docker 환경에서 더 약한 샌드박스 모드 활성화 (boolean, 기본값: false)
  • enableWeakerNetworkIsolation - macOS 샌드박스에서 com.apple.trustd.agent에 대한 접근 허용 (boolean, 기본값: false). Go 프로그램(gh, gcloud, terraform, kubectl 등)이 httpProxyPort를 MITM 프록시 및 사용자 지정 CA와 함께 사용할 때 TLS 인증서를 검증하는 데 필요합니다. 보안 경고: 이 기능을 활성화하면 trustd 서비스를 통한 잠재적 데이터 유출 경로가 열립니다.
  • allowAppleEvents - macOS 샌드박스에서 Apple Events 및 Launch Services 열기 요청 전송 허용 (boolean, 기본값: false). 이 기능이 없으면 open, osascript 및 AppleScript를 통해 URL이나 다른 앱의 스크립트를 여는 모든 명령이 AppleScript 오류 -600("Application isn't running") 또는 LaunchServices 오류(-10822, -54)로 실패합니다. 보안 경고: 이 기능을 활성화하면 샌드박스가 더 이상 코드 실행 격리를 제공하지 않습니다. 샌드박스 내 명령은 사용자 프롬프트 없이 open을 통해 다른 애플리케이션을 실행할 수 있으며, 실행된 모든 것은 샌드박스의 파일시스템 및 네트워크 제한 밖에서 실행됩니다. 이미 실행 중인 앱을 Apple Events로 스크립팅하는 것은 추가로 사용자의 앱별 TCC 자동화 동의에 의해 제한됩니다. 임베더는 이 옵션을 신뢰할 수 있는 사용자 수준 구성에서만 가져와야 합니다. 체크아웃된 저장소의 프로젝트 로컬 파일에서 가져오면 안 됩니다. 공격자가 작성한 프로젝트가 자체 샌드박스 권한을 상승시킬 수 있기 때문입니다.

일반적인 구성 레시피

GitHub 접근 허용 (필요한 모든 엔드포인트):```json { "network": { "allowedDomains": [ "github.com", "*.github.com", "lfs.github.com", "api.github.com" ], "deniedDomains": [] }, "filesystem": { "denyRead": [], "allowWrite": ["."], "denyWrite": [] } }

**특정 디렉터리로 제한:**```json
{
  "network": {
    "allowedDomains": [],
    "deniedDomains": []
  },
  "filesystem": {
    "denyRead": ["~/.ssh"],
    "allowWrite": [".", "src/", "test/"],
    "denyWrite": [".env", "secrets/"]
  }
}

작업 영역 전용 파일시스템 접근(작업 영역 외부 읽기 거부):```json { "network": { "allowedDomains": [], "deniedDomains": [] }, "filesystem": { "denyRead": ["/Users"], "allowRead": ["."], "allowWrite": ["."], "denyWrite": [] } }

This denies reading anything under `/Users` (or `/home` on Linux), then re-allows the current working directory. System paths (`/usr`, `/lib`, etc.) remain readable.

### Common Issues and Tips

**Running Jest:** Use `--no-watchman` flag to avoid sandbox violations:```bash
srt "jest --no-watchman"

Watchman은 샌드박스 경계 밖의 파일에 접근하므로 권한 오류가 발생합니다. 이를 비활성화하면 Jest가 내장 파일 감시자를 대신 사용하여 실행될 수 있습니다.

플랫폼 지원

  • macOS: 사용자 지정 프로필과 함께 sandbox-exec 사용 (추가 종속성 없음)
  • Linux: 컨테이너화를 위해 bubblewrap(bwrap) 사용
  • Windows: 알파 — 번들된 srt-win.exe 헬퍼 사용 (추가 종속성 없음). 설정, 보안 모델 및 알려진 제한 사항은 Windows (알파)를 참조하세요.

플랫폼별 종속성

Linux에 필요:

  • bubblewrap - 컨테이너 런타임
    • Ubuntu/Debian: apt-get install bubblewrap
    • Fedora: dnf install bubblewrap
    • Arch: pacman -S bubblewrap
  • socat - 프록시 브리징용 소켓 릴레이
    • Ubuntu/Debian: apt-get install socat
    • Fedora: dnf install socat
    • Arch: pacman -S socat
  • ripgrep - 거부 경로 탐지를 위한 빠른 검색 도구
    • Ubuntu/Debian: apt-get install ripgrep
    • Fedora: dnf install ripgrep
    • Arch: pacman -S ripgrep

Ubuntu 24.04+ 참고: 이 릴리스에서는 기본적으로 kernel.apparmor_restrict_unprivileged_userns가 활성화되어 있어 unshare(CLONE_NEWUSER)는 허용하지만 결과 네임스페이스에서 capabilities를 제거합니다. bubblewrap과 seccomp 격리 계층 모두 capabilities를 보유한 사용자 네임스페이스가 필요합니다. 다음 명령으로 제한을 비활성화하세요:```bash sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0

또는 `userns`를 관련 바이너리에 부여하는 AppArmor 프로필을 추가할 수 있습니다.

**선택적 Linux 종속성(seccomp 폴백용):**

패키지에는 x86-64 및 arm 아키텍처용으로 사전 생성된 seccomp BPF 필터가 포함되어 있습니다. 이러한 종속성은 사전 생성된 필터를 사용할 수 없는 다른 아키텍처를 사용하는 경우에만 필요합니다:

- `gcc` 또는 `clang` - C 컴파일러
- `libseccomp-dev` - Seccomp 라이브러리 개발 파일
  - Ubuntu/Debian: `apt-get install gcc libseccomp-dev`
  - Fedora: `dnf install gcc libseccomp-devel`
  - Arch: `pacman -S gcc libseccomp`

**macOS에는 다음이 필요합니다:**

- `ripgrep` - 거부 경로 감지를 위한 빠른 검색 도구
  - Homebrew로 설치: `brew install ripgrep`
  - 또는 다음에서 다운로드: https://github.com/BurntSushi/ripgrep/releases

**Windows에는 다음이 필요합니다:**

- 추가 종속성 없음. `srt-win.exe` 헬퍼(x64 및 arm64)는 npm 패키지에 번들로 포함되어 있습니다. 일회성 관리자 권한 `windows-install` 단계가 필요합니다 — 아래 참조.

## Windows(알파)

Windows 지원은 **알파** 단계입니다. 샌드박스 프로세스는 전용 `srt-sandbox` 로컬 사용자 계정으로 실행되며, 네이티브 Windows 보안 기본 요소(샌드박스 계정의 SID를 키로 사용하는 WFP(Windows Filtering Platform) 이그레스 펜스, 그리고 구성된 파일 시스템 경로에 대한 해당 SID의 액세스를 허용하거나 거부하는 세션별 명시적 ACE)를 통해 호출 사용자와 격리됩니다.

### 설정

머신당 한 번 실행(자체 승격, UAC 프롬프트 한 번):```powershell
npx @anthropic-ai/sandbox-runtime windows-install

This provisions the srt-sandbox local user account (with a random password stored DPAPI-encrypted in HKLM\SOFTWARE\sandbox-runtime — machine-wide, so fleet installs running as SYSTEM work and one user's rotation updates the copy the others read), the sandbox-runtime-users local group, and installs a machine-wide WFP filter set keyed on the srt-sandbox SID. It is idempotent — re-running it rotates the sandbox account's password and reconciles the filter set.

로그아웃은 필요하지 않습니다. WFP 필터는 전용 샌드박스 계정의 SID를 기준으로 하므로, 사용자 자신의 네트워크, 서비스 및 머신의 다른 모든 주체에는 영향을 미치지 않습니다.

설치 후 SandboxManager.initialize()srt CLI는 다른 플랫폼과 동일하게 작동합니다. initialize()는 샌드박스 계정과 WFP 펜스가 활성 상태인지 확인하며, 그렇지 않은 경우 실행 가능한 오류와 함께 실패합니다.

프로그래매틱 설치/제거는 installWindowsSandbox() / uninstallWindowsSandbox()로 내보내집니다.

보안 모델

샌드박스 명령은 호출 사용자가 아닌 srt-sandbox 계정으로 실행됩니다. 번들된 srt-win.exe 헬퍼는 2홉 실행을 수행합니다: 브로커는 CreateProcessWithLogonW를 호출하여 srt-sandbox로 러너를 시작하고, 러너는 작업 개체 내부의 제한된 토큰으로 대상 프로세스를 생성합니다. 자식 프로세스는 샌드박스 계정의 격리된 프로필(%USERPROFILE%, %TEMP%, HKCU)과 브로커의 PATH 및 생성된 프록시 변수만 덮어쓴 새 환경을 상속합니다.

별도의 사용자 SID로 실행하면 서로게이트 스폰 클래스의 탈출(작업 스케줄러, 브로커 소유 프로세스에 대한 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, BITS, RunAs="Interactive User"를 사용한 프로세스 외 COM)이 구조적으로 차단됩니다: 자식 프로세스가 대역 외로 스폰하는 모든 프로세스는 여전히 srt-sandbox SID를 가지므로 WFP 이그레스 펜스의 적용을 받으며 호출 사용자의 파일에 대한 권한이 없습니다.

네트워크 격리FWPM_LAYER_ALE_AUTH_CONNECT_V4/V6의 2필터 WFP 세트입니다: 구성된 프록시 포트 범위(기본 60080–60089) 내의 루프백 대상에 대한 PERMIT과 srt-sandbox SID를 가진 토큰의 모든 연결에 대한 BLOCK입니다. 샌드박스 프로세스는 해당 범위에서 수신 대기하는 JS HTTP/SOCKS5 프록시를 통해서만 인터넷에 도달합니다. 프록시 환경을 제거하고 직접 연결하는 프로세스는 커널에서 차단됩니다.

파일시스템 격리는 NTFS 임의 액세스 ACL로 강제됩니다. srt-sandbox 계정은 호출 사용자의 파일에 대한 고유 권한이 없으므로 initialize() 시 샌드박스는 srt-sandbox SID에 대해서만 추가적이고 상속되는 명시적 ACE를 작성합니다 — 경로의 기존 보안 설명자를 다시 쓰거나 대체하지 않습니다:

  • filesystem.allowWrite → 상속되는 MODIFY ALLOW ACE(READ|WRITE|EXECUTE|DELETE, FILE_DELETE_CHILD는 제외). 샌드박스 프로세스는 작업 트리 내에서 파일을 생성, 수정 및 삭제할 수 있습니다. 권한 부여에서 FILE_DELETE_CHILD를 제외하는 것은 아래 거부 스탬프에 대한 심층 방어이며, 트리 루트에 대한 보호는 아닙니다.
  • filesystem.allowRead → 상속되는 READ|EXECUTE ALLOW ACE
  • filesystem.denyRead / filesystem.denyWrite → 대상에 대한 상속되는 DENY ACE와 해당 부모에 대한 상속되는 FILE_DELETE_CHILD DENY — 작업 트리 권한에서 제외된 FILE_DELETE_CHILD와 함께, 샌드박스 프로세스가 부모 디렉터리를 통해 거부된 경로를 이름 변경하거나 삭제하지 못하도록 차단합니다

reset()은 이 세션이 추가한 모든 ACE를 제거합니다(사용자별 세션 DB를 통해 이 사용자의 동시 호스트 간에 참조 카운트됨. 다음 initialize() 시 충돌 복구 패스가 비정상 종료 후 정리합니다). 디렉터리 대상이 지원됩니다(ACE는 전체 하위 트리에 상속됨). 글로브 패턴은 initialize() 시점에 구체적인 경로로 확장됩니다 — 나중에 나타나는 일치 경로는 포함되지 않습니다.

Windows에서의 TLS 종료

network.tlsTerminate는 MITM CA가 샌드박스 사용자의 CurrentUser\Root 인증서 저장소에 있어야 합니다(schannel — System32\curl.exe, PowerShell Invoke-WebRequest, .NET 및 기본 백엔드 git이 사용하는 TLS 백엔드 — 환경 변수가 아닌 OS 저장소만 신뢰함). 이는 windows-install과 별개의 설치 시점 단계입니다:```typescript import { windowsTrustCa } from '@anthropic-ai/sandbox-runtime' windowsTrustCa('/path/to/mitm-ca.crt') // or: srt-win user trust-ca

`initialize()`는 세션 CA의 지문을 설치된 지문과 비교하여 불일치 시 실행 가능한 메시지와 함께 실패하므로, 오래된 설치 시점 CA가 샌드박스 내부의 TLS를 조용히 깨뜨릴 수 없습니다.

OpenSSL 기반 클라이언트(msys2 `curl`, `git -c http.sslBackend=openssl`, Node, Python, cargo)는 환경 변수 신뢰 계층으로 보호됩니다. macOS/Linux에서 사용되는 동일한 신뢰 번들이 `NODE_EXTRA_CA_CERTS`, `SSL_CERT_FILE`, `CURL_CA_BUNDLE`, `GIT_SSL_CAINFO`, `CARGO_HTTP_CAINFO` 등을 통해 샌드박스로 전달되며, 번들 경로는 세션의 `allowRead` 권한에 추가되어 샌드박스 계정이 이를 열 수 있습니다.

### Windows 전용 구성

크로스 플랫폼 `filesystem` 및 `network` 블록은 위에서 설명한 대로 적용됩니다. Windows 전용 설정은 `windows` 아래에 있습니다:

- `windows.proxyPortRange` — JS 프록시가 내부에 바인딩하는 `[low, high]` 포함 포트 범위. `windows-install --proxy-port-range`(기본값 `[60080, 60089]`)에 전달된 범위와 **일치해야 합니다** — WFP 루프백 PERMIT는 해당 범위만 허용합니다.
- `windows.sublayerGuid` — 필터가 설치된 WFP 하위 계층 GUID. 컴파일 타임 기본값을 사용하려면 생략하고, 엔터프라이즈 도구가 사용자 지정 하위 계층에 필터를 설치한 경우에만 설정합니다.
- `windows.srtWin.path` — `srt-win` 바이너리 경로. 패키지된 `vendor/srt-win/<arch>/srt-win.exe`를 확인하려면 생략합니다. `srt-win`의 CLI를 멀티콜 바이너리에 포함할 때 설정하며, 스폰 시 `--srt-win`을 `argv[1]`로 전달하여 임베더의 디스패처가 `srt_win::run_from_args`로 라우팅할 수 있게 합니다.

### 알려진 제한 사항

- **schannel에서의 인증서 해지.** CryptoAPI의 CRL/OCSP 가져오기는 호출자의 토큰으로 WinHTTP를 통해 나가며 프록시 환경을 무시하므로 WFP 이그레스 펜스에 의해 차단됩니다. 기본적으로 해지 확인이 켜진 schannel을 사용하는 도구는 도구별로 해지를 비활성화하지 않으면 `CRYPT_E_REVOCATION_OFFLINE`(`0x80092013`)로 실패합니다: `curl --ssl-no-revoke`, `git -c http.schannelCheckRevoke=false`, `CARGO_HTTP_CHECK_REVOKE=false`. `Invoke-WebRequest`, .NET `HttpClient`, `gh`는 기본적으로 해지를 확인하지 않으므로 영향을 받지 않습니다. 루프백 프록시에서 제공되는 CRL 배포 지점이 이 해결 방법을 제거하기 위해 계획되어 있습니다.
- **사용자별 도구 설치에 접근할 수 없습니다.** 샌드박스 프로세스는 사용자가 아닌 `srt-sandbox`로 실행되므로, 사용자 프로필에 설치된 도구(nvm/fnm 관리 Node, 사용자별 `winget`/Scoop 패키지, `pip install --user`, `%LOCALAPPDATA%\Programs\…`)는 상속된 `PATH`에서 확인되지만 샌드박스 계정이 열 수 없습니다. 머신 전체 설치(`Program Files`, `choco`/`winget --scope machine`)를 선호하거나 특정 프로필 경로를 `filesystem.allowRead`에 추가하세요.
- **실행별 `filesystem.allowRead` / `filesystem.allowWrite` 재정의는 지원되지 않습니다.** 세션 수준 `allowRead`/`allowWrite`(`initialize()`에 전달된 구성에서)는 위에서 설명한 대로 작동합니다. `wrapWithSandbox`의 `customConfig`에서 명령별로 전달하면 예외가 발생합니다 — 권한은 `initialize()`에서 `srt-win acl grant`를 통해 세션 전체에 적용되며, `srt-win exec`는 실행별 거부만 노출합니다.
- **`proxyAuthToken`이 러너의 명령줄에 표시됩니다.** 프록시 환경(`HTTP_PROXY=http://srt:<token>@127.0.0.1:…` 포함)은 `srt-win exec`의 argv에서 `--env` 인수로 2홉 러너에 전달되므로, `PROCESS_QUERY_LIMITED_INFORMATION`으로 러너 프로세스를 열 수 있는 모든 로컬 주체가 토큰을 읽을 수 있습니다. 토큰은 샌드박스 프로세스가 루프백 프록시에 인증할 수 있도록 존재하므로 샌드박스 자체에는 비밀이 아닙니다. 단일 사용자 개발 머신에서는 일반적으로 허용되지만, 공유 호스트에서는 프록시 허용 목록이 동일 세션의 다른 주체가 접근할 수 있는 것으로 취급하세요.
- **시스템 리졸버를 통한 DNS 확인은 펜스되지 않습니다.** `getaddrinfo()`는 `NETWORK SERVICE`로 실행되는 `Dnscache` 서비스가 처리하므로, 샌드박스 프로세스의 후속 `connect()`가 차단되더라도 이름 확인은 성공합니다. 자체 UDP/53을 수행하는 도구(`nslookup`, `dig`)는 펜스됩니다. 이는 macOS 동작을 반영합니다.

### 제거```powershell
npx @anthropic-ai/sandbox-runtime windows-uninstall

WFP 필터 세트, srt-sandbox 계정 및 해당 프로필, sandbox-runtime-users 그룹을 제거하고 HKLM\SOFTWARE\sandbox-runtime 키(자격 증명, 마커, CA 레코드)를 제거합니다 — UAC 프롬프트 1회. %ProgramData%\sandbox-runtime(CA 키 자료)은 그대로 남아 있으므로 완전히 정리하려면 수동으로 삭제하세요(사용자별 %LOCALAPPDATA%\sandbox-runtime도 포함).

개발```bash

Install dependencies

npm install

Build the project

npm run build

Run tests

npm test

Type checking

npm run typecheck

Lint code

npm run lint

Format code

npm run format

### Seccomp 바이너리 빌드

BPF 필터와 `apply-seccomp` 로더는 `vendor/seccomp-src/`의 C 소스에서 `npm run build:seccomp`를 통해 컴파일됩니다(Linux 전용, `gcc` 및 `libseccomp-dev` 필요). CI는 각 Linux 아키텍처에서 테스트 전에 이를 실행하며, 릴리스 워크플로는 두 아키텍처를 모두 빌드하여 게시된 패키지에 번들로 포함합니다.

## 구현 세부 사항

### 네트워크 격리 아키텍처

샌드박스는 호스트 머신에서 HTTP 및 SOCKS5 프록시 서버를 실행하여 권한 규칙에 따라 모든 네트워크 요청을 필터링합니다:

1. **HTTP/HTTPS 트래픽**: HTTP 프록시 서버가 요청을 가로채 허용/거부된 도메인에 대해 검증합니다
2. **기타 네트워크 트래픽**: SOCKS5 프록시가 다른 모든 TCP 연결(SSH, 데이터베이스 연결 등)을 처리합니다
3. **권한 적용**: 프록시는 구성의 `permissions` 규칙을 적용합니다

**플랫폼별 프록시 통신:**

- **Linux**: 요청은 Unix 도메인 소켓을 통해 파일시스템으로 라우팅됩니다(`socat`을 사용하여 브리징). 네트워크 네임스페이스는 bubblewrap 컨테이너에서 제거되어 모든 네트워크 트래픽이 반드시 프록시를 통과하도록 보장합니다.

- **macOS**: Seatbelt 프로필은 프록시가 수신 대기하는 특정 localhost 포트로만 통신을 허용합니다. 다른 모든 네트워크 액세스는 차단됩니다.

- **Windows**: WFP `ALE_AUTH_CONNECT` 필터는 구성된 프록시 포트 범위로의 루프백을 제외하고 `srt-sandbox` 계정의 모든 아웃바운드 연결을 차단합니다. 프록시는 해당 범위 내에 바인딩됩니다. 환경 변수(`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, …)는 도구를 프록시로 안내하지만, WFP 필터가 경계 역할을 합니다 — 이를 무시하거나 해제하는 프로세스도 여전히 차단됩니다.

### 파일시스템 격리

파일시스템 제한은 OS 수준에서 적용됩니다:

- **macOS**: 허용된 읽기/쓰기 경로를 지정하는 동적으로 생성된 Seatbelt 프로필과 함께 `sandbox-exec`를 사용합니다
- **Linux**: 바인드 마운트와 함께 `bubblewrap`을 사용하여 구성에 따라 디렉터리를 읽기 전용 또는 읽기-쓰기로 표시합니다
- **Windows**: 구성된 경로에 `srt-sandbox` SID에 대한 추가적 `(OI)(CI)` 명시적 ACE를 작성합니다(`allowRead`/`allowWrite`에는 ALLOW, `denyRead`/`denyWrite`에는 DENY), 그런 다음 `reset()`에서 제거합니다

**기본 파일시스템 권한:**

- **읽기**(거부 후 허용): 기본적으로 모든 곳에서 허용됩니다. 넓은 영역을 거부한 다음 그 안의 특정 경로를 다시 허용할 수 있습니다. `allowRead`는 `denyRead`보다 우선합니다.

  - 예: `denyRead: ["~/.ssh"]` — SSH 키에 대한 액세스 차단
  - 예: `denyRead: ["/Users"], allowRead: ["."]` — 작업 공간을 제외한 `/Users` 전체 차단
  - 빈 `denyRead: []` = 전체 읽기 액세스 허용(거부 없음)

- **쓰기**(허용 전용): 기본적으로 모든 곳에서 거부됩니다. 경로를 명시적으로 허용해야 합니다.
  - 예: `allowWrite: [".", "/tmp"]` — 현재 디렉터리 및 /tmp에 대한 쓰기 허용
  - 빈 `allowWrite: []` = 쓰기 액세스 없음(허용 없음)
  - `denyWrite`는 허용된 경로 내에서 예외를 생성합니다(거부가 우선)

**우선순위는 읽기와 쓰기에 대해 의도적으로 반대입니다:** `allowRead`는 `denyRead`를 재정의하는 반면, `denyWrite`는 `allowWrite`를 재정의합니다. 이를 통해 거부된 영역 내에서 읽기 가능한 영역을, 쓰기 가능한 영역 내에서 보호된 영역을 만들 수 있습니다.

### 필수 거부 경로(자동 보호 파일)

특정 민감한 파일 및 디렉터리는 허용된 쓰기 경로 내에 있더라도 **항상 쓰기가 차단됩니다**. 이는 샌드박스 탈출 및 구성 변조에 대한 심층 방어를 제공합니다.

**항상 차단되는 파일:**

- 셸 구성 파일: `.bashrc`, `.bash_profile`, `.zshrc`, `.zprofile`, `.profile`
- Git 구성 파일: `.gitconfig`, `.gitmodules`
- 기타 민감한 파일: `.ripgreprc`, `.mcp.json`

**항상 차단되는 디렉터리:**

- IDE 디렉터리: `.vscode/`, `.idea/`
- Claude 구성 디렉터리: `.claude/commands/`, `.claude/agents/`
- Git 훅 및 구성: `.git/hooks/`, `.git/config`

이러한 경로는 자동으로 차단됩니다 — `denyWrite`에 추가할 필요가 없습니다. 예를 들어, `allowWrite: ["."]`가 있어도 `.bashrc` 또는 `.git/hooks/pre-commit`에 쓰기는 실패합니다:```bash
$ srt 'echo "malicious" >> .bashrc'
/bin/bash: .bashrc: Operation not permitted

$ srt 'echo "bad" > .git/hooks/pre-commit'
/bin/bash: .git/hooks/pre-commit: Operation not permitted

참고(Linux): Linux에서 필수 거부 경로는 이미 존재하는 파일만 차단합니다. 이러한 패턴에 해당하는 존재하지 않는 파일은 bubblewrap의 바인드 마운트 방식으로는 차단할 수 없습니다. macOS는 glob 패턴을 사용하여 기존 파일과 새 파일 모두를 차단합니다.

Linux 검색 깊이: Linux에서 샌드박스는 ripgrep을 사용하여 허용된 쓰기 경로 내 하위 디렉터리에서 위험한 파일을 검색합니다. 기본적으로 성능을 위해 최대 3단계 깊이까지 검색합니다. 이는 mandatoryDenySearchDepth로 구성할 수 있습니다:```json { "mandatoryDenySearchDepth": 5, "filesystem": { "allowWrite": ["."] } }

- 기본값: `3` (최대 3단계까지 검색)
- 범위: `1` ~ `10`
- 값이 높을수록 더 강력한 보호를 제공하지만 성능은 느려집니다
- CWD(깊이 0)의 파일은 이 설정과 관계없이 항상 보호됩니다

### Unix 소켓 제한 (Linux)

Linux에서 샌드박스는 **seccomp BPF(Berkeley Packet Filter)** 를 사용하여 syscall 수준에서 Unix 도메인 소켓 생성을 차단합니다. 이는 프로세스가 로컬 IPC를 위한 새 Unix 도메인 소켓을 생성하는 것을 방지하는 추가 보안 계층을 제공합니다(명시적으로 허용되지 않는 한).

**작동 방식:**

1. **내장 BPF 필터**: 패키지에는 seccomp BPF 필터가 컴파일된 정적 `apply-seccomp` 바이너리가 x64 및 arm64용으로 포함되어 있습니다. 필터는 아키텍처별로 다르지만 libc와 무관하므로 바이너리는 glibc와 musl 모두에서 작동합니다.

2. **런타임 감지**: 샌드박스는 시스템 아키텍처를 자동으로 감지하고 일치하는 `apply-seccomp` 바이너리를 사용합니다.

3. **Syscall 필터링**: BPF 필터는 `socket()` syscall을 가로채 `EPERM`을 반환하여 `AF_UNIX` 소켓 생성을 차단합니다. 이는 샌드박스 코드가 새 Unix 도메인 소켓을 생성하는 것을 방지합니다.

4. **apply-seccomp 바이너리를 사용한 2단계 적용**:
   - 외부 bwrap이 파일시스템, 네트워크 및 PID 네임스페이스 제한으로 샌드박스를 생성합니다
   - 네트워크 브리징 프로세스(socat)가 샌드박스 내부에서 시작됩니다(Unix 소켓 필요)
   - apply-seccomp가 중첩된 user+PID+mount 네임스페이스를 생성하고 `/proc`을 다시 마운트합니다
   - 중첩된 네임스페이스 내부에서 apply-seccomp는 PID 1(dump 불가능한 init/reaper)로 작동합니다
   - apply-seccomp는 fork하고 `prctl()`을 통해 seccomp 필터를 적용한 다음 사용자 명령을 exec합니다
   - 사용자 명령은 모든 샌드박스 제한과 Unix 소켓 생성 차단이 적용된 상태로 실행됩니다

**PID 네임스페이스 격리**: 중첩된 PID 네임스페이스는 사용자 명령이 seccomp 필터 없이 실행되는 프로세스(bwrap의 init, 셸 래퍼 또는 socat 헬퍼)를 볼 수 없고 접근할 수 없도록 보장합니다. 이는 `kernel.yama.ptrace_scope`와 관계없이 seccomp 경계를 유지하며, 필터링되지 않은 헬퍼가 `ptrace` 또는 `/proc/N/mem`을 통해 도달할 수 없기 때문입니다. 내부 PID 1은 `PR_SET_DUMPABLE=0`을 설정하여 ptrace 대상이 될 수도 없습니다. 중첩 네임스페이스 생성이 실패하면 apply-seccomp는 격리 없이 실행하는 대신 중단합니다.

**보안 제한 사항**: 필터는 `socket(AF_UNIX, ...)` 및 `io_uring_setup`/`io_uring_enter`/`io_uring_register` syscall을 차단합니다(후자의 세 가지는 Linux 5.19+의 `IORING_OP_SOCKET`이 그렇지 않으면 `socket()` 규칙을 우회할 수 있기 때문입니다). 상위 프로세스에서 상속되었거나 `SCM_RIGHTS`를 통해 전달된 Unix 소켓 파일 디스크립터에 대한 작업은 방지하지 않습니다. 대부분의 샌드박싱 시나리오에서 소켓 생성 차단은 무단 IPC를 방지하기에 충분합니다.

**런타임 종속성 없음**: 사전 빌드된 정적 apply-seccomp 바이너리와 사전 생성된 BPF 필터가 x64 및 arm64 아키텍처용으로 포함되어 있습니다. 런타임에 컴파일 도구나 외부 종속성이 필요하지 않습니다.

**아키텍처 지원**: x64 및 arm64는 사전 빌드된 바이너리로 완전히 지원됩니다. 다른 아키텍처는 현재 지원되지 않습니다. 지원되지 않는 아키텍처에서 Unix 소켓 차단 없이 샌드박싱을 사용하려면 구성에서 `allowAllUnixSockets: true`를 설정하세요.

### 위반 감지 및 모니터링

샌드박스 프로세스가 제한된 리소스에 접근을 시도할 때:

1. **운영 체제 수준에서 작업을 차단**합니다(`EPERM` 오류 반환)
2. **위반을 기록**합니다(플랫폼별 메커니즘)
3. **사용자에게 알립니다**(Claude Code에서는 권한 프롬프트가 트리거됨)

**macOS**: 샌드박스 런타임은 macOS의 시스템 샌드박스 위반 로그 저장소에 연결됩니다. 이는 무엇이 시도되었고 왜 차단되었는지에 대한 자세한 정보와 함께 실시간 알림을 제공합니다. 이는 Claude Code가 위반 감지에 사용하는 것과 동일한 메커니즘입니다.```bash
# View sandbox violations in real-time
log stream --predicate 'process == "sandbox-exec"' --style syslog

Linux: Bubblewrap는 내장된 위반 보고 기능을 제공하지 않습니다. strace를 사용하여 시스템 호출을 추적하고 차단된 작업을 식별하세요:```bash

Trace all denied operations

strace -f srt 2>&1 | grep EPERM

Trace specific file operations

strace -f -e trace=open,openat,stat,access srt 2>&1 | grep EPERM

Trace network operations

strace -f -e trace=network srt 2>&1 | grep EPERM

### 고급: 자체 프록시 사용

더 정교한 네트워크 필터링을 위해 샌드박스가 내장 프록시 대신 자체 프록시를 사용하도록 구성할 수 있습니다. 이를 통해 다음이 가능합니다:

- **트래픽 검사**: [mitmproxy](https://mitmproxy.org/)와 같은 도구를 사용하여 트래픽을 검사하고 수정
- **사용자 정의 필터링 로직**: 단순 도메인 허용 목록을 넘어 복잡한 규칙 구현
- **감사 로깅**: 규정 준수 또는 디버깅을 위해 모든 네트워크 요청 기록

**mitmproxy 사용 예시:**```bash
# Start mitmproxy with custom filtering script
mitmproxy -s custom_filter.py --listen-port 8888

참고: 새 구성 형식에서는 사용자 지정 프록시 구성이 아직 지원되지 않습니다. 이 기능은 향후 릴리스에서 추가될 예정입니다.

중요한 보안 고려 사항: 도메인 허용 목록을 사용하더라도 데이터 유출 경로가 존재할 수 있습니다. 예를 들어 github.com을 허용하면 프로세스가 모든 저장소에 푸시할 수 있습니다. 사용자 지정 MITM 프록시와 적절한 인증서 설정을 통해 특정 API 호출을 검사하고 필터링하여 이를 방지할 수 있습니다.

보안 제한 사항

  • 네트워크 샌드박스 제한: 네트워크 필터링 시스템은 프로세스가 연결할 수 있는 도메인을 제한하는 방식으로 작동합니다. 프록시를 통과하는 트래픽을 그 외에는 검사하지 않으므로, 사용자는 정책에서 신뢰할 수 있는 도메인만 허용하도록 해야 합니다.
사용자는 `github.com`과 같은 광범위한 도메인을 허용할 때 데이터 유출이 발생할 수 있는 잠재적 위험을 인지해야 합니다. 또한 경우에 따라 [도메인 프론팅](https://en.wikipedia.org/wiki/Domain_fronting)을 통해 네트워크 필터링을 우회할 수 있습니다.
  • Unix 소켓을 통한 권한 상승: allowUnixSockets 구성은 샌드박스 우회로 이어질 수 있는 강력한 시스템 서비스에 대한 액세스를 의도치 않게 부여할 수 있습니다. 예를 들어, 이를 사용하여 /var/run/docker.sock에 대한 액세스를 허용하면 Docker 소켓을 악용하여 호스트 시스템에 대한 액세스 권한을 사실상 부여하게 됩니다. 사용자는 샌드박스를 통해 허용하는 Unix 소켓을 신중히 고려해야 합니다.
  • 파일 시스템 권한 상승: 지나치게 광범위한 파일 시스템 쓰기 권한은 권한 상승 공격을 가능하게 할 수 있습니다. $PATH에 있는 실행 파일이 포함된 디렉터리, 시스템 구성 디렉터리 또는 사용자 셸 구성 파일(.bashrc, .zshrc)에 대한 쓰기를 허용하면 다른 사용자나 시스템 프로세스가 이러한 파일에 액세스할 때 다른 보안 컨텍스트에서 코드 실행으로 이어질 수 있습니다.
  • Linux 샌드박스 강도: Linux 구현은 강력한 파일 시스템 및 네트워크 격리를 제공하지만, 권한 있는 네임스페이스 없이 Docker 환경 내에서 작동할 수 있게 해주는 enableWeakerNestedSandbox 모드를 포함합니다. 이 옵션은 보안을 상당히 약화시키므로, 다른 방식으로 추가 격리가 적용되는 경우에만 사용해야 합니다.
  • 약한 네트워크 격리(macOS): enableWeakerNetworkIsolation 옵션은 Go 프로그램이 macOS 보안 프레임워크를 통해 TLS 인증서를 검증하는 데 필요한 com.apple.trustd.agent에 대한 액세스를 다시 활성화합니다. 이는 trustd 서비스를 통한 잠재적 데이터 유출 경로를 열 수 있으므로 Go TLS 검증이 필요한 경우(예: MITM 프록시 및 사용자 지정 CA와 함께 httpProxyPort를 사용할 때)에만 활성화해야 합니다.
  • Apple Events(macOS): allowAppleEvents 옵션은 Apple Events 및 Launch Services 열기 요청((allow appleevent-send), (allow lsopen), 그리고 com.apple.coreservices.appleevents, com.apple.CoreServices.coreservicesd, com.apple.coreservices.quarantine-resolver에 대한 mach-lookup) 전송을 다시 활성화하며, open, osascript 및 URL 열기 헬퍼가 필요로 합니다. 이를 허용하면 샌드박스 내 명령이 사용자 프롬프트 없이 임의의 애플리케이션을 실행할 수 있고, 실행된 애플리케이션은 샌드박스 외부에서 완전히 실행됩니다. 따라서 이 옵션은 코드 실행 격리를 약화시키는 것이 아니라 제거합니다. Apple Events를 통해 이미 실행 중인 애플리케이션을 스크립팅하는 것은 macOS TCC 자동화 동의에 의해 추가로 제한되지만, open을 통한 실행은 그렇지 않습니다. 샌드박스 내 명령이 실제로 URL이나 애플리케이션을 열어야 하는 경우에만 이 옵션을 활성화하세요.

알려진 제한 사항 및 향후 작업

Linux 프록시 우회: 현재 환경 변수(HTTP_PROXY, HTTPS_PROXY, ALL_PROXY)를 사용하여 트래픽을 프록시로 전달합니다. 이는 대부분의 애플리케이션에서 작동하지만 이러한 변수를 존중하지 않는 프로그램에서는 무시되어 인터넷에 연결하지 못할 수 있습니다.

향후 개선 사항:

  • Proxychains 지원: Linux에서 LD_PRELOAD와 함께 proxychains 지원을 추가하여 네트워크 호출을 더 낮은 수준에서 가로채 우회를 더 어렵게 만듭니다.

  • Linux 위반 모니터링: 위반 저장소와 통합된 Linux용 자동 strace 기반 위반 감지를 구현합니다. 현재 Linux 사용자는 macOS가 시스템 로그 저장소를 통해 자동 위반 모니터링을 제공하는 것과 달리 위반 사항을 확인하려면 strace를 수동으로 실행해야 합니다.

카테고리