업데이트로 돌아가기
New releaseAug 8, 2026

sandbox-runtime v0.0.71

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

공유

Anthropic Sandbox Runtime (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 Filtering Platform 송신 펜스와 작업 트리에 대한 세션별 명시적 ACE를 사용합니다.

0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305

이중 격리 모델

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

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

  • 읽기 (거부 후 허용 패턴): 기본적으로 읽기 액세스는 모든 곳에서 허용됩니다. 넓은 영역(예: /Users)을 거부한 다음 그 안의 특정 경로(예: .)를 다시 허용할 수 있습니다. allowReaddenyRead보다 우선합니다 — 이는 쓰기의 반대로, 쓰기에서는 denyWriteallowWrite보다 우선합니다.
  • 쓰기 (허용 전용 패턴): 기본적으로 쓰기 액세스는 모든 곳에서 거부됩니다. 경로(예: ., /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 이벤트, 프록시 거부)은 귀속 키(attribution key) 아래에 저장되며, `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` 접미사를 사용하며, 전체 거부(deny-all)를 위해 단독 `*`(또는 `*:22`)도 허용됩니다.
- `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` - 로컬 포트 바인딩 허용(boolean, 기본값: false)

**TLS 종료**(`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) 클라이언트** - 업스트림의 신원을 자체적으로 검증하고(사용자 정의 CA, SAN 고정) MITM 인증서를 거부하는 클라이언트.
- `network.tlsTerminate.extraCaCertPaths` - MITM CA와 호스트의 일반 루트 다음으로 해당 신뢰 번들에 추가되는 PEM 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 Socket 설정 (플랫폼별 동작):

설정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). MITM 프록시 및 사용자 지정 CA와 함께 httpProxyPort를 사용할 때 Go 프로그램(gh, gcloud, terraform, kubectl 등)이 TLS 인증서를 검증하는 데 필요합니다. 보안 경고: 이 기능을 활성화하면 trustd 서비스를 통한 잠재적 데이터 유출 경로가 열릴 수 있습니다.
  • allowAppleEvents - macOS 샌드박스에서 Apple Events 및 Launch Services 열기 요청을 보낼 수 있도록 허용합니다 (boolean, 기본값: false). 이 옵션이 없으면 open, osascript 및 URL을 열거나 AppleScript를 통해 다른 앱을 스크립팅하는 모든 명령이 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": [] } }

이는 `/Users` (또는 Linux의 `/home`) 아래의 모든 읽기를 차단한 다음 현재 작업 디렉터리를 다시 허용합니다. 시스템 경로(`/usr`, `/lib` 등)는 계속 읽을 수 있습니다.

### 일반적인 문제 및 팁

**Jest 실행:** 샌드박스 위반을 방지하려면 `--no-watchman` 플래그를 사용하세요:```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

이 작업은 srt-sandbox 로컬 사용자 계정(%LOCALAPPDATA%\sandbox-runtime\state.db 아래에 DPAPI로 암호화되어 저장되는 임의 비밀번호 사용), sandbox-runtime-users 로컬 그룹을 프로비저닝하고, srt-sandbox SID를 기준으로 하는 머신 전체 WFP 필터 세트를 설치합니다. 멱등적(idempotent) 입니다. 다시 실행하면 샌드박스 계정의 비밀번호가 순환되고 필터 세트가 조정됩니다.

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

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

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

보안 모델

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

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

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

파일 시스템 격리는 NTFS DACL(임의 액세스 제어 목록)로 적용됩니다. 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를 제거합니다(state.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와 비교하여 불일치 시 조치 가능한 메시지와 함께 실패합니다. 따라서 설치 시점의 오래된 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를 멀티콜 바이너리에 포함할 때 설정하세요. 이 경우 spawn 시 `--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`는 실행별 거부(deny)만 노출합니다.
- **`proxyAuthToken`은 러너의 명령줄에서 볼 수 있습니다.** 프록시 환경(`HTTP_PROXY=http://srt:<token>@127.0.0.1:…` 포함)은 `srt-win exec`의 argv에서 `--env` 인수로 two-hop 러너에 전달되므로, 러너 프로세스를 `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 그룹을 제거하고 state.db에서 자격 증명/설정 마커를 지웁니다(UAC 프롬프트 1회). %LOCALAPPDATA%\sandbox-runtime\state.db 자체는 그대로 유지됩니다(브로커 전용으로 ACL이 설정되어 있음). 완전히 정리하려면 디렉터리를 수동으로 삭제하세요.

개발```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의 bind-mount 방식으로는 차단할 수 없습니다. 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 필터가 컴파일된 x64 및 arm64용 정적 `apply-seccomp` 바이너리가 포함되어 있습니다. 필터는 아키텍처별로 다르지만 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(덤프 불가능한 init/reaper)로 동작합니다
   - apply-seccomp는 fork한 후 `prctl()`을 통해 seccomp 필터를 적용하고 사용자 명령을 exec합니다
   - 사용자 명령은 모든 샌드박스 제한과 Unix 소켓 생성 차단이 적용된 상태로 실행됩니다

**PID 네임스페이스 격리**: 중첩 PID 네임스페이스는 사용자 명령이 seccomp 필터 없이 실행되는 프로세스(bwrap의 init, 셸 래퍼, socat 헬퍼)를 볼 수 없고 주소 지정도 할 수 없도록 보장합니다. 필터링되지 않은 헬퍼는 `ptrace`나 `/proc/N/mem`을 통해 접근할 수 없으므로 `kernel.yama.ptrace_scope`와 관계없이 seccomp 경계가 그대로 유지됩니다. 내부 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. OS 수준에서 **작업을 차단**합니다(`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에 대한 액세스를 허용하는 데 사용되면 도커 소켓을 악용하여 사실상 호스트 시스템에 대한 액세스 권한을 부여하게 됩니다. 사용자는 샌드박스를 통해 허용하는 Unix 소켓을 신중히 검토하는 것이 좋습니다.
  • 파일 시스템 권한 상승: 지나치게 광범위한 파일 시스템 쓰기 권한은 권한 상승 공격을 가능하게 할 수 있습니다. $PATH에 있는 실행 파일이 포함된 디렉터리, 시스템 구성 디렉터리 또는 사용자 셸 구성 파일(.bashrc, .zshrc)에 대한 쓰기를 허용하면 다른 사용자나 시스템 프로세스가 이러한 파일에 액세스할 때 다른 보안 컨텍스트에서 코드 실행으로 이어질 수 있습니다.
  • Linux 샌드박스 강도: Linux 구현은 강력한 파일 시스템 및 네트워크 격리를 제공하지만, 권한 있는 네임스페이스 없이 Docker 환경 내에서 작동할 수 있게 해주는 enableWeakerNestedSandbox 모드를 포함합니다. 이 옵션은 보안을 상당히 약화시키므로, 다른 방식으로 추가 격리가 적용되는 경우에만 사용해야 합니다.
  • 약한 네트워크 격리(macOS): enableWeakerNetworkIsolation 옵션은 Go 프로그램이 macOS Security 프레임워크를 통해 TLS 인증서를 검증하는 데 필요한 com.apple.trustd.agent에 대한 액세스를 다시 활성화합니다. 이는 trustd 서비스를 통한 잠재적 데이터 유출 경로를 열 수 있으므로 Go TLS 검증이 필요한 경우에만 활성화해야 합니다(예: MITM 프록시 및 사용자 지정 CA와 함께 httpProxyPort를 사용하는 경우).
  • Apple Events(macOS): allowAppleEvents 옵션은 open, osascript 및 URL 열기 헬퍼가 필요로 하는 Apple Events 및 Launch Services 열기 요청 전송((allow appleevent-send), (allow lsopen), 그리고 com.apple.coreservices.appleevents, com.apple.CoreServices.coreservicesd, com.apple.coreservices.quarantine-resolver에 대한 mach-lookup)을 다시 활성화합니다. 이것이 허용되면 샌드박스 내 명령이 사용자 프롬프트 없이 임의의 애플리케이션을 실행할 수 있으며, 실행된 애플리케이션은 완전히 샌드박스 외부에서 실행됩니다. 따라서 이 옵션은 코드 실행 격리를 약화시키는 것이 아니라 제거합니다. 이미 실행 중인 애플리케이션을 Apple Events로 스크립팅하는 것은 macOS TCC 자동화 동의에 의해 추가로 제한되지만, open을 통한 실행은 그렇지 않습니다. 샌드박스 내 명령이 실제로 URL이나 애플리케이션을 열어야 하는 경우에만 이 기능을 활성화하세요.

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

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

향후 개선 사항:

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

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

카테고리