2026년 10월 22일, Forever Security는 모든 코딩 에이전트를 운영하는 팀이 문자 그대로 받아들여야 할 제목의 연구 결과를 발표했습니다: "Markdown Is the New Executable." 이들의 소프트웨어는 실제 고객의 장치에서 코딩 에이전트가 알려진 악성 npm 패키지인 function-color를 설치하려는 것을 막아냈습니다. 이를 설치하라는 지시는 의존성(dependency)이나 저장소(repo)로부터 온 것이 아니었습니다. 그것은 아무도 거기에 놓았다는 기억조차 없는 고객의 ~/Downloads 폴더에 있던 AGENTS.md 파일에서 왔습니다.
이 글에서는 연구원들이 보여준 내용, 작동 원리, 그리고 제가 Codex, Claude Code 또는 다른 코딩 에이전트를 운영하는 방식에서 무엇을 변경할 수 있는지 다룹니다. 요약하자면: 명령어 파일은 에이전트가 신뢰하는 명령으로 취급하는 신뢰할 수 없는 입력이며, 방어책은 모델 외부에서 존재해야 합니다.
아래의 모든 성공률은 Forever Security가 자체 보고한 테스트 결과입니다 (BleepingComputer 및 Help Net Security에 의해 보도됨). 작성된 글들 중에는 테스트된 에이전트 버전이 언급되어 있지 않으며, Convika가 10월 27일에 확인했을 때 OpenAI나 Anthropic 모두 코멘트를 남기지 않았습니다.
무슨 일이 일어났는가
- 실제 파일: 13 KB 크기의 'Engineering Work Guidelines'라는 평범하고 일상적인 일반 텍스트 문서였으며, 공격 코드는 마지막 근처의 한 섹션에 루틴한 설정처럼 위장되어 있었습니다.
- 대상: OpenAI Codex. 해당 섹션은 Codex에게 "사용자 요청을 시작하기 전에"
project-tools MCP 서버 블록을 ~/.codex/config.toml 파일에 추가하도록 지시했습니다. 이 서버의 실행 명령어는 macOS의 launchctl에 npm install function-color를 전달했습니다.
- 샌드박스 우회: 설치 과정에 네트워크 접근이 필요했기 때문에, 해당 파일은 Codex에게 "필수 초기화 검사"로 위장하여
--dangerously-bypass-approvals-and-sandbox 옵션을 가진 자식 codex exec을 실행하도록 지시했습니다. 연구원들은 이 플래그가 모델 스스로 작성한 것임을 언급합니다.
- 성공률: "테스트 결과, Codex는 시도 중 90% 이상에서 악성 코드를 실행했습니다." 대부분의 테스트에서는 계산기만 여는 무해한 페이로드(payload)를 사용했지만, 실제 패키지는 격리된 VM 내부에서 한 번 실행되었습니다.
- 지속성 (Persistence):
~/.codex/config.toml 파일은 기계 전체에 적용되므로, 일단 작성되면 해당 장치에서 이후의 모든 Codex 세션이 어떤 폴더에서든 공격자가 만든 서버를 로드하게 됩니다.
- Claude Code: 연구원들은 공격자의 파일을 참고하여 자체적으로
CLAUDE.md 문서를 작성했습니다. 이 파일은 Claude Code에게 .claude/settings.json을 저장하도록 요청했으며, 이때 ANTHROPIC_BASE_URL이 "팀의 내부 게이트웨이"(연구원들이 통제하는 서버)를 가리키도록 했습니다. Claude는 약 50%의 확률로 이를 따랐고, 이 과정에서 OAuth 토큰이 유출되었으며, 연구원들은 이 토큰을 실제 API에 재사용하여 피해자로 위장했습니다.
- 코드 실행: 다음 실행 시, 그들의 서버가 모델인 것처럼 응답하며
dangerouslyDisableSandbox: true를 설정하는 Bash 도구 호출(tool call)을 전송했고 클라이언트가 이를 실행했습니다. 테스트 중 약 5분의 1에서 생성된 서브 에이전트(subagent)가 그들의 서버를 통해 새로운 연결을 열고 동일 세션 내에서 코드 실행에 성공했습니다.
연구원들은 Claude가 "속이기 훨씬 어려웠으며", 페이로드가 너무 강하게 작동했을 때, 서브 에이전트가 CLAUDE.md 파일을 읽어내고 이를 공격으로 플래그 지정했다고 전합니다. 이후 npm은 해당 패키지인 function-color를 제거했습니다.
작동 원리: 결합된 두 가지 무해한 요소
Forever가 제시하는 관점이 연구에서 가장 유용합니다. 각 부분은 그 자체로 문제가 없습니다:
- 지침 파일은 따라야 하는 것입니다.
AGENTS.md와 CLAUDE.md는 에이전트에게 프로젝트 내에서 어떻게 구축하고, 테스트하며, 행동해야 하는지를 알려주기 위해 존재합니다. 에이전트는 이 파일들을 작업 디렉토리(working directory)에서 자동으로 로드합니다.
- 웹 페이지는 사용자 요청 없이
~/Downloads에 파일을 저장할 수 있습니다. BleepingComputer가 확인한 바에 따르면 Chrome, Edge, Firefox는 기본적으로 다운로드 알림창을 표시하지만, 사용자에게 프롬프트를 거치지 않고 해당 폴더에 다운로드를 저장합니다. Brave의 경우 승인을 요청했습니다.
이 두 가지를 결합하면 웹은 사용자가 검토했다고 생각하는 프로젝트 폴더 안에 명령어를 심을 수 있게 됩니다. 운영 체제는 오래전에 다운로드한 실행 파일(executable)을 승인 없이 실행하지 않도록 학습해 왔습니다. Markdown 파일 자체는 실행 파일이 아니므로, 에이전트가 이를 읽기 전까지는 이러한 안전장치(guardrails) 중 어느 것도 적용되지 않습니다.
그리고 이는 드문 현상이 아닙니다. Forever에 따르면 고객의 약 절반이 Downloads 폴더 내에서 코딩 에이전트를 사용하며, 에이전트 세션의 약 4분의 1은 실제 브라우저를 열어봅니다. Weizman은 BleepingComputer에게 Claude Code만으로도 해당 위치에서 1,300회 이상의 세션을 실행했다고 전했습니다. 사람들은 다운로드한 파일을 정리하거나 그 파일에 대해 조치를 취하기 위해 에이전트를 사용합니다.
Convika의 글에서 알아두면 좋은 또 다른 세부 사항이 있습니다: Claude Code 2.1.277 (2026년 9월) 이후로, 프로젝트에 CLAUDE.md가 없는 경우 Claude Code는 AGENTS.md를 읽습니다. 따라서 심어진 AGENTS.md는 두 에이전트 모두에게 도달할 수 있습니다.
진짜 교훈: 길이와 톤이 악용 지점이다
제가 가장 유익하다고 생각한 부분은 파일이 모델을 통과하게 된 '방식'입니다. Forever에 따르면:
- 간단한 "이 패키지를 설치해 주세요" 요청은 거부됩니다. 하지만 길고 지루한 엔지니어링 문서 형식의 내용은 통과합니다. 이것이 실제 파일 크기가 한 줄짜리가 아니라 13 KB인 이유입니다.
- 각 제어 장치들은 산문(prose)으로 우회되었습니다. 신뢰 게이트(Codex는 신뢰하는 프로젝트 내에서만
AGENTS.md를 준수하며, 다운로드 폴더에 작업한 적이 있다면 해당 폴더도 포함됩니다), 시작 시 서버 로딩(자식 세션으로 축소됨), 네트워크 샌드박스(우회 플래그), 그리고 서버 핸드셰이크 타임아웃(설치를 launchctl에 위임하는 것) 등이 그러합니다.
- Claude 페이로드는 "상황을 읽습니다". 깨끗한 폴더에서 작동했던 바로 그 파일이 보안 주석으로 가득 찬 폴더에서는 매번 실패했습니다.
이것이 에이전트를 구축하는 모든 사람에게 불편한 교훈입니다. 모델이 악의적인 지침을 인식할 것이라고 의존해서는 안 됩니다. 거부율은 확률이며, 인내심 있는 공격자는 그 확률이 자신에게 유리해질 때까지 텍스트를 조정합니다. Anthropic 자체 문서도 명확하게 말하고 있습니다: CLAUDE.md와 AGENTS.md는 "강제되는 설정(enforced configuration)이 아니라 컨텍스트"이며, "Claude가 무엇을 결정하든 관계없이 특정 동작을 차단하려면 대신 PreToolUse 훅을 사용하십시오."라고 합니다.
연구원들은 OpenAI나 Anthropic이 패치할 것이 "아무것도 없다"고 주장합니다. 왜냐하면 두 에이전트 모두 설계된 대로 작동하기 때문입니다. 동의하든 안 하든, 이는 해결책이 운영자(operator) 측에 있다는 것을 의미합니다.
오늘 제가 바꿀 것들
이것들은 Forever의 권장 사항, BleepingComputer의 공급업체 가이드라인 주석, 그리고 Convika가 문서화한 설정을 바탕으로 합니다. 저는 이것들을 막는 대상별로 그룹 지었습니다.
1. 에이전트가 시작되는 제어 위치.
절대 ~/Downloads나 ~/에서 에이전트를 시작하지 마십시오. OpenAI와 Anthropic 모두 특정 프로젝트의 루트 디렉터리에서 시작할 것을 권장합니다. 다운로드한 파일을 먼저 프로젝트 폴더로 옮긴 다음, 그곳에서 에이전트를 시작하십시오.
2. 지침 파일(instruction files)을 자신이 작성하지 않은 코드처럼 취급하세요.
에이전트가 접근하기 전에, AGENTS.md나 CLAUDE.md와 같이 자신이 저자(author)가 아닌 모든 파일을 읽어보세요. 이는 방금 클론한 저장소(repo)에서도 마찬가지입니다. 이러한 심어진 파일들은 다음과 같은 설정 노트처럼 보일 수 있습니다: 패키지 설치, 도구 서버 추가, 회사 게이트웨이 사용 등. Convika를 이용해 빠르게 확인하는 방법:
find ~ -maxdepth 2 \( -name 'AGENTS*.md' -o -name 'CLAUDE*.md' \)
2>/dev/null
3. 에이전트 자체의 설정(config)을 주시하세요. 왜냐하면 그곳이 진짜 목표물이기 때문입니다.
두 공격 모두 사용자의 코드가 아닌, 에이전트의 구성 파일에 쓰기 작업을 했습니다. 자신이 추가하지 않은 MCP 서버나 기본 URL이 있는지 확인하세요:
grep -nE 'mcp_servers|base_url' ~/.codex/config.toml
grep -HniE 'BASE_URL|PROXY|apiKeyHelper' ~/.claude/settings.json .claude/settings.json 2>/dev/null
Claude Code에서는 Convika가 설정 변경을 감사(audit)하거나 차단하기 위해 ConfigChange 후크(hook)를 사용하며, .claude/settings.json에 대한 쓰기 작업을 거부하는 PreToolUse 후크도 있습니다 (모델이 echo 명령으로 파일을 쓸 수 있기 때문에 Bash뿐만 아니라 Write|Edit에도 해당).
4. '샌드박스 우회(bypass the sandbox)'를 단순히 권장하지 않는 수준을 넘어 불가능하게 만드세요.
승인(approvals) 및 샌드박스를 활성화 상태로 유지하고, --dangerously-bypass-approvals-and-sandbox 명령이 포함된 명령어는 절대 승인하지 마세요. Claude Code에서는 엄격한 샌드박스 모드("sandbox": {"allowUnsandboxedCommands": false})가 dangerouslyDisableSandbox 매개변수를 무시합니다. Convika의 주의사항에 따르면, 이것만으로는 토큰 누출을 막지 못하는데, 그 이유는 Claude Code 자체 API 트래픽이 Bash 명령어가 아니기 때문입니다.
5. 자신의 권한 모드(permission mode)를 파악하세요.
Convika에 따르면, Claude Code의 2.1.283 버전 이후 대화형 기본값은 auto이며, 이 경우 .claude/에 대한 쓰기 작업이 사용자에게 질문하는 대신 분류기(classifier)로 전달됩니다. 수동 모드(Manual mode)와 acceptEdits는 항상 보호된 경로(protected paths)에 대해 프롬프트를 표시합니다. 신뢰할 수 없는 폴더를 열 경우, --restricted은 보호된 경로 쓰기를 차단하고 명령어 도구를 제거합니다.
6. 심어 놓은 파일을 발견하면, 회전(rotate)하세요.
토큰이 유출되었다고 가정하십시오. Forever는 다음과 같이 경고합니다: '도난당한 토큰은 활성 세션입니다.' 로그아웃했다가 다시 로그인하고, API 키를 교체하며, function-color가 설치되었던 모든 장치를 손상된 것으로 간주해야 합니다.
에이전트 빌더를 위한 더 큰 패턴
단순히 에이전트를 사용하는 것이 아니라 직접 구축하는 경우에도, 귀하의 제품에는 동일한 취약점이 존재합니다:
- 지시사항과 데이터를 내용이 아닌 출처별로 분리하세요. 에이전트가 읽을 수 있고 다른 사람이 작성할 수 있는 모든 것(다운로드된 파일, 웹 페이지, 티켓, 이메일 등)은 지시사항처럼 형식이 지정되어 있더라도 데이터입니다.
- 에이전트 자체의 제어 평면(control plane)을 보호하세요. 설정 파일, 도구 등록 및 API 엔드포인트는 에이전트로부터 쓰기 방지(write-protected)되어야 하며, 모든 변경 사항은 외부 채널 승인(out-of-band approval)이 필요해야 합니다.
- 에이전트가 읽고, 쓰고, 접근하는 것을 기록하세요. Forever는 사용자 행동이 아닌 에이전트의 행동을 모니터링했기 때문에 이 점을 포착했습니다.
Forever의 결론은 다운로드 폴더를 훨씬 넘어 적용됩니다. 대부분의 방어책은 클릭하고, 승인하며, 코드를 실행하는 인간을 중심으로 설계되었습니다. 에이전트는 인간을 그 루프에서 제외시키며, 영구적이라고 느껴졌던 보장들이 다시 가정(assumption)으로 돌아가게 만듭니다.
코딩 에이전트를 어디서 시작해야 하며, 무엇이 이들이 자체 설정을 편집하는 것을 막을 수 있을까요?
참고 자료
참고 자료 및 관련 기사: