앞선 검증 실험은 서늘한 질문 하나로 끝났다 — 스스로를 고칠 수 있는 시스템에서, 승인은 어디에 있는가. 이번 4a 실습은 그 질문에 대한 교과서적 답, 즉 정책을 에이전트가 만질 수 없는 곳(커널·네트워크 층)에 두는 구조를 직접 확인한 기록이다. 그리고 정직하게도, 그렇게 다 세운 뒤에도 열려 있는 실패 모드 두 개를 눈으로 보는 데서 끝난다. 이 두 구멍이 이 글의 본론이다.

4a 실습 정리 — 4개 메커니즘 실측, 실패 원인 분류, 정책 편집권 격리, 열린 실패 모드 2개, Claude Code 방어층과의 대응

먼저, 세워진 것 — 4중 메커니즘의 실측

샌드박스 안에서 직접 확인한 잠금은 네 겹이다:

  • 프로세스는 non-root(uid 998)로 시작한다.
  • 네트워크 출구는 격리 netns 의 프록시 10.200.0.1:3128 단 하나다.
  • 허용 목록 밖 호스트로의 CONNECT 는 OPA 가 403 으로 자른다.
  • /opt 쓰기는 거부된다 — 정책·바이너리 영역은 읽기 전용.

각 메커니즘(netns/Landlock/seccomp/non-root)이 커널 문서상 무엇을 보는지는 별도 글에서 1차 문서로 되짚었으니, 여기서는 실습에서만 얻을 수 있는 것들에 집중한다.

첫 소득은 의외로 실패 원인의 분류다. 샌드박스 안에서 이것저것 시도하면 전부 “안 된다”로 보이지만, 실은 네 가지 다른 사실이다:

증상 정체
sudo·docker 없음 소프트웨어 부재 — 애초에 안 깔림
apt 가 root 요구 권한 — 깔려 있으나 자격 없음
CONNECT 403 정책 — OPA 가 의도적으로 거부
허용된 호스트의 404 앱 에러 — 정책은 통과, 상대가 없음

이 넷을 구분 못 하면 “샌드박스가 막았다”는 보고 자체가 오염된다. 403 만이 정책의 목소리다.

둘째 소득은 격리의 핵심 설계 확인: 정책 편집권은 샌드박스 밖에만 있다. 에이전트 환경에는 정책 CLI(nemoclaw/openshell) 바이너리 자체가 존재하지 않는다. 앞 실험의 워크스페이스 파일들과 대조적이다 — 파일은 에이전트가 쓸 수 있는 데이터였지만, 정책은 에이전트가 도달할 수 없는 다른 권한 도메인이다. “승인은 어디에 있는가”에 대한 이 아키텍처의 답: 오퍼레이터의 터미널에, 그리고 거기에만.

그래도 열려 있는 실패 모드 ① — 페르소나 변조

커널이 파일시스템 경계를 완벽히 지켜도 못 막는 게 있다. SOUL.md 가 샌드박스 소유로 rw 라는 사실이다. 에이전트는 여전히 자기 규칙 파일을 고칠 수 있다 — 앞 실험에서 MEMORY.md 에 쓰게 했던 것과 정확히 같은 권한으로.

이게 왜 커널 층의 실패가 아니라 설계상 사각인지가 중요하다. Landlock 은 “이 경로에 쓸 수 있는가”를 판정할 뿐, “이 파일이 다음 세션의 시스템 프롬프트가 된다”는 의미론을 모른다. 쓰기 가능한 파일이 곧 상시 지침인 구조에서는, 파일 권한이 곧 자기수정 권한이다. 출력→내일의 지침 루프는 샌드박스를 세운 뒤에도 그대로 열려 있다.

열려 있는 실패 모드 ② — 허용된 채널은 양방향이다

더 근본적인 구멍. 실습 중 pip install 이 성공했다 — 정책이 pypi.org 를 허용하니까. 그런데 다운로드가 되는 채널은 업로드도 되는 채널이다. PyPI 로 바이트를 보낼 수 있다는 뜻이고, 이는 Simon Willison 이 정리한 lethal trifecta — ① 사적 데이터 접근, ② 비신뢰 콘텐츠 노출, ③ 외부 통신(exfiltration) — 의 세 번째 요소가 허용 목록 안에서 이미 성립한다는 뜻이다.1 Willison 의 표현대로 “HTTP 요청을 할 수 있는 도구라면 무엇이든 훔친 정보를 되돌려 보내는 통로가 될 수 있다.”

OPA 정책의 시야가 어디서 끝나는지가 정확한 진단이다: 정책은 “pypi.org 는 허용” 까지만 알고, 그 위로 무엇이 지나가는지는 모른다. 호스트 단위 allowlist 는 목적지를 거르지 페이로드를 거르지 않는다. 탈출구를 다 막았다고 생각한 방에서, 합법적 출입구가 곧 반출구였던 셈이다. 완화하려면 층이 하나 더 필요하다 — 프록시에서의 메서드 제한(GET 만), 내부 미러, 또는 DLP 류의 페이로드 검사 — 그리고 그 각각도 완전하지 않다.

Claude Code 와의 대응 — 두 층은 대체가 아니라 누적

실습 마지막 줄은 이 랩의 구조를 지금 쓰고 있는 Claude Code 세션과 나란히 놓는다. 이 세션에서 에이전트는 curl 을 자유롭게 쳤다(호스트 PC 에는 프록시 allowlist 가 없다). 대신 /etc/shadow 같은 민감 패턴은 하네스 층의 분류기가 막았다. OpenShell 식 구조였다면 순서가 다르다 — 그 명령이 분류기를 통과했더라도 커널·프록시가 EPERM/403 을 냈을 것이다.

같은 위협을 두 시스템이 다른 층에서 막는 것이고, 교훈은 하나다: 두 층은 서로 대체가 아니라 누적이다. 분류기는 의도를 보지만 우회당할 수 있고(패턴을 안 밟으면 통과), 커널은 우회가 어렵지만 의미를 모른다(허용 채널 위의 유출은 통과). 각자의 사각이 정확히 상대의 시야다 — defense in depth 가 표어가 아니라 기하학인 이유다.

정리

4a 가 세운 것: 정책은 에이전트가 도달할 수 없는 권한 도메인에 있고(바이너리 부재), 출구는 하나이며(단일 프록시), 거부는 기계적이다(OPA 403). 4a 가 정직하게 남긴 것: 쓰기 가능한 규칙 파일(페르소나 변조)과 허용 채널의 양방향성(trifecta 의 출구)은 이 층이 못 막는다. 다음 검증은 자연히 “정책 변경은 정말 오퍼레이터만 할 수 있는가”의 실측이다 — VM 터미널에서 policy add github 후 샌드박스에서 api.github.com 이 200 으로 바뀌는지, policy remove 로 원복되는지. 승인의 자리가 어디인지를 이번엔 긍정형으로 보여주는 1분짜리 실험이 될 것이다.


References

관련 시리즈: OpenClaw 워크스페이스 문서들의 역할 · 에이전트 검증 실험 로그 6줄 읽기 · 네 가지 OS 메커니즘, 네 가지 검증 가능한 질문

본문의 관찰 결과(uid 998, 프록시 주소, 403/404 응답, pip 성공, 바이너리 부재)는 본인 샌드박스 실습에서의 실측이다.

  1. Simon Willison, “The lethal trifecta for AI agents: private data, untrusted content, and external communication”, 2025-06-16. https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/