사람은 안 보이지만 AI는 보이는 MCP 서버의 보안 취약점
터미널 제어용으로 쓰이는 ANSI 이스케이프 시퀀스를 악용해, 사용자 눈에는 보이지 않지만 AI 모델에게는 악성 지시문이 읽히도록 숨기는 새로운 프롬프트 인젝션 공격이 대두되었습니다. 특히 AI 에이전트와 연결되는 MCP 서버 환경에서 이 취약점이 치명적으로 작용할 수 있으며, DAST(동적 애플리케이션 보안 테스트) 스캐너를 통해 이를 탐지하고 방어하는 방안의 중요성이 강조됩니다.
DAST로 MCP 서버의 ANSI 이스케이프 시퀀스 인젝션 탐지하기
ANSI 이스케이프 시퀀스는 터미널을 위해 설계되었지, 대형 언어 모델을 위해 만들어진 것이 아닙니다. 이는 터미널에 색상을 변경하거나, 텍스트를 숨기거나, 화면을 지우거나, 커서를 이동하도록 지시하는 보이지 않는 제어 코드입니다. 렌더링된 터미널 화면을 읽는 사람은 이 코드 자체를 절대 볼 수 없으며, 오직 그 결과만 보게 됩니다. 하지만 동일한 내용을 읽는 언어 모델은 모든 바이트를 그대로 읽어냅니다. 이 격차가 바로 이 공격의 핵심입니다. 공격자가 AI 에이전트가 소비하는 텍스트에 ANSI 이스케이프 시퀀스를 밀반입할 수 있다면, 출력물을 검토하는 인간의 눈에는 지시문을 숨기면서도 모델에는 완벽하게 읽히도록 만들 수 있습니다.
이는 실제 제품에서 발견됐던 출력 무효화 실패 취약점과 동일한 종류입니다. 과거 Kubernetes kubectl (CVE-2021-25743)은 터미널 출력을 위조할 수 있는 제어 시퀀스를 Event 문자열에서 허용했으며, Git (CVE-2024-52005)은 터미널 제어 코드를 제거하지 않은 채 원격 사이드밴드 메시지를 출력했습니다. 모델 컨텍스트 프로토콜(MCP) - 서버가 텍스트를 에이전트로 직접 스트리밍하는 도구, 리소스 및 프롬프트를 노출하는 환경 - 에서는 모델이 읽는 모든 필드가 잠재적인 인젝션 표면이 됩니다.
DAST(동적 애플리케이션 보안 테스트)는 이러한 종류의 결함을 잡는 자연스러운 방법입니다. Bright 스캐너는 외부에서 실행 중인 대상을 테스트하고, 조작된 입력을 보낸 뒤, 실제 응답을 검사하여 소스 코드 접근 없이도 취약점의 증거를 찾아냅니다. 페이로드가 살아남는지 여부는 실제 서버가 이를 어떻게 처리하고 전달하는지에 전적으로 달려 있기 때문에, 이러한 블랙박스 런타임 방식이야말로 ANSI 이스케이프 시퀀스 인젝션(AESI) 탐지에 꼭 필요합니다. 이 글에서는 두 가지 공격 변형인 직접 패치 AESI와 저장형 AESI, 이들이 초래하는 위험, 그리고 가장 중요한 DAST 스캐너가 이를 어떻게 자동으로 탐지하는지 다룹니다.
ANSI 이스케이프 시퀀스란 무엇인가? ANSI 이스케이프 시퀀스는 1970년대로 거슬러 올라갑니다. 당시 다양한 하드웨어 터미널 벤더들은 서로 호환되지 않는 고유한 제어 방식을 사용했습니다. ANSI X3.64 표준은 이를 통합하여, 프로그램이 커서 이동, 화면 지우기 또는 색상 설정을 위해 합의된 하나의 코드 세트를 내보내면 모든 호환 터미널이 이를 따르도록 만들었습니다. 텍스트 터미널을 휴대 가능하고 제어 가능하게 만들기 위해 발명되었으며, 오늘날의 공격은 바로 이 제어 기능을 악용하는 것입니다.
ANSI 이스케이프 시퀀스는 이스케이프 바이트(ESC, 16진수 0x1B)로 시작하여 터미널이 일반 텍스트가 아닌 명령으로 처리하는 제어 코드로 이어집니다. 여기서 중요한 두 가지 카테고리는 텍스트를 보이지 않게 만드는 '숨김 코드'와 디스플레이를 지우거나 커서를 이동시켜 정상적인 출력물을 지우거나 덮어쓰는 '화면 및 커서 코드'입니다. 핵심은 렌더링 과정에서 이 바이트들이 사람의 눈에 보이지 않게 숨겨지지만, 모델은 원시 텍스트를 그대로 처리한다는 점입니다. 사람에게는 단순한 빈 줄이나 정리된 보고서로 보이는 것이 에이전트에게는 완전한 지시문 세트로 읽힐 수 있습니다.
공격 1: 직접 패치 (Direct-fetch) AESI 많은 MCP 서버는 URL을 패치(Fetch)하여 모델에 내용을 반환하는 도구, 즉 '이 페이지 요약해 줘' 또는 '이 문서 읽어 줘'와 같은 기능을 노출합니다. 공격은 다음과 같이 작동합니다. 공격자는 자신이 제어하는 URL에 ANSI 이스케이프 시퀀스와 숨겨진 지시문이 섞인 콘텐츠를 호스팅합니다. 해당 URL이 패치 도구의 인자로 제공됩니다. 서버는 콘텐츠를 검색하여 에이전트가 실제로 섭취하는 응답 위치, 즉 '모델 소비 가능 필드(model-consumable field)'로 전달합니다. 모델은 이 숨겨진 지시문을 읽고 이에 따라 행동합니다.
여기서 짚고 넘어가야 할 핵심 개념은 바로 '모델 소비 가능 필드'입니다. MCP 응답의 모든 부분이 모델에 전달되는 것은 아닙니다. 중요한 것은 에이전트가 콘텐츠로 취급하는 특정 필드들입니다.
- 도구 결과: result.content[].text 내부의 텍스트
- 리소스 읽기: result.contents[].text 내부의 텍스트
- 프롬프트 템플릿: result.messages[].content.text 내부의 텍스트
페이로드가 다른 곳에 나타난다면 악용할 수 없습니다. 이는 크로스 프롬프트 인젝션의 한 형태로, 악의적인 지시문이 에이전트가 신뢰하는 데이터에 숨어 들어가는 방식입니다.