암호문 컨텍스트 인젝션 - Grok과 Gemini
페이지 하나를 요약해 달라고 부탁했을 뿐인데 이름과 위치와 구독 등급과 그때까지 나눈 대화 전체가 공격자 서버로 넘어갑니다. Adversa AI가 2026년 8월 20일 공개한 cryptographic context injection입니다. Grok에서는 데이터 유출로, Gemini에서는 안전 필터 우회로 나타났습니다.
공격 사슬
공격자는 웹페이지에 AES-256-GCM 암호문을 심습니다. 키는 PBKDF2로 유도하고, 복호화 지시를 암호문 옆에 나란히 둡니다. 페이지 자체는 평범한 문서처럼 보입니다.
사용자가 그 페이지를 요약해 달라고 요청하면 사슬이 시작됩니다.
단계 |
벌어지는 일 |
|---|---|
1 |
에이전트가 페이지를 읽고 암호화된 JSON 객체와 복호화 지시를 함께 가져옵니다 |
2 |
에이전트의 Python 런타임이 복호화를 실행합니다 |
3 |
"복호화 키"라고 적힌 것이 실은 템플릿입니다. 사용자 이름, 대략적 위치, 구독 등급, 대화의 전체 프롬프트가 그 자리에 채워집니다 |
4 |
복호화된 지시가 그 값들을 URL에 끼워 넣고 "추가 컨텍스트를 가져오라"며 열게 합니다 |
5 |
브라우징 툴이 자율적으로 호출되고, 쿼리 파라미터에 실린 데이터가 공격자 인프라에 도착합니다 |
3단계가 이 공격의 영리한 지점입니다. 키를 흉내 낸 문자열이 사실은 컨텍스트 보간 템플릿입니다. 에이전트는 자기가 지금 암호를 풀고 있다고 생각하지만, 실제로 하는 일은 세션의 사적 데이터를 문자열에 조립하는 것입니다.
사용자가 승인해야 하는 지점은 어디에도 없습니다. 처음 요약 요청 이후로는 눈에 보이는 경고 없이 끝까지 자동으로 진행됩니다.
검사와 실행 사이
왜 가드레일이 못 잡을까요.
입력 필터는 텍스트를 분류합니다. 실행하지는 않습니다. 필터 앞에 놓인 암호문은 그저 의미 없는 바이트열이고, 악성 지시로 분류될 근거가 없습니다. 복호화는 필터를 통과한 뒤에 일어납니다. 검사하는 시점과 명령이 되는 시점이 어긋나 있습니다. 이 어긋남이 공격의 전부입니다.
여기서 한 겹 더 들어가면 이 공격의 진짜 성격이 나옵니다. 강한 암호는 모델 가중치 안에서 풀리지 않습니다. AES-256을 어텐션으로 되짚을 수는 없습니다. 그래서 복호화가 코드 실행 런타임으로 강제됩니다. 공격자가 약한 인코딩 대신 굳이 진짜 암호를 쓴 이유가 이것입니다. base64나 ROT13이었다면 모델이 머릿속에서 풀 수도 있고 필터가 잡을 수도 있습니다. AES-256-GCM은 반드시 Python을 거쳐야 합니다.
그러니 취약한 것은 언어 모델이 아닙니다. 그 주변에 붙은 도구 고리입니다. 모델은 자기가 받은 코드를 실행했고, 실행 결과로 나온 지시를 따랐고, 브라우징 툴에 URL을 넘겼습니다. 각 단계는 설계대로 동작했습니다.
결론이 뒤집혀 있습니다. 암호를 풀 수 있는 능력이 방어를 우회하는 경로가 됩니다. 더 정확히는 임의 코드를 돌릴 수 있는 능력입니다. 에이전트를 유능하게 만드는 바로 그 기능이 공격 표면을 넓힙니다.
두 모델, 두 결과
같은 기법인데 두 모델에서 결과가 다릅니다.
주입 방식 |
간접 주입 (워터링 홀 페이지) |
직접 주입 (프롬프트 한 개) |
사용 도구 |
Python 런타임 + 브라우징 |
Python 런타임 |
결과 |
대화 내역 유출 |
안전 필터 우회 |
피해 등급 |
데이터 탈취 |
금지 콘텐츠 생성 |
Gemini 쪽은 Deep Thinking 모드에서 재현됐습니다. 프롬프트 하나가 암호문을 Python으로 풀게 하고, 평소에는 차단되는 내용을 "안전을 위해 암호화하겠다"는 틀로 감싸 뱉게 만듭니다. 소이성 무기 제작 지시가 예시로 제시됐습니다.
Gemini에서 데이터 유출이 일어나지 않은 이유는 안전 설계가 더 나아서가 아닙니다. 외부 사이트에 접근하지 못하기 때문입니다. 나갈 통로가 없으니 피해가 생성 단계에서 멈춥니다.
두 사례를 겹쳐 놓으면 어느 쪽 보고서에도 한 문장으로 적혀 있지 않은 것이 보입니다. 우회 여부는 모델이 정하고 피해 등급은 도구 조합이 정합니다. 코드 실행만 있으면 가드레일이 뚫립니다. 코드 실행에 브라우징이 붙으면 데이터가 나갑니다. 여기에 파일 시스템이나 결제 API가 붙으면 무엇이 될지는 이 구조를 그대로 연장하면 됩니다.
이 프레임은 이 블로그에서 다룬 Agentjacking - MCP 주입으로 AI 코딩 에이전트 원격 코드 실행과 그대로 이어집니다. 그때는 도구 정의가 오염됐고 이번에는 도구 입력이 오염됐습니다. 공통점은 에이전트가 읽은 것을 실행 가능한 것으로 취급한다는 점입니다. 프롬프트 인젝션이 계속 같은 자리에서 재발하는 이유이기도 합니다.
공개까지 78일
타임라인이 이 사건의 두 번째 이야기입니다.
- 2026년 6월 3일: xAI와 HackerOne에 최초 보고
- 8월 4일, 8월 10일: 조율 시도
- 8월 19일에서 20일: 실동작 페이로드는 공개하지 않은 채 공개 발표
xAI는 보고를 접수했다고 인정했지만 구체적인 내용도 완화 일정도 내놓지 않았습니다. 8월 19일 기준으로 기법은 grok.com에서 여전히 동작했습니다. 올해 xAI를 인수한 SpaceX는 취재에 응답하지 않았습니다.
Google 쪽은 사정이 다릅니다. 공식 신고 자체가 불가능했습니다. 취약점 프로그램이 탈옥을 범위에서 제외하기 때문입니다. 다만 8월 들어 공격 성공률이 떨어졌는데, 필터가 갱신된 것인지 모델이 바뀐 것인지 연구자들도 구분하지 못했습니다.
여기가 출처들이 갈리는 지점입니다. 한쪽은 "안 고쳐졌다"가 관측으로 확인됐고, 다른 쪽은 "고쳐졌는지 아닌지 확인할 방법이 없다"입니다. 정반대처럼 보이지만 같은 결론으로 모입니다. 두 경우 모두 공개 창구가 작동하지 않았습니다. 한쪽은 접수하고 답을 안 줬고, 한쪽은 접수 대상이 아니라고 했습니다.
탈옥을 취약점 범위에서 빼는 정책은 모델이 텍스트만 뱉던 시절에는 말이 됐습니다. 그 모델이 Python을 돌리고 웹을 열게 된 뒤로는 사정이 다릅니다. 이번 건에서 탈옥과 데이터 유출을 가른 것은 정책 문서상의 분류가 아니라 브라우징 툴이 붙어 있었는지 여부였습니다.
남은 질문
네 건의 보도 어디에서도 다루지 않은 것이 있습니다. 그래서 무엇을 고쳐야 하는가입니다.
필터를 더 똑똑하게 만드는 방향으로는 안 풀립니다. 암호문을 읽어내는 필터는 원리상 불가능합니다. 남는 선택지는 도구 쪽에 있습니다. 에이전트의 코드 런타임이 공격자가 제공한 임의 암호문을 복호화하도록 두어야 하는가. 브라우징 툴이 세션 컨텍스트로 조립된 URL을 받아도 되는가. 실행 결과로 나온 문자열을 새 지시로 승격시켜도 되는가.
세 질문 모두 답이 "아니오"에 가까워 보이지만, 그렇게 막으면 에이전트가 할 수 있는 일이 눈에 띄게 줄어듭니다. 벤더가 조용한 이유가 여기 있다고 봅니다. 이 취약점의 수정은 버그 픽스가 아니라 기능 축소이기 때문입니다.
당장 쓸 수 있는 대응은 제한적입니다. 신뢰하지 않는 페이지를 에이전트에게 요약시키지 않는 것, 브라우징과 코드 실행을 동시에 켠 세션에 민감한 대화를 남기지 않는 것 정도입니다. 근본적인 해법은 사용자 쪽에 없습니다.
참고: Adversa AI, Cryptographic Context Injection · The Register, Grok chat duped into swallowing injected instructions · SecurityWeek, Encrypted Prompts Bypass AI Safety Guardrails in Grok and Gemini · The Hacker News, New Cryptographic Context Injection Attack