페이로드는 영어 한 단락으로 구성되어 있었습니다. 내용은
AWS의 게시물 [AWS-2025-015]는 근본 원인을 제시합니다: 확장 프로그램의 CodeBuild 구성이 너무 광범위한 범위(scope)를 가진 GitHub 토큰을 보유하고 있었습니다. 공격자는 이를 사용하여 오픈 소스 저장소에 코드를 커밋했고, 이 코드는 자동 릴리스로 이어졌습니다. [GitHub advisory]는 이를 "부적절하게 범위가 지정된 GitHub 토큰"이라고 부르며 CVE-2025-8217로 추적합니다.
공격자는 [404 Media]에게 풀 리퀘스트(pull request)를 제출하여 침입했으며, 아마존의 AI "보안 쇼(security theater)"를 폭로하고 싶었다고 말했습니다. Bargury는 GH Archive에서 해당 계정의 풀 리퀘스트 주장을 뒷받침할 만한 이전 활동을 찾지 못했기 때문에, 그 부분은 아직 확인되지 않았습니다. 게시물은 토큰에 대해서만 언급합니다.
다음은 [Bargury의 재구성]에 따른 공개 커밋 기록을 UTC 기준으로 정리한 순서입니다:
- 7월 13일, 19:26: 'scripts/extensionNode.bk'를 추가하는 커밋이 이루어졌으며, 메시지는 "fix(amazonq): use stable backup."입니다.
- 7월 13일, 19:41: 자동화 계정이 'stability' 태그를 생성했습니다 (나중에 삭제됨).
- 7월 13일, 20:10:
lkmanka58이 해당 파일을 수정하여 악성 프롬프트로 Q를 호출하게 했습니다.
- 7월 13일, 20:30:
lkmanka58이 패키징 스크립트에 다운로더를 커밋했습니다. 이 코드는 오직 env.STAGE=prod일 때만 'stability' 태그에서 'src/extensionNode.ts'로 파일을 가져옵니다.
- 7월 17일, 20:29: 다운로더가 포함된 버전 1.84.0이 릴리스되었습니다.
- 7월 19일, 03:58: 풀 리퀘스트를 통해 다운로더가 되돌려진 후 버전 1.85.0이 릴리스되었습니다.
- 7월 23일: [404 Media]가 기사를 게재했습니다. AWS의 게시물은 그날 저녁 태평양 시간(Pacific time)에 뒤따랐습니다.
STAGE=prod 조건은 페이로드를 테스트 빌드에서 제외하도록 만들어졌기 때문에, 오직 빌드 사용자만이 이를 얻게 되었습니다.
왜 단락이 이제 페이로드인가요
Bargury는 한 줄의 교체를 보여줍니다. 디버깅 호출이었던 childProcess.exec(pwd)가 그가 기록한 대로 다음과 같이 변경되었습니다:
childProcess.exec(q --trust-all-tools --no-interactive "${PROMPT}")
q는 Amazon의 Q Developer CLI입니다. CLI 참조에 따르면 --no-interactive는 채팅을 시작하지 않고 첫 번째 응답을 출력하며, --trust-all-tools가 설정되지 않으면 도구가 권한을 필요로 할 때 실패합니다. 이 두 번째 플래그는 모델이 질문 없이 모든 도구를 실행하도록 허용합니다.
따라서 공격자의 실제 작업은 이미 셸(shell), 파일 시스템, AWS 프로필을 가진 에이전트에게 전달된 직무 설명서와 같았으며, 승인 단계가 꺼져 있었습니다. CyberInsider의 요약에 따르면 나머지 프롬프트는 로컬 홈 디렉토리 지우기, ec2 terminate-instances, s3 rm 및 iam delete-user와 같은 명령을 사용한 AWS 리소스 삭제, 그리고 삭제 기록을 /tmp/CLEANER.LOG에 남기는 것을 나열하고 있습니다.
이 명령어는 또한 해당 장치에 q가 필요했습니다. 이것 없이는 모델이 프롬프트를 읽기 전에 호출 자체가 실패합니다.
왜 수고를 했는지 물어볼 수도 있습니다. 주입된 코드는 이미 명령을 실행할 수 있었고 스스로 rm -rf ~를 호출할 수도 있었기 때문입니다. 출처에서 언급한 내용은 아니지만, 제 해석으로는 프롬프트가 공격자에게 검토자나 스캐너에게는 영어처럼 보이는 페이로드를 제공하여, 하드코딩된 rm -rf가 와이퍼(wiper)처럼 보이게 만든 것입니다.
실행되었나요?
AWS의 답변: 코드는 배포되었지만, '구문 오류로 인해 실행에 실패'하여 어떤 서비스나 고객 환경도 변경하지 못했습니다(AWS-2025-015). CVE 기록이 더 정확합니다: 주입된 코드는 '확장 프로그램이 실행될 때' 작동하며, 구문 오류가 Q CLI에 성공적으로 호출하는 것을 막았습니다. 위험도는 중간(Medium)으로 평가되었습니다.
모두가 깨끗한 버전만 받아들이는 것은 아닙니다. BleepingComputer는 보도에 따르면 '일부 사용자들이 악성 코드가 실제로 실행되었지만 아무런 피해를 입히지 않았다'고 보고했다고 전했습니다. 404 Media는 데이터가 삭제된 기기의 실제 위험을 낮다고 판단한 반면, 공격자는 자신이 가진 접근 권한으로 '훨씬 더 큰 피해를 줄 수 있었을 것'이라고 말했습니다. AWS 대변인은 BleepingComputer에 [전해]
이러한 설정들은 악성 코드가 에이전트를 실행할 때를 포함하여 사용자의 자체 에이전트에 경계를 만듭니다. 하지만 이는 자체 코드를 실행하는 확장 프로그램에는 아무런 효과가 없으며, 이것이 바로 1.84.0 버전에서 문제가 된 부분입니다. 이 경우의 경계는 확장 프로그램 업데이트를 고정(pinning)하거나 검토하는 것이거나, 에디터를 dev container 또는 VM에서 실행해야 합니다.
1. 격리된 환경 외부에서의 자동 승인 셸 방지. 이번 공격은 --trust-all-tools에 의존했습니다. Claude Code 버전에서는 이것이 bypassPermissions이며, 문서에는 이를 "컨테이너나 VM과 같은 격리된 환경에서만" 사용하라고 명시되어 있습니다. permissions.disableBypassPermissionsMode를 "disable"로 설정하여 이 기능을 비활성화할 수 있습니다.
2. 클리너가 건드릴 만한 것에 대한 거부 규칙. Claude Code는 "거부(deny) -> 질문(ask) -> 허용(allow)" 순서로 평가하며, 허용 규칙은 거부된 항목에 예외를 만들 수 없습니다. ~/.claude/settings.json 파일에서는 다음과 같습니다:
{
"permissions": {
"disableBypassPermissionsMode": "disable",
...
한계를 인지해야 합니다. 같은 문서에는 Bash 규칙이 "프로그램 주변의 보안 경계가 아니다"라고 명시되어 있습니다. Bash(rm *)는 rm -rf build/를 막지만, /bin/rm -rf build/나 bash -c 'rm -rf build/'는 막지 못합니다. 거부 규칙은 모델이 일반적으로 작성하는 명령을 포착할 뿐입니다. 이 규칙들을 우회하는 명령어까지는 막지 못합니다.
3. 셸을 위한 샌드박스. 이것이 스니펫이 Bash 샌드박스를 활성화하는 이유입니다. 기본적으로 비활성화되어 있으며, /sandbox 또는 sandbox.enabled로 활성화할 수 있습니다. 그러면 셸 명령어는 작업 디렉터리(working directory), 사용자별 임시 디렉터리(per-user temp directory), 그리고 사용자가 추가한 디렉터리에만 쓸 수 있게 됩니다. 문서에는 테스트 방법이 제시되어 있습니다: 샌드박스 내부에서 touch ~/sandbox-probe를 실행하면 macOS에서는 Operation not permitted, Linux 및 WSL2에서는 Read-only file system 오류가 발생해야 합니다. 이 경로 외부에서의 셸 삭제도 같은 방식으로 실패합니다. 일반적으로 ~ 아래에 위치하는 작업 디렉터리 자체는 쓰기가 가능하므로, 에이전트는 여전히 프로젝트를 삭제할 수 있습니다. 또한 샌드박스는 셸 명령어만 포함합니다: 문서에 따르면 Claude의 파일 도구(file tools), MCP 서버 및 후크(hooks)는 이 외부에서 실행됩니다. 이는 macOS, Linux 및 WSL2에서 작동하며 네이티브 Windows에서는 작동하지 않습니다.
4. 작업별 워크트리(worktree)와 모든 턴(turn) 확인. 워크트리는 에이전트의 수정 사항을 메인 체크아웃이나 다른 에이전트와 분리된 자체 브랜치에 보관합니다. 이 기능은 rm -rf ~ 명령까지 막지는 못합니다. 하지만 작업별로 작고 읽기 쉬운 diff를 제공하여, 사용자가 요청하지 않은 작업을 수행하는 에이전트가 눈에 띄게 만듭니다.
Hermes의 역할 범위와 그 한계
저는 Hermes IDE를 구축했으므로 이 섹션을 참고하여 읽어주시기 바랍니다. 해당 README에는 설계 원칙이 명확하게 나와 있습니다: Hermes는 "사용자를 대신하여 권한 프롬프트에 응답하지 않으며, 스스로 터미널에 타이핑하지 않는다." 에이전트가 명령 실행을 요청할 때, 그 질문은 사용자가 답변할 때까지 해당 에이전트의 자체 터미널에 머무릅니다.
이는 이번 사건에서 중요합니다. 공격은 승인 단계를 비활성화함으로써 작동했기 때문입니다. 에이전트를 실행하는 도구는 자동 승인 기능을 조용히 다시 활성화해서는 안 됩니다.
⌘N(Windows 및 Linux에서는 Ctrl+Shift+N)으로 작업을 시작하면, 아무것도 시작되기 전에 에이전트, 새로운 hermes/ 워크트리, 승인 모드, 그리고 Hermes가 실행할 정확한 명령이 표시되는 시트가 나타납니다.
The Hermes ⌘N New task sheet with chips for Claude Code, the orders-api project, a new hermes/ worktree, Accept edits, model and effort, and the Hermes will run preview of the claude command
Hermes 2.3.4의 ⌘N 새 작업 시트: 에이전트, 프로젝트, 새로운 hermes/ 워크트리, '수정 사항 승인(Accept edits)' 모드, 그리고 Hermes가 실행할 명령 미리보기.
모든 에이전트의 턴(turn)은 저장되며, 리뷰 데스크(Review Desk, ⌘G)는 위험 플래그와 함께 턴별 또는 파일별 변경 사항을 보여줍니다. 예상치 못한 파일을 건드린 턴은 쉽게 발견하고 복원할 수 있습니다.
The Hermes Review Desk in By turn view for a Claude Code task in orders-api, listing two turns, turn 1's diff of src/db.ts, the changed-files list and a drafted commit message
턴별 보기의 리뷰 데스크(Review Desk, ⌘G): Claude 코드 작업의 두 턴, 턴 1의 src/db.ts diff, 그리고 해당 턴들로부터 작성된 커밋 메시지.
Hermes는 샌드박스가 아닙니다. 각 에이전트는 '어디에서든 작동할 것과 정확히 동일하게' 실제 터미널에서 실행되므로, 무엇이 실행될지는 에이전트 자체의 권한 설정과 샌드박스에 의해 결정됩니다. Turn-by-turn restore는 리포지토리 내 파일들을 복구합니다. 삭제된 홈 디렉토리나 종료된 EC2 인스턴스는 되돌릴 수 없습니다. Hermes는 BSL 1.1 하에서 무료로 사용 가능하며, macOS, Windows, Linux에서 실행되고, Nous Research, Amazon, Anthropic 또는 어떤 에이전트 공급업체와도 제휴하지 않습니다. 다운로드하거나 GitHub에서 소스 코드를 읽어보세요.
CI를 소유한 사람에게 주는 교훈