본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 27. 13:23

BoxAgnts 소개 (3) — WebAssembly 샌드박스

요약

AI 에이전트의 실행 권한 오남용 문제를 해결하기 위해 WebAssembly(Wasmtime) 기반의 보안 샌드박스를 활용하는 BoxAgnts를 소개합니다. WASM의 명령어 수준 격리를 통해 파일 시스템과 네트워크 액세스를 세밀하게 제어하여 안전한 에이전트 실행 환경을 구축합니다.

핵심 포인트

  • Wasmtime 런타임을 활용한 밀리초 단위의 빠른 샌드박스 실행
  • WASI preopen 메커니즘을 통한 엄격한 파일 시스템 격리
  • 와일드카드 패턴 매칭을 이용한 네트워크 화이트리스트 제어
  • 프롬프트 인젝션 및 악성 명령어로 인한 시스템 피해 방지

AI 에이전트가 파일 읽기/쓰기, Shell 실행, 네트워크 액세스 권한을 가질 때, 해를 끼치지 않을 것이라고 누가 보장할 수 있을까요?

이 문제의 심각성은 과소평가되어서는 안 됩니다. 전통적인 아키텍처(Architecture)에서 AI 도구는 사용자와 동일한 시스템 권한을 가지고 호스트 머신에서 직접 실행됩니다. 이는 다음을 의미합니다:

  • 프롬프트 인젝션 (Prompt injection)이 악의적인 파일 수정을 초래할 수 있음
  • 잘못된 Shell 명령어가 중요한 데이터를 삭제할 수 있음
  • 탈취된 네트워크 요청이 민감한 정보를 유출할 수 있음

BoxAgnts의 해답은 최하단 레이어인 **WASM 보안 샌드박스 (Sandbox)**에 있습니다. 이것은 선택적인 "보안 강화"가 아니라, 전체 시스템의 신뢰 기반입니다.

왜 WebAssembly인가?

수많은 샌드박스 기술 중에서 BoxAgnts는 수십억 개의 브라우저를 통해 검증된 성숙한 기술인 WebAssembly를 선택했습니다.

비교 항목Docker 컨테이너 (Container)VM 가상 머신 (Virtual Machine)WebAssembly (Wasmtime)
시작 속도초 단위분 단위밀리초 (Milliseconds) 단위
...

WASM의 명령어 수준 격리 (Instruction-level isolation)는 모든 메모리 액세스 명령어가 샌드박스 경계 내에서 검증됨을 의미합니다. 이는 사후 점검이 아니라, 실행 중 하드웨어 지원을 받는 경계 검사 (Bounds checking)입니다. BoxAgnts는 현재 사용 가능한 가장 성숙하고 성능이 뛰어난 WASM 런타임 중 하나인 Bytecode Alliance의 Wasmtime을 런타임 엔진으로 선택했습니다.

RunOption: 샌드박스의 세밀한 제어 패널

BoxAgnts의 샌드박스 설정은 단순한 "켜기" 또는 "끄기"가 아닙니다. 이는 11차원 제어 패널과 같습니다:

pub struct RunOption {
    pub work_dir: Option<String>,              // 호스트 디렉토리 → 게스트 루트 디렉토리 매핑
    pub map_dirs: Option<Vec<(String, String)>>, // 다중 디렉토리 매핑
...

각 차원의 보안적 함의

1. work_dir + map_dirs: 파일 시스템 격리 (Filesystem Isolation)

WASM 컴포넌트는 호스트 파일 시스템 (Filesystem)에 직접 접근할 수 있는 능력이 없습니다. 모든 파일 작업은 WASI의 preopen 메커니즘을 통해 이루어져야 하며, 호스트 디렉토리가 게스트의 가상 파일 시스템 루트에 매핑됩니다. 이는 다음을 의미합니다:

