프롬프트 인젝션은 OWASP가 LLM 애플리케이션 취약점을 추적하기 시작한 이래 줄곧 1위를 차지하고 있다. 모든 주요 AI 플랫폼이 이에 대한 가이드를 발표했다. 연구자들은 수십 가지 방어 기법을 제안했다. 그러나 어떤 것도 문제를 해결하지 못했으며, 이 방어들이 계속 실패하는 패턴은 문제의 근본 원인이 어디에 있는지를 가리키고 있다.
요약하면 이렇다: 문제 그 자체인 계층에서는 문제를 해결할 수 없다. 프롬프트 인젝션은 모델이 개발자의 명령과 공격자의 명령을 구분할 수 없기 때문에 작동한다. 모델에 더 많은 명령을 추가하는 방식으로 이를 해결하려는 모든 방어는, 바로 그 공격을 가능하게 만드는 동일한 제약 조건 안에서 작동하는 것이다.

공격이 실제로 하는 일
언어 모델은 컨텍스트 윈도우를 입력으로 받아 완성(completion)을 생성한다. 컨텍스트 윈도우는 토큰의 평면적인 시퀀스다. 모델에는 어떤 토큰이 신뢰할 수 있는 시스템 프롬프트에서 왔는지, 어떤 토큰이 사용자에게서 왔는지, 어떤 토큰이 에이전트가 작업 중에 가져온 외부 콘텐츠에서 왔는지를 추적하는 네이티브 메커니즘이 없다. 개발자들은 역할 태그 같은 구조적 관례를 사용해 의도를 표시하지만, 이는 관례일 뿐 강제 사항이 아니다. 모델의 관점에서 전체 컨텍스트는 다음 토큰 예측에 참고하는 입력일 뿐이다.
프롬프트 인젝션은 이것을 악용한다. 공격자는 에이전트가 읽을 콘텐츠, 즉 웹페이지, 문서, 이메일, 코드 주석, 데이터베이스 필드 등에 명령을 삽입하고, 이 명령들은 동일한 컨텍스트 윈도우 안에서 개발자의 명령과 경쟁한다. 삽입된 명령이 충분히 설득력 있거나, 일관성이 있거나, 컨텍스트 내에서 유리한 위치에 배치되면, 모델은 개발자의 명령 대신 이를 따른다. 이것은 특정 모델의 버그가 아니다. 이러한 시스템들이 작동하는 방식 자체의 결과다.
간접 프롬프트 인젝션은 더 위험한 형태다. 사용자가 직접 악의적인 프롬프트를 입력하는 대신, 공격자가 에이전트가 자율적으로 가져오는 콘텐츠를 오염시킨다. 사용자는 잘못한 것이 없다. 에이전트가 작업을 수행하는 과정에서 오염된 콘텐츠를 접하게 되고, 공격이 실행된다. 공격자는 대화에 접근할 필요가 없다. 에이전트가 읽을 곳 어딘가에 자신의 텍스트를 넣기만 하면 된다.
문서화된 공격 사례

