Anthropic Sandbox Runtime (srt)
컨테이너를 요구하지 않고 OS 수준에서 임의의 프로세스에 파일 시스템 및 네트워크 제한을 적용하는 경량 샌드박싱 도구입니다.
srt는 네이티브 OS 샌드박싱 프리미티브(sandbox-exec (macOS), bubblewrap (Linux))와 프록시 기반 네트워크 필터링을 사용합니다. 에이전트, 로컬 MCP 서버, bash 명령어 및 임의의 프로세스의 동작을 샌드박싱하는 데 사용될 수 있습니다.
베타 리서치 프리뷰
샌드박스 런타임은 더 안전한 AI 에이전트를 구현하기 위해 Claude Code를 위해 개발된 연구 미리보기입니다. 이는 광범위한 생태계가 더욱 안전한 에이전트 시스템을 구축할 수 있도록 초기 오픈 소스 미리보기로 제공되고 있습니다. 이것은 초기 연구 미리보기이므로 API 및 구성 형식은 변경될 수 있습니다. AI 에이전트를 기본적으로 더 안전하게 만드는 데 대한 피드백과 기여를 환영합니다!
설치
npm install -g @anthropic-ai/sandbox-runtime
기본 사용법
$ srt "curl anthropic.com"
실행 중: curl anthropic.com
...
개요
이 패키지는 CLI 도구와 라이브러리 모두로 사용될 수 있는 독립적인 샌드박스 구현을 제공합니다. 이 도구는 기본적으로 안전한(secure-by-default) 철학으로 설계되었으며, 일반적인 개발자 사용 사례에 맞춰져 있습니다: 프로세스는 최소한의 접근 권한으로 시작하며, 필요한 구멍만을 명시적으로 뚫게 합니다.
주요 기능:
- 네트워크 제한: HTTP/HTTPS 및 기타 프로토콜을 통해 액세스할 수 있는 호스트/도메인을 제어합니다.
- 파일 시스템 제한: 읽기/쓰기가 가능한 파일/디렉토리를 제어합니다.
- Unix 소켓 제한: 로컬 IPC(Inter-Process Communication) 소켓에 대한 접근을 제어합니다.
- 위반 모니터링: macOS에서는 실시간 경고를 위해 시스템의 샌드박스 위반 로그 저장소에 연결할 수 있습니다.
사용 사례 예시: MCP 서버 샌드박싱
주요 사용 사례 중 하나는 모델 컨텍스트 프로토콜(Model Context Protocol, MCP) 서버를 샌드박싱하여 그 기능을 제한하는 것입니다. 예를 들어, 파일 시스템 MCP 서버를 샌드박스하려면:
샌드박싱 없이 (.mcp.json):
작동 방식 (How It Works)
샌드박스는 OS 레벨 기본 요소(primitives)를 사용하여 전체 프로세스 트리(process tree)에 적용되는 제한을 강제합니다:
- macOS: 동적으로 생성된 Seatbelt 프로파일과 함께
sandbox-exec를 사용합니다.
- Linux: 네트워크 네임스페이스 격리(network namespace isolation)가 적용된 컨테이너화(containerization)를 위해 bubblewrap을 사용합니다.
- Windows: 전용
srt-sandbox 로컬 사용자 계정 아래에서 샌드박싱된 프로세스를 실행하며, 해당 계정의 SID에 키가 지정된 Windows Filtering Platform 이그레스 펜스(egress fence), 쓰기 제한 토큰(write-restricted token), 그리고 작업 트리(working tree)에 대한 명시적 ACE(Access Control Entries)를 사용합니다.
0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305
이중 격리 모델 (Dual Isolation Model)
효과적인 샌드박싱을 위해서는 파일시스템 격리와 네트워크 격리가 모두 필요합니다. 파일 격리가 없으면, 손상된 프로세스가 SSH 키나 기타 민감한 파일을 유출(exfiltrate)할 수 있습니다. 네트워크 격리가 없으면, 프로세스가 샌드박스를 탈출하여 무제한 네트워크 접근 권한을 얻을 수 있습니다.
**파일시스템 격리 (Filesystem Isolation)**는 읽기 및 쓰기 제한을 강제합니다:
-
읽기(Read) (거부 후 허용 패턴, deny-then-allow pattern): 기본적으로 읽기 접근은 모든 곳에서 허용됩니다. 광범위한 영역을 거부하고(예: /Users), 그 안의 특정 경로를 다시 허용할 수 있습니다(예: .). allowRead는 denyRead보다 우선하며, 이는 쓰기(write)와 반대입니다. 쓰기의 경우 denyWrite가 allowWrite보다 우선합니다. allowRead 영역보다 더 구체적인 denyRead 항목(예: denyRead: ["**/.env"] 또는 ["./secrets"]와 함께 allowRead: ["."])은 여전히 거부됩니다.
-
쓰기(Write) (허용만 패턴, allow-only pattern): 기본적으로 쓰기 접근은 모든 곳에서 거부됩니다. 경로를 명시적으로 허용해야 합니다(예: ., /tmp). 허용 목록이 비어 있으면 쓰기 접근 권한이 없습니다.
네트워크 격리(Network Isolation) (허용만 패턴, allow-only pattern): 기본적으로 모든 네트워크 접근은 거부됩니다. 도메인을 명시적으로 허용해야 합니다. allowedDomains 목록이 비어 있으면 네트워크 접근이 없습니다. 네트워크 트래픽은 호스트에서 실행되는 프록시 서버를 통해 라우팅됩니다:
-
Linux: 요청은 파일 시스템을 통해 Unix 도메인 소켓(Unix domain socket)으로 라우팅됩니다. 샌드박스화된 프로세스의 네트워크 네임스페이스(network namespace)는 완전히 제거되므로, 모든 네트워크 트래픽은 호스트에서 실행되는 프록시를 거쳐야 합니다 (샌드박스로 바인드 마운트된 Unix 소켓에 리스닝).
-
macOS: Seatbelt 프로파일은 특정 로컬호스트 포트(localhost port)로만 통신을 허용합니다. 프록시는 이 포트에서 리스닝하며, 모든 네트워크 접근에 대한 제어된 채널을 생성합니다.
-
Windows: 머신 전체에 적용되는 WFP 필터 세트(WFP filter set)는 srt-sandbox 계정으로 실행되는 프로세스가 프록시 포트 범위로 루프백 연결을 하는 경우를 제외한 모든 아웃바운드 연결을 차단합니다. 프록시는 해당 범위 내에서 리스닝하며, 모든 네트워크 접근에 대한 제어된 채널을 생성합니다. 이 필터는 소켓을 생성하기 전에 스레드에 다른 토큰을 설정하는 샌드박스화된 프로세스를 추적하지 않으며, 시스템 서비스가 대신 전송하는 트래픽도 추적하지 않습니다. Windows 알려진 제한 사항를 참조하십시오.
HTTP/HTTPS(HTTP 프록시를 통해) 및 기타 TCP 트래픽(SOCKS5 프록시를 통해)은 이 프록시에 의해 중개되며, 이 프록시는 사용자의 도메인 허용 목록(allowlists)과 차단 목록(denylists)을 강제합니다.
Claude Code에서의 샌드박싱(sandboxing)에 대한 자세한 내용은 다음을 참조하세요:
아키텍처 (Architecture)
src/
├── index.ts # 라이브러리 내보내기(Library exports)
├── cli.ts # CLI 진입점(srt 명령어)
...
사용법 (Usage)
CLI 도구로 사용하기
srt 명령어(Anthropic Sandbox Runtime)는 모든 명령어를 보안 경계(security boundaries)로 감쌉니다:
srt echo "hello world"
...
설정 파일은 선택 사항입니다. ~/.srt-settings.json에 파일이 없으면, srt는 내장 기본값(built-in defaults)으로 실행됩니다: 네트워크 접근 불가, 기본 쓰기 경로 외부 쓰기 불가, 무제한 읽기 허용. 존재하지만 비어 있거나, 읽을 수 없거나, 유효성 검사를 통과하지 못하는 설정 파일은 오류입니다. 이 경우 srt는 단순히 메시지를 출력하고 종료하며, 더 약한 구성(weaker one)으로 폴백(falling back)하지 않습니다. 왜냐하면 폴백할 경우 파일의 denyRead, allowRead, 자격 증명 규칙(credential rules)과 그 외 모든 내용이 손실되기 때문입니다. --settings로 지정된 이름의 파일도 마찬가지로 존재해야 합니다.
명령 실행 중 구성 업데이트하기: --control-fd
--control-fd <fd>는 호출자가 이미 열어둔 디스크립터(descriptor)에서 설정 업데이트를 읽습니다. 이 업데이트는 한 줄에 하나의 JSON 객체 형태로 제공되며, 그 형태는 설정 파일과 동일합니다. 각 줄은 전체 구성을 대체하며 동일한 스키마(schema)로 유효성 검사를 거치므로, 한 줄은 패치(patch)가 아니라 완전한 구성입니다: network와 filesystem이 필수이며, 해당 줄에서 누락된 키는 기본값으로 돌아갑니다.
srt --control-fd 3 -- npm test
명령이 실행된 후 수락된 줄은 무엇을 변경합니까:
네트워크 목록 — network.allowedDomains, deniedDomains (및 deniedDomainReasons), 그리고 deniedResolvedAddresses — 는 모든 플랫폼에서 다음 연결 시점에 적용됩니다: 프록시는 요청마다 이들을 조회하며, resolved-address 확인은 동일한 라인으로부터 재구축됩니다. 또한 network.mitmProxy와 network.tlsTerminate.excludeDomains도 마찬가지로 요청마다 읽힙니다.
credentials.sigv4는 srt가 credentials 블록과 함께 시작된 경우 다음 요청 시점에 적용됩니다: 서명 훅(signing hook)은 이때만 설치되며, 정책을 캡처하는 대신 요청마다 읽습니다.
그 외에는 아무것도 변경되지 않습니다. 파일 시스템 규칙은 이미 seatbelt 프로필, bubblewrap argv 또는 Windows ACEs에 포함되어 있으며, 자격 증명 마스크는 명령이 래핑될 때 구축되었고, 실행 중인 프록시 서버들은 시작 시점에 network.parentProxy와 TLS가 아예 종료되는지 여부를 기록했습니다.
Windows에서 srt는 파일 접근 세트(filesystem.* 및 credentials.files)가 시작 시 적용된 것과 다른 라인을 감지하며, 이는 오직 SRT_DEBUG 환경 변수 하에서만 알립니다: ACL 권한 부여(ACL grant)는 세션 전체에 걸쳐 있으므로 시작 시 적용된 세트가 유지됩니다. 나머지 라인은 위와 같이 적용됩니다.
srt가 채널을 읽고 거부하는 방식:
디스크립터(descriptor)는 3 이상의 정수여야 하며 읽기 가능해야 합니다. 0~2는 표준 스트림(standard stream)입니다. srt가 주어진 디스크립터를 읽을 수 없으면 명령을 실행하는 대신 오류와 함께 종료됩니다. 따라서 살아있는 채널이 죽은 채널로 대체되는 일은 없습니다. 업데이트를 단 하나도 전달하기 전에 죽는 채널은 해당 명령과 함께 다운되고, 그 이후에 죽는 채널은 이를 알리고 마지막으로 적용된 설정(config) 하에서 명령을 계속 실행되도록 남겨둡니다.
유효한 설정(config)이 아닌 줄은 stderr에 보고되고 무시됩니다. 이전 설정이 계속 적용됩니다. 해당 줄 자체는 터미널 대신 디버그 로그(debug log)로 전송되며, 빈 줄은 조용히 무시됩니다.
srt는 샌드박스(sandbox)가 준비된 후에만 읽기를 시작하므로, 그 이전에 작성된 업데이트는 손실되는 대신 채널에 대기하며 — 샌드박스가 시작할 때의 설정으로는 덮어쓰여지지 않습니다. 그러한 줄은 명령이 아직 래핑(wrapping)되는 동안 읽힐 수 있으며, 이때 적용되는 설정과 파일 시스템 규칙(filesystem rules)을 포함합니다. 이처럼 일찍 읽히는지는 래핑에 걸리는 시간에 따라 달라지며 (리눅스에서 대형 트리에 대한 deny glob의 경우 충분히 오래 걸림), 따라서 명령이 시작해야 하는 규칙은 설정 파일(settings file)에 포함되어야 합니다.
srt는 래핑된 명령과 함께 종료되며, 작성자(writer)가 디스크립터를 닫을 때까지 기다리지 않습니다. 입력의 끝(End of input) 역시 오류가 아닙니다. 해당 명령은 마지막으로 적용된 설정 하에서 계속 실행됩니다.
srt에 **전용의 읽기 전용 끝점(dedicated, read-only end)**을 제공하십시오. srt는 파이프(pipe)나 소켓(socket)을 논블로킹 모드(non-blocking mode)로 설정하며, 이 플래그는 열린 파일 디스크립터(open file description)에 존재합니다. 따라서 동일한 디스크립터를 보유하는 다른 모든 것 — 셸의 exec 3<fifo나 부모 프로세스가 계속 사용하는 디스크립터의 pass_fds — 은 그 이후부터 자체 블로킹 읽기(blocking reads)에서 EAGAIN을 받게 됩니다.
macOS와 Linux에서는 샌드박스된 명령이 해당 디스크립터를 받지 못합니다: srt는 해당 슬롯을 명령에 대해 /dev/null로 지정하므로, 샌드박스 내부의 어떤 것도 업데이트를 읽거나 자체 설정을 작성할 수 없습니다.
Windows에서는 해당 명령이 세 가지 표준 스트림만으로 생성되므로, 제어 디스크립터는 전달되는 디스크립터 중 하나가 아닙니다.
외부 결정자(decider)와 함께 독립형 프록시로 사용: srt proxy
srt proxy(또는 bun run build:srt-proxy로 빌드된 단일 파일 srt-proxy 실행 파일)는 워크로드를 다른 곳에서 실행하는 호스트를 위해 SRT의 HTTP 프록시만 실행하며, 격리된 자식 프로세스는 없습니다. 이는 호스트가 전달하는 리스닝 소켓(listening socket)을 받아 모든 CONNECT 요청을 인프로세스(in-process)에서 종료하고, 별도의 결정자 프로세스가 다른 상속된 디스크립터(inherited descriptor)를 통해 접근하여 허용할 때만 요청을 포워딩합니다. 명령줄, 결정자 프로토콜 및 보안 모델에 대한 자세한 내용은 docs/srt-proxy.md를 참조하십시오.
라이브러리로 사용
import {
SandboxManager,
type SandboxRuntimeConfig,
...