  • WASM 코드는 명시적으로 매핑된 디렉토리만 볼 수 있습니다.
  • 민감한 시스템 경로 (예: /etc/passwd, C:\Windows\System32)는 자연스럽게 보이지 않습니다.
  • 다중 디렉토리 매핑 (Multi-directory mapping)을 통해 더 복잡한 시나리오를 지원합니다 (예: 공유 라이브러리 디렉토리와 프로젝트 디렉토리 분리).

2. allowed_outbound_hosts: 네트워크 액세스 화이트리스트 (Network Access Whitelist)

이는 가장 중요한 보안 제어 중 하나입니다. 와일드카드 패턴 매칭 (Wildcard pattern matching)을 사용합니다:

"https://*"           → 모든 HTTPS 연결 허용
"https://*.github.com" → *.github.com 서브도메인만 허용
"*://localhost:*"     → 모든 프로토콜에 대해 모든 포트의 localhost 허용

WASM 컴포넌트가 네트워크 연결을 시도할 때마다 socket_addr_check()가 다음을 검증합니다:

pub async fn socket_addr_check(
    addr: SocketAddr,
    addr_use: SocketAddrUse,
...

TCP Bind 및 UDP Bind는 직접 거부됩니다. 즉, 컴포넌트는 외부 연결을 시작할 수만 있을 뿐, 포트에서 대기 (Listen)할 수는 없습니다.

3. block_networks: IP 블랙리스트 (IP Blacklist)

호스트 이름 화이트리스트 (Hostname whitelisting) 외에도 IP 네트워크 범위 블랙리스트가 지원됩니다:

--block-network 10.0.0.0/8       # Class A 사설 네트워크 차단
--block-network 192.168.0.0/16   # Class C 사설 네트워크 차단
--block-network private           # 모든 사설 네트워크 차단

block_networksip_network 크레이트 (Crate)를 사용하여 정밀한 IP 범위 매칭을 수행하며, private 키워드에 대한 특별한 처리를 포함합니다. 이는 RFC 1918의 세 가지 사설 네트워크 범위인 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16을 차단합니다.

4. wasm_timeout: 엄격한 실행 시간 제한 (Hard Execution Time Limit)

WASM 코드가 무한 루프에 진입하거나 악의적으로 CPU를 점유하는 경우, 타임아웃 (timeout) 메커니즘이 지정된 초(seconds)가 지난 후 실행을 강제로 종료합니다. Wasmtime의 에포크 기반 중단 (epoch-based interruption) 메커니즘은 신뢰성을 보장합니다. 이는 외부에서 타임아웃을 위해 "기다리는" 것이 아니라, WASM 실행 엔진 내부에서 주기적으로 확인하는 방식입니다.

5. wasm_max_memory_size + wasm_max_wasm_stack: 엄격한 메모리 제한 (Hard Memory Limits)

악의적이거나 버그가 있는 WASM 컴포넌트가 무제한적인 메모리 증가를 통해 호스트 리소스를 고갈시키는 것을 방지합니다. 선형 메모리 (linear memory) 증가 요청이 제한을 초과하면 memory.grow 명령어가 -1을 반환하여, 컴포넌트가 OOM (Out Of Memory)을 일으키는 대신 우아하게 실패(fail gracefully)할 수 있도록 합니다.

6. wasm_fuel: 명령 단위 실행 예산 (Instruction-Level Execution Budget)

이것은 WASM의 독특한 보안 기능인 "연료 계측 (fuel metering)"입니다. 각 WASM 명령은 1 단위의 연료를 소비합니다 (일부 제어 흐름 명령은 0을 소비함). 연료가 소진되면 실행이 즉시 종료됩니다. 이는 타임아웃보다 더 정밀한 실행 제어를 제공하여 알고리즘 복잡도 공격 (algorithmic complexity attacks)을 방지합니다.

7. wasm_cache_dir: 성능과 보안의 균형

사전 컴파일된 .cwasm 파일 캐싱을 통해 매 실행 시마다 WASM 모듈을 다시 컴파일하는 것을 방지합니다. 이는 성능 최적화인 동시에 보안 강화이기도 합니다. 사전 컴파일된 모듈은 이미 Wasmtime의 검증 (validation)을 통과했으므로 재검증이 필요하지 않기 때문입니다.

WasmTool: 두 세계를 잇는 가교

wasm_tool.rs에 정의된 WasmTool은 중간 계층인 Tool 트레이트 (trait)와 하위 계층인 WASM 실행을 연결하는 핵심적인 가교 역할을 합니다:

pub struct WasmTool {
    name: String,                 // 도구 이름 ("read", "write", "bash"...)
    wasm_file: String,            // .wasm 파일명
...

JSON stdin/stdout 인터페이스 패턴

BoxAgnts의 WASM 컴포넌트들은 깔끔하고 실용적인 인터페이스 패턴인 JSON stdin/stdout 방식을 채택합니다:

WASM Component
    stdin  ← JSON 파라미터 (예: {"file_path":"/src/main.rs","limit":50})
    stdout → JSON 결과 (예: {"content":"...","is_error":false})
...

이 설계의 장점:

  1. 디버깅 용이성 (Easy to debug): echo '{}' | wasmtime run tool.wasm 명령어로 직접 테스트할 수 있습니다.
  2. 언어 불가지론 (Language agnostic): stdin/stdout을 읽고 쓸 수 있는 모든 언어로 WASM 컴포넌트를 작성할 수 있습니다.
  3. 하위 호환성 (Backward compatible): 필드를 추가하더라도 기존 컴포넌트가 중단되지 않습니다.

WASI: 표준화된 시스템 인터페이스 (Standardized System Interface)

WASM 자체는 계산 모델 (Computation model)일 뿐입니다. WASM 코드가 파일 시스템과 네트워크에 접근하려면 WASI (WebAssembly System Interface)가 필요합니다. BoxAgnts의 샌드박스는 WASI를 통해 제어된 시스템 접근을 구현합니다:

파일 시스템 접근: preopen 메커니즘

호스트 파일 시스템 (Host Filesystem)           WASM 게스트 뷰 (WASM Guest View)
─────────────────                    ────────────────
/home/user/workspace/     ──map──→   /
...

WASM 코드의 fopen("/etc/passwd") 호출은 WASI 레이어에 의해 가로채집니다. /etc/가 호스트의 어떤 디렉토리와도 매핑되어 있지 않기 때문에, 이 호출은 즉시 실패합니다.

네트워크 접근: socket_addr_check

WASM 코드가 네트워크 연결을 시도할 때마다 보안 검사가 트리거됩니다:

// 1. TCP Bind → 즉시 거부됨 (컴포넌트는 포트에서 리스닝해서는 안 됨)
SocketAddrUse::TcpBind => {
    eprintln!("Deny TCP bind: {}", addr);
...

연결이 거부되면 시스템은 명확한 로그 메시지를 출력합니다:

A component tried to make an outbound network connection to
disallowed destination 'http://internal-server:8080'.
To allow this request, add 'http://internal-server:8080' to
...

3계층 방어 시스템 전체 구성

위의 메커니즘들을 결합하여, BoxAgnts의 샌드박스는 3계층 심층 방어 (Defense-in-depth) 시스템을 형성합니다:

                        도구 실행 요청 (Request to Execute Tool)
                              │
        ┌─────────────────────┼─────────────────────┐
...

1계층: 리소스 제한 (Resource Limits)

WASM 런타임은 모듈을 로드할 때 엄격한 리소스 경계(resource boundaries)를 설정합니다:

  • 메모리 상한 (Memory ceiling): wasm_max_memory_size
  • 스택 상한 (Stack ceiling): wasm_max_wasm_stack
  • 실행 시간 (Execution time): wasm_timeout
  • 명령어 예산 (Instruction budget): wasm_fuel

이러한 제한 사항은 Wasmtime 엔진 수준에서 보장됩니다. 제한 사항이 WASM 가상 머신(virtual machine)의 실행 루프(execution loop)에 인코딩되어 있기 때문에 컴포넌트 코드는 이를 우회할 수 없습니다.

2계층: WASI 파일 시스템 인터셉션 (WASI Filesystem Interception)

파일 시스템 접근은 WASI 프리오픈 (preopen) 메커니즘을 통해 가상화됩니다. 주요 보호 기능은 다음과 같습니다:

  • 컴포넌트는 명시적으로 매핑된 디렉토리만 "볼" 수 있습니다.
  • 경로 탐색 공격 (Path traversal attacks, ../../etc/passwd)은 WASI 계층에서 차단됩니다.
  • 심볼릭 링크 (Symbolic link) 추적은 매핑된 디렉토리 범위로 제한됩니다.

3계층: 네트워크 제어 (Network Control)

네트워크 접근은 이중 필터링을 거칩니다:

  1. 호스트 이름 화이트리스트 (Hostname whitelist, 와일드카드 매칭)
  2. IP 네트워크 범위 블랙리스트 (IP network range blacklist, CIDR 매칭 + "private" 키워드)

두 필터는 AND 관계로 작동합니다. 즉, 대상은 화이트리스트 검사를 통과하는 동시에 블랙리스트에 의해 차단되지 않아야 합니다.

Wasmtime HTTP: 샌드박스 내부의 HTTP 클라이언트

wasmtime_http/ 모듈은 WASM 컴포넌트를 위한 제한된 HTTP 클라이언트를 제공합니다:

// wasmtime_http/src/handler.rs
// WASM 컴포넌트로부터의 HTTP 요청을 인터셉트합니다.
// allowed_outbound_hosts를 확인합니다.
...

핵심 설계 결정 사항: WASM 컴포넌트는 호스트 운영체제(OS)의 네트워크 스택을 직접 사용하지 않습니다. 모든 HTTP 요청은 BoxAgnts의 프록시 계층(proxy layer)을 통과하며, 이를 통해 다음을 보장합니다:

  1. 모든 요청이 화이트리스트 검증을 통과함
  2. 요청/응답을 기록(log)하고 감사(audit)할 수 있음
  3. 악성 URL 패턴을 차단할 수 있음 (block_url 파라미터를 통해)

스킬 시스템 (Skill System): 샌드박스 내의 지능형 확장 기능

7개의 WASM 도구 컴포넌트 외에도, BoxAgnts는 스킬 시스템을 통해 샌드박스 내에서 특화된 AI 스킬을 실행하는 것을 지원합니다. 5개의 스킬이 사전 설치되어 있습니다:

스킬 (Skill)기능 (Function)설정 파일 (Config File)
code-review코드 리뷰 및 분석skills/code-review/SKILL.md
...

스킬 작동 방식 (How Skills Work)

스킬의 핵심은 SKILL.md 파일입니다. 이는 스킬의 특화된 프롬프트 (Prompt)를 Markdown 형식으로 기술한 설명서입니다. SkillTool이 호출되면 다음과 같은 과정을 거칩니다:

  1. 대상 스킬의 SKILL.md 파일을 읽습니다.
  2. 해당 대화 차례 (Conversation turn)의 시스템 프롬프트 (System prompt)로 이를 주입합니다.
  3. AI는 해당 역할 내에서 작업을 완료하기 위해 기반 도구 (Underlying tools)들을 사용합니다.

새로운 스킬을 만드는 비용은 매우 낮습니다. Markdown 설명 파일만 작성하면 되며

성능 고려 사항: 샌드박스(Sandbox)가 곧 느림을 의미하지는 않습니다

샌드박스 기술에 대한 많은 사람들의 첫 번째 반응은 "느려지지 않을까요?"입니다. BoxAgnts는 실제 아키텍처를 통해 이에 대한 해답을 제시합니다.

컴파일 최적화: Cranelift JIT

Wasmtime은 Cranelift 컴파일러를 사용하여 WASM 바이트코드(bytecode)를 대상 플랫폼을 위한 머신 코드(machine code)로 컴파일합니다. 최고 수준의 최적화 단계는 아니지만 (그것은 LLVM의 영역입니다), Cranelift의 컴파일 속도는 매우 빨라 JIT (Just-In-Time) 시나리오에 적합합니다.

사전 컴파일 캐시 (Precompilation Cache)

compiler.rs.wasm 파일을 .cwasm (Compiled WASM)으로 사전 컴파일하고 이를 캐싱하는 기능을 지원합니다:

// compiler.rs
// 처음 로드 시 .wasm → 컴파일 → .cwasm으로 캐싱
// 이후 로드 시 → .cwasm을 직접 사용 → 컴파일 건너뜀

이는 도구를 처음 사용할 때 약간의 컴파일 오버헤드(밀리초 단위)가 발생하지만, 이후 사용 시에는 네이티브 코드(native code)의 시작 속도와 거의 동일함을 의미합니다.

제로 카피 데이터 전송 (Zero-Copy Data Transfer)

호스트(host)와 WASM 사이의 stdin/stdout을 통한 데이터 전송은 가능한 한 제로 카피 (zero-copy) 최적화를 사용합니다. 일반적인 AI 에이전트 (AI Agent) 워크로드(파일 읽기/쓰기, 웹 요청, 명령줄 출력)의 경우, 샌드박스 오버헤드는 I/O 오버헤드 자체보다 훨씬 낮기 때문에 그 존재를 거의 느낄 수 없습니다.

요약

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0