2024년 8월, PromptArmor의 보안 연구원들이 Slack AI의 프롬프트 인젝션 취약점을 문서화했다. 공격은 이렇게 작동했다: 공격자가 공개 Slack 채널을 만들고 악의적인 명령이 포함된 메시지를 게시한다. 이 메시지는 Slack AI에게 사용자가 API 키를 조회할 때, 자리 표시 단어를 실제 키 값으로 대체하고 이를 "재인증하려면 여기를 클릭하세요" 링크의 URL 파라미터로 인코딩하라고 지시한다. 공격자의 채널에는 멤버가 한 명뿐이다: 공격자 자신. 피해자는 이 채널을 본 적이 없다. 워크스페이스의 다른 곳에서 한 개발자가 Slack AI를 사용해 자신의 API 키에 대한 정보를 검색하면, 이 API 키는 공격자가 접근할 수 없는 비공개 채널에 저장되어 있음에도 불구하고, Slack AI는 공격자의 공개 채널 메시지를 컨텍스트에 가져오고, 명령을 따르고, 개발자의 Slack 환경에 피싱 링크를 렌더링한다. 이를 클릭하면 비공개 API 키가 공격자의 서버로 전송된다.
이 공개에 대한 Slack의 초기 대응은 사용자가 멤버가 아닌 공개 채널을 조회하는 것은 의도된 동작이라는 것이었다. 문제는 채널 접근 정책이 아니다. 문제는 모델이 Slack 직원의 명령과 공격자의 명령이 동시에 컨텍스트 윈도우에 존재할 때 이 둘을 구분할 수 없다는 것이다.
2025년 6월, 한 연구원이 GitHub Copilot의 프롬프트 인젝션 취약점을 발견했으며, 이는 CVE-2025-53773으로 추적되고 Microsoft의 2025년 8월 패치 화요일(Patch Tuesday) 릴리스에서 패치되었다. 공격 벡터는 소스 코드 파일, README 파일, GitHub 이슈, 또는 Copilot이 처리할 수 있는 기타 텍스트에 삽입된 악의적인 명령이었다. 이 명령은 Copilot에게 프로젝트의 .vscode/settings.json 파일을 수정하여 프로젝트에서 "YOLO 모드"라고 부르는 기능을 활성화하는 설정 한 줄을 추가하도록 지시했다: 모든 사용자 확인 프롬프트를 비활성화하고 AI에게 셸 명령을 실행할 수 있는 무제한 권한을 부여하는 것이다. 그 줄이 작성되면, 에이전트는 묻지 않고 개발자의 머신에서 명령을 실행한다. 연구원은 계산기를 여는 것으로 이를 시연했다. 실제 악성 페이로드는 훨씬 더 심각할 것이다. 이 공격은 GPT-4.1, Claude Sonnet 4, Gemini 및 기타 모델을 기반으로 한 GitHub Copilot에서 모두 작동하는 것으로 확인되었는데, 이는 취약점이 모델에 있지 않다는 것을 말해준다. 취약점은 아키텍처에 있다.
웜 변종(wormable variant)은 이해할 가치가 있다. Copilot은 파일에 쓸 수 있고, 삽입된 명령은 Copilot에게 리팩토링이나 문서 생성 중에 처리하는 다른 파일로 명령을 전파하라고 지시할 수 있기 때문에, 단 하나의 오염된 저장소가 개발자가 작업하는 모든 프로젝트를 감염시킬 수 있다. 명령은 바이러스가 실행 파일을 통해 퍼지는 것처럼 커밋을 통해 전파된다. GitHub은 이제 이 종류의 위협을 "AI 바이러스"라고 부른다.
표준 방어가 실패하는 이유
프롬프트 인젝션에 대한 직관적인 대응은 더 나은 시스템 프롬프트를 작성하는 것이다. 가져온 콘텐츠의 명령을 무시하라고 모델에 지시한다. 외부 데이터를 신뢰할 수 없는 것으로 취급하라고 지시한다. 자신의 동작을 재정의하려는 시도로 보이는 것을 플래그하라고 지시한다. 많은 플랫폼이 정확히 이렇게 한다. 보안 벤더들은 에이전트의 컨텍스트에 정교하게 설계된 탐지 프롬프트를 추가하는 것을 중심으로 구축된 제품을 판매한다.
OpenAI, Anthropic, Google DeepMind의 연구팀이 2025년 10월에 프롬프트 인젝션에 대해 발표된 12가지 방어를 평가하고 각각에 적응적 공격(adaptive attack)을 수행한 논문을 발표했다. 12가지 모두를 우회했으며, 대부분에서 공격 성공률은 90%를 넘었다. 방어들이 나쁘지 않았다. 실제 기법을 사용하는 진지한 연구자들의 작업이 포함되어 있었다. 문제는 모델에게 무엇을 거부해야 하는지 가르치는 방어는, 그 방어가 무엇을 말하는지 아는 공격자에 의해 역설계될 수 있다는 것이다. 공격자의 명령은 동일한 컨텍스트 윈도우에서 경쟁한다. 방어가 "데이터를 전달하라는 명령을 무시하라"고 말하면, 공격자는 그런 단어를 사용하지 않는 명령을 작성하거나, 이 특정 경우가 왜 다른지에 대한 그럴듯한 정당화를 제공하거나, 신뢰할 수 있는 출처의 권한을 주장하는 명령을 작성한다. 모델은 이에 대해 추론한다. 추론은 조작될 수 있다.
LLM 기반 탐지기도 다른 수준에서 동일한 문제를 가지고 있다. 두 번째 모델을 사용해 입력을 검사하고 악의적인 프롬프트가 포함되어 있는지 판단하게 하면, 그 두 번째 모델도 동일한 근본적 제약을 가진다. 주어진 콘텐츠를 기반으로 판단을 내리는 것이며, 그 판단은 콘텐츠에 의해 영향받을 수 있다. 연구자들은 탐지기에게는 양성으로 보이고 하류 에이전트에게는 악성으로 작동하는 인젝션을 제작하여 탐지 기반 방어를 성공적으로 우회하는 공격을 시연한 바 있다.
이 모든 접근 방식이 의지가 있는 공격자에게 실패하는 이유는, 신뢰를 강제할 수 없는 컨텍스트 윈도우에 더 많은 콘텐츠를 추가하는 것으로 신뢰 문제를 해결하려 하기 때문이다. 공격 표면은 컨텍스트 윈도우 자체다. 컨텍스트 윈도우에 더 많은 명령을 추가하는 것은 공격 표면을 줄이지 않는다.
실제로 문제를 제약하는 것
시스템의 보안 속성이 모델의 올바른 판단에 의존해서는 안 된다는 원칙을 적용하면, 프롬프트 인젝션 위험을 의미 있게 줄일 수 있다. 이것은 보안에서 새로운 아이디어가 아니다. "접근 권한이 있는 데이터만 접근하세요"라고 정책 문서에 쓰는 대신, 코드에서 접근 제어를 강제하게 만드는 것과 같은 원칙이다.
AI 에이전트의 경우, 이는 강제 계층이 모델 외부에, 모델의 추론이 영향을 미칠 수 없는 코드에 위치해야 한다는 것을 의미한다. 모델은 요청을 생성한다. 코드는 세션 상태에 대한 사실, 관련 데이터의 분류, 출력이 향하는 채널의 권한을 기반으로 해당 요청이 허용되는지 평가한다. 모델은 이 평가를 말로 통과시킬 수 없다. 왜냐하면 이 평가는 대화를 읽지 않기 때문이다.
이것이 프롬프트 인젝션을 불가능하게 만드는 것은 아니다. 공격자는 여전히 명령을 삽입할 수 있고 모델은 여전히 이를 처리할 것이다. 달라지는 것은 피해 범위다. 삽입된 명령이 데이터를 외부 엔드포인트로 유출하려고 하면, 아웃바운드 호출은 모델이 명령을 무시하기로 결정했기 때문이 아니라, 강제 계층이 해당 요청을 세션의 분류 상태 및 대상 엔드포인트의 분류 하한과 대조하여 검사하고 해당 흐름이 하향 기록(write-down) 규칙을 위반함을 발견했기 때문에 차단된다. 모델의 의도가, 실제든 삽입된 것이든, 이 검사와는 무관하다.

