GuardFall 셸 인젝션 (Shell Injection): 인기 AI 코딩 에이전트 11개 중 10개가 자체 안전 가드(Safety
요약
Adversa AI의 연구에 따르면 인기 있는 AI 코딩 에이전트 11개 중 10개가 셸 인젝션 공격에 취약한 것으로 나타났습니다. GuardFall이라 명명된 이 취약점은 패턴 기반의 보안 가드가 Bash의 명령어 재작성 방식을 제대로 검증하지 못해 발생합니다.
핵심 포인트
- 인기 AI 코딩 에이전트 대부분이 셸 트릭을 통한 보안 우회에 노출됨
- GuardFall: 패턴 기반 차단 목록과 Bash 실행 방식 간의 구조적 격차
- 자동 실행 플래그 사용 시 악성 명령어가 인간의 검토 없이 실행될 위험
- 단 하나의 에이전트(Continue)만이 해당 유형의 우회 공격을 방어함
AI 코딩 에이전트가 위험한 명령어를 실행하는 것을 막아야 할 안전 점검(Safety check)은, 역설적으로 개발자들이 인간의 검토를 끄고 안심할 수 있게 만드는 바로 그 이유입니다. --auto-exec를 켜고, CI 파이프라인을 설정하며, 차단 목록(Blocklist)을 신뢰하십시오. GuardFall은 그 차단 목록이 작동하지 않을 때 발생하는 현상입니다.
2026년 6월 30일, Adversa AI의 연구원 Omer Ben Simon은 가장 인기 있는 11개의 오픈 소스 AI 코딩 에이전트 중 10개(합계 약 548,000개의 GitHub 스타 보유)가 수십 년 동안 보안 연구에서 문서화된 셸 트릭(Shell tricks)을 통해 우회될 수 있음을 보여주는 연구를 발표했습니다. 영향을 받는 도구에는 Aider, Cline, Roo-Code, Goose, Plandex, Open Interpreter, OpenHands, SWE-agent, opencode, 그리고 NousResearch의 Hermes가 포함됩니다. 오직 하나의 에이전트인 Continue만이 이러한 유형의 우회에 실제로 방어하도록 구축되었습니다.
GuardFall은 Adversa AI가 에이전트 기반 코딩 도구(Agentic coding tools)의 패턴 기반 셸 가드(Shell guards)에 대한 우회 유형에 붙인 이름입니다. 즉, 가드는 가공되지 않은 명령어 텍스트(Raw command text)를 검사하지만, Bash는 이를 실행하기 전에 텍스트를 재작성하며, 두 가지는 결코 동일한 것을 보지 못한다는 것입니다. 이 격차는 우연이 아닌 구조적인 문제입니다. 차단 목록(Denylist) 패턴을 더 추가하더라도 이 격차는 메워지지 않습니다.
실제로 무슨 일이 일어났는가?
이 연구는 NousResearch의 오픈 소스 Hermes 프로젝트에서 시작되었습니다. Adversa AI는 Hermes의 30개 패턴 정규 표현식(Regex) 차단 목록이 수십 년 된 셸 인용(Shell quoting) 기술을 사용하여 통과될 수 있음을 발견했습니다. 필터는 r''m을 rm과 다른 것으로 인식합니다. 하지만 Bash는 빈 따옴표를 제거하고 어쨌든 rm을 실행합니다. 거기서부터 그들은 GitHub 스타 수 기준으로 가장 인기 있는 10개의 코딩 에이전트를 추가로 테스트했습니다.
이 공격은 두 가지 조건을 필요로 하며, 두 조건 모두 운영 환경에서 흔히 볼 수 있는 것입니다. 첫째, AI 모델이 악성 명령어를 생성해야 합니다. 노골적인 rm -rf /는 일반적으로 거부되지만, Makefile 타겟, MCP 도구의 문서 응답, 또는 에이전트가 저장소의 일부로 읽어들이는 설정 파일(config file)에 포함된 동일한 명령어는 일상적인 작업으로 간주되어 생성됩니다. 둘째, --auto-exec, --auto-run, --auto-test, dangerously-skip-permissions와 같은 자동 실행 플래그(auto-execution flag)가 켜져 있거나 컨테이너 샌드박스(container sandbox)가 꺼져 있어야 합니다. 두 가지 모두 CI 파이프라인(CI pipelines)과 개발자 노트북 설정에서 표준적으로 사용됩니다.
Adversa는 실제 운영 중인 Plandex 바이너리를 대상으로 전체 공격 체인(attack chain)을 엔드 투 엔드(end-to-end)로 시연했으며, 다른 8개의 에이전트에 대해서도 동일한 공격 경로를 확인했습니다. 시연된 공격 시나리오는 다음과 같습니다: 개발자의 CI 파이프라인에 풀 리퀘스트(pull requests)에서 실행되는 코딩 에이전트가 포함되어 있습니다. 에이전트는 공격자가 제출한, ~/.aws/credentials를 삭제하는 clean 타겟이 정의된 Makefile을 읽습니다. 에이전트의 자동 실행 플래그가 인간의 검토 없이 이를 실행합니다. 결과적으로 IAM 자격 증명(IAM credentials)이 사라집니다.
다섯 가지 우회 클래스(bypass classes)가 이 구조적인 문제를 포괄합니다. 클래스 A: 따옴표 제거(quote removal) — r''m이 rm이 됩니다. 클래스 B: $IFS 확장(expansion) — rm$IFS-rf$IFS/는 패턴 필터에는 하나의 단어로 보이지만, bash에는 세 개의 인자(arguments)로 보입니다. 클래스 C: 명령어 치환(command substitution) — $(echo rm) -rf /는 바이너리 이름을 동적으로 생성하여 문자열 매처(string matcher)가 감지할 수 없게 만듭니다. 클래스 D: 셸(shell)로 전달되는 base64 — 각 세그먼트는 단독으로는 무해하지만, 결합되면 파괴적입니다. 클래스 E: 대안적인 파괴적 argv 형태 — find /x -delete, dd of=/dev/sda, install -m 4755 payload /usr/bin/backdoor 등이 있습니다.
GuardFall에 할당된 단일 CVE는 없습니다. 그것이 핵심입니다. 이것은 단일 구성 요소의 패치 가능한 버그가 아닙니다. 이것은 문자열 매칭(string matching)으로 제어되는 에이전트와 셸 사이의 설계 관행(design convention)이 구조적으로 실패한 것입니다.
패턴 기반 셸 가드(Pattern-Based Shell Guards)가 이 싸움에서 이길 수 없는 이유
근본적인 문제는 가공되지 않은(raw) 명령 문자열(command strings)에서 작동하는 텍스트 매처(text matcher)가 bash의 확장 규칙(expansion rules)을 모델링할 수 없다는 점입니다. 매처를 통과하면서도 매칭된 패턴과 bash 상에서 동일한 의미를 갖는 모든 재작성(rewrite)은 우회(bypass)에 해당합니다. 차단 목록(blocklist)의 범위가 얼마나 넓은지는 중요하지 않습니다.
Adversa의 조사 결과, 영향을 받은 에이전트들에서 네 가지 아키텍처적 실패 모드(architectural failure modes)가 확인되었습니다.
모드 1: 가공되지 않은 문자열에 대한 정규 표현식(Regex) 적용. Hermes, opencode, 그리고 Goose는 고정된 정규 표현식 세트를 컴파일하여 이를 문자 그대로의 명령(verbatim command)과 대조합니다. 이는 다섯 가지 우회 클래스(bypass classes) 모두에서 실패합니다.
모드 2: 토큰화되었으나 가공되지 않은 텍스트 매칭. Cline (옵트인 모드)과 Roo-Code는 명령을 토큰화(tokenize)하지만, 여전히 재구성된 세그먼트 텍스트를 대상으로 매칭을 수행합니다. 이는 클래스 A를 부분적으로 차단하지만, 클래스 C(따옴표 내부)와 클래스 E는 여전히 취약한 상태로 남습니다.
모드 3: 정적 가드(static guard) 부재 및 자동 승인(auto-yes). Aider, Plandex, Open Interpreter, 그리고 Cline (기본 모드)은 패턴 매칭을 수행하지 않습니다. 이들의 방어 기제는 인간이 개입하는 방식(human in the loop)입니다. 하지만 워크플로의 압박으로 인해 --auto-test, --auto-exec가 생성되거나, 악성 저장소(repository)가 운영자가 조치를 취하기 전에 플래그를 전환하는 설정 파일을 배포할 때까지는 무방비 상태입니다. 클론된 저장소 내부의 .aider.conf.yml 파일은 auto-test: true를 설정하고 test-cmd 필드에 페이로드(payload)를 심을 수 있습니다. 에이전트는 이를 일반적인 프로젝트 설정으로 읽어들입니다.
모드 4: 문서화된 로컬 옵트아웃(opt-out) 기능이 있는 컨테이너 샌드박스(Container sandbox). OpenHands와 SWE-agent는 기본적으로 샌드박스를 사용하며, 이는 워크스페이스가 일회용(disposable)일 때는 안전해 보입니다. 그러나 두 에이전트 모두 컨테이너를 비활성화하고 별도의 대체 수단(fallback)을 제공하지 않는 로컬 모드 설정을 문서화하여 제공합니다. 로컬 모드는 CI, 개발자 노트북, 셀프 호스팅 러너(self-hosted runners)에서 흔히 사용되며, 바로 이러한 배포 환경이 실제 자격 증명(credentials)이 존재하는 곳입니다.
Continue는 예외입니다. 이 에이전트의 평가기(evaluator)는 shell-quote를 사용하여 토큰화하고, 변수 확장(variable expansion)을 감지하며, 명령 치환(command substitutions) 내부로 재귀적으로 들어가고, 파이프(pipe) 목적지를 확인하며, 전형적인 파괴적 패턴에 대해 명시적인 비활성화 목록을 유지합니다. 테스트 결과, 21개의 우회 페이로드 중 기본 IDE 모드에서 allowedWithoutPermission에 도달한 것은 단 하나도 없었습니다.
실패한 모든 설계의 공통점은 다음과 같습니다: 결정(decision)이 이를 유지할 수 없는 어딘가에 위치한다는 점입니다. 모델은 신뢰할 수 없습니다. 직접적인 요청으로서는 거부되었던 동일한 페이로드(payload)가 운영 컨텍스트(operational context)로 감싸지면 망설임 없이 방출됩니다. 운영자 확인(operator confirmation)도 신뢰할 수 없습니다. 워크플로(workflow)가 느려지는 첫 순간에 자동 승인(auto-yes) 플래그가 설정됩니다. 컨테이너(container)도 신뢰할 수 없습니다. 컨테이너는 로컬 옵트아웃(local opt-out)이 설정될 때까지 방어하지만, 이는 실제 배포 환경에서 흔히 발생하는 일입니다.
다음 CI 실행 전에 무엇을 점검해야 하는가?
이 중 어느 것도 완전한 해결책은 아닙니다. 이것들은 상위 단계(upstream)에서 아키텍처 문제(architectural problem)가 해결되는 동안 사용하는 보완 통제(compensating controls)입니다.
모든 에이전트 호출에 대해 $HOME을 리다이렉션(Redirect)하십시오. 한 줄짜리 셸 래퍼(shell wrapper) — HOME=$HOME/.agent-sandbox-$RANDOM agent … — 를 사용하면 프로젝트 디렉토리는 유지하면서도, 공격자가 가장 노리는 자격 증명 표면(credential surface)인 ~/.ssh/, ~/.aws/, 셸 히스토리(shell history) 등을 제거할 수 있습니다. 이는 항상 활성화되어 있으며 단일 플래그로 옵트아웃할 수 없습니다.
피할 수 없는 경우가 아니라면 자동 실행(auto-execute) 플래그를 비활성화하십시오. 이는 --auto-exec, --auto-run, --auto-test, dangerously-skip-permissions, 그리고 auto-mode: full에 적용됩니다. CI 환경에서는 이러한 설정을 기본값이 아닌, 명시적인 정당화가 필요한 권한 있는 하위 프로세스 호출(privileged subprocess invocations)로 취급해야 합니다.
포크된 풀 리퀘스트(fork pull requests)에서 에이전트 실행을 비활성화하십시오. 공격자가 제어하는 README 또는 테스트 설정 파일은 신뢰할 수 없는 콘텐츠에서 권한 있는 셸 실행(privileged shell execution)으로 이어지는 가장 직접적인 경로입니다. 포크된 PR(Fork PRs)은 전체 계정 액세스 권한을 가진 코딩 에이전트를 실행해서는 안 됩니다.
저장소 설정 파일(repository config files)을 감사하십시오. 클론된 저장소 내에 포함된 악성 .aider.conf.yml 파일은 auto-test: true로 전환하고 test-cmd 필드에 페이로드를 심을 수 있습니다. 저장소에 포함된 에이전트 설정은 신뢰할 수 없는 코드(untrusted code)로 취급하십시오.
빌더(builders)와 유지관리자(maintainers)를 위한 조언: 이번 조사에서 확인된 유일하게 견고하고, 항상 작동하며, 플래그(flag)에 의존하지 않는 방어책은 Continue 스타일의 평가기(evaluator)입니다. 연구진은 다섯 가지 구성 요소 — 토큰화(tokenize), 확장 탐지(detect expansion), 치환에 대한 재귀(recurse into substitutions), 파이프 목적지 확인(check pipe destinations), 명시적인 비활성화 목록 유지(maintain an explicit disabled list) — 를 구현하는 것이 숙련된 엔지니어에게는 대략 이틀 정도의 작업이라고 설명합니다.
Waxell이 이를 처리하는 방식
GuardFall이 드러낸 구조적 문제는 에이전트와 셸(shell) 사이의 경계에 거버넌스 계층(governance layer)이 없다는 점입니다. 에이전트는 명령을 내보내고, 셸은 이를 실행하며, 그 사이의 문자열 매칭(string match)은 bash가 실제로 무엇을 수행할지에 대한 모델을 가지고 있지 않습니다. 차단 목록(blocklist)에 더 많은 패턴을 추가하는 것은 렉서(lexer) 대 평가기(evaluator) 문제를 해결하지 못합니다.
Waxell Observe는 셸 앞단이 아닌 에이전트 실행 계층(agent execution layer)에 위치합니다. 두 줄의 코드로 초기화되는 이 시스템은 도구 호출(tool-call) 수준에서 실행을 가로채며, 어떤 것이 셸에 도달하기 전에 각 호출을 50개 이상의 정책 카테고리에 따라 평가합니다. 콘텐츠(Content) 정책 카테고리는 입력으로 수용될 수 있는 것을 검증하며, 안전(Safety) 카테고리는 에이전트가 내보낼 수 있는 도구 호출에 대해 엄격한 제한을 적용합니다. 아이덴티티(Identity) 카테고리는 각 작업이 전체 계정이 아닌, 해당 작업을 승인한 아이덴티티(identity)의 범위 내에서 이루어지도록 보장합니다. 이러한 정책들은 실행 전(pre-execution)에 작동합니다. 즉, bash -c가 문자열을 접하기 전에 평가를 완료합니다.
패턴 기반의 차단 목록(blocklist)과의 차이점은 명확합니다. 차단 목록은 에이전트가 이미 내보내기로 결정한 텍스트를 대상으로 실행됩니다. 반면 Waxell의 정책 엔진은 셸이 확인하기 전의 도구 호출에 대해, 그리고 모델이 무엇인가를 결정하기 전의 입력에 대해 실행됩니다. 텍스트 매처(text matcher)를 무력화하는 따옴표 제거(quote-removal)나 $IFS 우회 기법은, 명령 문자열의 문자가 아닌 작업의 의미론(semantics)을 평가하는 정책에는 영향을 미치지 않습니다.
MCP를 통해 외부 서비스와 연결된 에이전트를 운영하는 팀의 경우, Waxell MCP Gateway가 두 번째 계층을 추가합니다. 이 게이트웨이는 도구가 등록되는 시점인 핑거프린트 타임(fingerprint time) — 즉, 에이전트가 도구를 호출하기 전 — 에 도구 설명(tool descriptions)을 스캔하며, 도구 메타데이터에 포함된 명령(instructions)을 포착하는 프롬프트 인젝션 스캐너(prompt injection scanner)를 사용합니다. MCP 도구의 문서 필드에 심어진 Makefile 명령은 모델의 컨텍스트(context)에 도달하기 전에 차단됩니다. 개인정보(PII) 및 비밀 정보(secrets)는 에이전트에 진입하기 전 전송 과정(in flight)에서 삭제(redacted)됩니다. 이것은 제어된 입력 및 검증된 데이터 인터페이스 (controlled inputs and validated data interfaces)입니다. 거버넌스(governance) 결정이 실제로 이를 제어할 수 있는 위치에서 이루어집니다.
전체 에이전트 보안 모델 (agent security model)을 탐색할 수 있습니다. Waxell Observe는 다음 두 줄로 시작할 수 있습니다:
pip install waxell-observe
자주 묻는 질문 (Frequently Asked Questions)
어떤 AI 코딩 에이전트가 GuardFall의 영향을 받습니까?
2026년 6월 30일 Adversa AI 설문 조사에서 영향을 받은 10개의 에이전트는 다음과 같습니다: Aider, Cline, Goose, Open Interpreter, OpenHands, opencode, Plandex, Roo-Code, SWE-agent, 그리고 NousResearch Hermes입니다. 이들은 합계 약 548,000개의 GitHub 스타를 보유하고 있습니다. 오직 Continue만이 우회 표면(bypass surface)의 구조적 대부분을 차단하는 가드 아키텍처(guard architecture)를 갖추고 구축되었습니다.
GuardFall에 할당된 CVE가 있습니까?
아니요. Adversa AI는 추적하거나 패치할 단일 CVE가 없음을 명시적으로 밝히고 있습니다. GuardFall은 우회 기법의 한 종류(class of bypasses)입니다. 즉, 단일 구성 요소의 개별적인 취약점이 아니라 설계 관습(design convention)입니다. 더 많은 차단 목록(denylist) 패턴을 추가하는 것으로는 해결되지 않습니다. 아키텍처 패턴(문자열 매칭으로 제어되는 에이전트-bash 연결)은 목록에 패턴이 얼마나 많든 상관없이 구조적으로 실패하기 때문입니다.
GuardFall이 CI/CD 파이프라인에 의미하는 바는 무엇입니까?
CI 파이프라인은 일반적으로 자동 실행 (auto-execute) 플래그가 켜진 상태로 실행됩니다. 이것이 CI의 목적이기 때문입니다. GuardFall은 해당 플래그가 활성화되는 즉시 악용될 수 있습니다. 영향을 받는 코딩 에이전트를 사용하면서 신뢰할 수 없는 콘텐츠(포크된 풀 리퀘스트 (fork pull requests), 제3자 의존성 파일, 공격자가 접근 가능한 설정 파일)를 처리하는 모든 CI 파이프라인은 공격 표면 (attack surface)에 노출되어 있습니다. 즉각적인 보완 통제 (compensating controls)로서 $HOME을 리다이렉션하고, 포크된 PR에 대한 에이전트 실행을 비활성화하십시오.
자동 실행을 비활성화하면 GuardFall을 방어할 수 있습니까?
부분적으로 그렇습니다. 이 공격은 모델이 악성 명령을 생성해야 하며, 동시에 셸 (shell)이 이를 자동으로 실행해야 합니다. 자동 실행 플래그를 제거하면 두 번째 조건은 제거되지만, 첫 번째 조건은 해결되지 않습니다. 즉, 악성 저장소는 첫 번째 편집 시 자동 실행을 다시 활성화하는 설정 파일 (.aider.conf.yml)을 배포하여 운영자의 설정을 우회할 수 있습니다. 자동 실행 비활성화는 보완 통제일 뿐, 완전한 방어책은 아닙니다.
Waxell의 정책 강제 (policy enforcement)는 GuardFall 방식의 공격을 어떻게 방지합니까?
Waxell Observe는 셸이 명령을 확인하기 전, 도구 호출 (tool-call) 단계에서 가로챕니다. 콘텐츠 (입력 검증), 안전 (도구 호출 제한), 신원 (범위 강제)을 포함한 50개 이상의 정책 카테고리는 명령 문자열의 텍스트가 아니라, 동작의 의미론 (semantics)을 바탕으로 실행 전에 검사합니다. 텍스트 매처 (text matcher)를 무력화하는 따옴표 제거 또는 $IFS 우회 기법은 호출이 무엇을 시도하고 있는지를 평가하는 정책에는 영향을 미치지 않습니다. Waxell MCP Gateway는 외부 연결 도구에 대해 두 번째 계층을 추가합니다. 이는 지문 인식 (fingerprint) 시점에 도구 설명을 스캔하여 내장된 지침을 확인하고, 에이전트에 도달하기 전에 자격 증명 및 개인정보 (PII)를 삭제합니다.
다음 CI 실행 전에 무엇을 해야 합니까?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기