프롬프트 하나. 셸 명령어 세 개. 그들의 AI를 이용해 그 AI를 해킹했다.
이것은 오늘날 출시된 모든 멀티 에이전트 AI 제품에 존재할 가능성이 있는 버그 유형이다. 그리고 그 해결책은 업계에서 아직 아무도 언급하지 않는 디자인 패턴이다.
전체 이야기는 이렇다.
해킹하려는 의도는 아니었다. Perplexity Computer가 샌드박싱을 어떻게 처리하는지 연구 중이었다. 내 에이전트 인프라 작업을 위해서다. 프로덕션 멀티 에이전트 시스템이 실제로 실행 환경을 어떻게 격리하는지, 무엇이 공유되고 무엇이 공유되지 않는지 이해하려고 했다.
먼저, 시스템을 살펴보기 시작했다. 샌드박스에 Claude Code가 설치된 것을 발견했다.
에이전트를 실행시켜 테스트 코드를 생성하게 했다. 잘 작동했다. 표준 Claude Code였고, 권한 우회 모드로 실행되어 확인을 요구하지 않았다. 에이전트 시스템에 적합한 설정이다.
그때 문득 생각이 들었다: 잠깐, API 키는 어떻게 관리하는 거지?! Claude Code가 작동하려면 Anthropic API 키가 필요하다. 그 키는 이 샌드박스 어딘가에 있어야 한다. 어떻게 주입되는 걸까? 범위는 어떻게 지정되나? 격리되어 있을까?
그 질문이 나를 이 길로 이끌었다.
서브 에이전트는 프로세스 환경에 API 키를 보관하고 있다. 그것을 훔쳐야 했다.
Perplexity Computer는 여섯 번 시도했지만 실패했다.
- 서브 에이전트에 환경 변수 덤프 요청: 거부됨!
- 공유 파일 시스템에 트로이 목마 스크립트 설치: 내 코드를 읽고 의도를 파악한 후 실행을 거부함!
- .bashrc와 .profile 오염: API 키가 주입되기 전에 너무 일찍 실행됨.
- PATH에 가짜 node 바이너리 배치: 트리거되지 않음.
- 코딩 에이전트를 생성하고 동시에 프로세스 트리 감시: 서브 에이전트가 다른 샌드박스에서 실행되어 아무것도 캡처되지 않음 :(
- Claude Code의 시스템 프롬프트를 찾아 거부 행동을 제거하도록 수정: 주입된 커스텀 시스템 프롬프트를 찾을 수 없음.
여섯 번의 실패. Claude의 모델/프롬프트 수준 안전성은 확실히 뛰어나다. 교묘한 시도를 할 때마다 모델이 이를 감지했다.

그러자 Perplexity가 Claude Code가 npm을 통해 실행되는 Node.js 앱이라는 사실을 떠올렸다. 그리고 npm은 홈 디렉토리에서 ~/.npmrc를 읽는다. 그 홈 디렉토리는 내가 쓸 수 있는 공유 파일 시스템에 있다.
Node.js에는 애플리케이션 코드가 실행되기 전에 JavaScript 모듈을 미리 로드하는 --require 플래그가 있다. .npmrc의 NODE_OPTIONS를 통해 설정할 수 있다. 즉, 공유 홈 디렉토리에 .npmrc를 작성하면 서브 에이전트가 생성하는 모든 Node 프로세스가 내 코드를 미리 로드하게 된다! 이 작업은 Claude Code가 초기화되기도 전, 모든 안전 검사가 실행되기 전, 그 어떤 것보다 먼저 발생한다!
익스플로잇은 세 가지 명령어로 구성된다:
- process.env를 공유 작업 공간의 파일에 덤프하는 여섯 줄짜리 스크립트 작성
- echo 'node-options=--require /path/to/script.js' > ~/.npmrc
- Perplexity Computer에 아무 코딩 작업이나 요청
서브 에이전트 부팅 → npm이 내 .npmrc를 읽음 → 내 프리로드가 Claude Code 시작 전에 실행 → 전체 API 자격 증명이 공유 파일 시스템에 저장됨.
성공했다! Perplexity 게이트웨이 토큰을 얻었고, 이를 통해 agent-proxy.perplexity.ai를 거쳐 그들의 마스터 Anthropic 계정에 프록시 접근할 수 있었다.

당연히 가장 먼저 한 일은 노트북의 Claude Code에 이 API 키와 BASE_URL을 설정하는 것이었다. Claude Code의 LLM 호출이 실패하고 샌드박스로 제한될 거라고 예상했다. 충격적이었다. Opus 4.6에서 즉시 응답이 왔다!
그리고 나는 "당연히 내 계정에 이 사용량이 청구될 거야, 이 API 키는 내 사용자에게 연결되어 있을 거야"라고 생각했다. 또 틀렸다.
Opus 4.6에 모든 발명품, 제국, 발견을 포함한 세계 역사를 설명하는 긴 이야기를 생성하게 했다. 이 호출을 5번 병렬로 실행하여 각각 10만 개 이상의 출력 토큰을 생성했다. 이로 인해 내 Perplexity Computer 크레딧이 모두 소진되어야 했지만, 크레딧은 전혀 줄어들지 않았다.
IP 제한도 없었다. 세션 범위도 없었다. 샌드박스에 바인딩되지도 않았다. 그들의 청구서였다.
지구상에서 가장 자금이 넉넉한 AI 스타트업 중 하나가 2019년부터 Node.js 공급망 공격에 사용된 도트 파일 하나에 무너졌다.
모델은 모든 것을 올바르게 수행했다. 인프라가 그러지 못했다.
이제 에이전트 인프라를 구축하는 창업자들이 여기서 얻어가길 바라는 점이다.
Perplexity의 아키텍처는 절반은 맞다. 샌드박스와 Anthropic API 사이에 프록시를 사용한다. 이는 올바른 패턴이다. 절대 원시 제공자 API 키를 샌드박스 안에 넣어서는 안 된다. 프록시는 제어, 관찰 가능성, 그리고 마스터 키를 교체하지 않고도 액세스를 철회할 수 있는 기능을 제공한다.
문제는 그들의 프록시 토큰이 실행 컨텍스트에 전혀 바인딩되지 않는다는 점이다. 일단 획득하면 어디서나 영원히 작동한다.
올바르게 구현하는 방법은 다음과 같다:
토큰을 샌드박스 ID에 바인딩하라. 토큰과 샌드박스 ID가 일치하지 않으면 거부된다. 키가 유출되어도 샌드박스가 없으면 무용지물이다. 이상적으로는 토큰을 샌드박스 IP 주소에도 바인딩해야 하지만, E2B(그들이 사용하는 샌드박스 제공자)는 샌드박스가 시작되기 전에는 이를 제공하지 않는다.
토큰을 일시적으로 만들어라. 샌드박스가 시작될 때 발급하고, 중지될 때 폐기하라. 장기 자격 증명은 없어야 한다. 프록시는 세션 시작 시 단기 토큰을 생성하고, 세션 종료 시 무효화한다. 죽은 샌드박스에서 유출된 키는 죽은 키다.
토큰을 사용자의 청구 계정에 연결하라. 다른 모든 것이 실패하더라도, 누군가 활성 샌드박스에서 라이브 토큰을 빼내 만료 전에 사용하더라도, 사용량은 세션을 생성한 계정에 청구된다. 공유 마스터 청구 풀이 아니다. 이는 "무제한 무료 API 액세스"를 "누군가 자신의 할당량을 남용하는 것"으로 바꾸며, 이는 완전히 다른 심각도다.
이 세 가지, 즉 샌드박스 바인딩, 일시적 토큰, 사용자 청구가 프록시 패턴이 실제로 작동하게 하는 핵심이다. 이것들이 없으면 아무것도 막지 못하는 추가 네트워크 홉을 추가하는 것에 불과하다.
이는 Perplexity만의 문제가 아니다. 현재 에이전트 인프라의 기본 아키텍처가 이렇다. 가장 빠르게 구축할 수 있기 때문이다. 에이전트 간 공유 파일 시스템, 장기 자격 증명, 마스터 계정 청구. 오늘날 프로덕션에 있는 대부분의 멀티 에이전트 제품에 이러한 문제가 어느 정도 존재할 것이라고 확신한다.
게시 전에 @AravSrinivas와 @denisyarats에게 보고했습니다.