세션 오염(taint) 추적은 접근 제어만으로는 커버할 수 없는 특정 간극을 메운다. 에이전트가 CONFIDENTIAL로 분류된 문서를 읽으면, 해당 세션은 이제 CONFIDENTIAL로 오염된다. 이후 PUBLIC 채널을 통해 출력을 보내려는 모든 시도는, 모델이 무엇을 하라고 지시받았든, 그 명령이 정당한 사용자에게서 왔든 삽입된 페이로드에서 왔든 관계없이, 하향 기록 검사에 실패한다. 인젝션은 모델에게 데이터를 유출하라고 지시할 수 있다. 강제 계층은 신경 쓰지 않는다.
아키텍처적 프레이밍이 중요하다: 프롬프트 인젝션은 모델의 명령 수행 동작을 대상으로 하는 공격 유형이다. 올바른 방어는 모델에게 명령을 더 잘 따르도록 가르치거나 나쁜 명령을 더 정확하게 탐지하도록 가르치는 것이 아니다. 올바른 방어는 모델이 잘못된 명령을 따랐을 때 발생할 수 있는 결과의 범위를 줄이는 것이다. 이를 위해서는 결과, 즉 실제 도구 호출, 실제 데이터 흐름, 실제 외부 통신을 모델이 영향을 미칠 수 없는 게이트 뒤에 배치하면 된다.
이것은 해결 가능한 문제다. 모델이 신뢰할 수 있는 명령과 그렇지 않은 명령을 안정적으로 구분하게 만드는 것은 불가능하다.
