flawopen.com/Teardowns/cve-2026-90970-gitlab-ai-gateway-prompt-template-sandbox-escape
CVE-2026-90970: GitLab AI Gateway 프롬프트 샌드박스 탈출
특수하게 구성한 Duo Agent Platform 흐름이 AI Gateway의 프롬프트 템플릿 샌드박스를 벗어나 명령을 실행할 수 있었습니다. 자체 호스팅 운영자는 해당 GitLab 계열의 수정 버전으로 업데이트해야 합니다.[1], [4]
대화 기록을 바탕으로 보고서를 작성하는 담당자를 떠올려 보세요. 허용된 항목은 일반 텍스트로 옮겨 적어야 합니다. 하지만 특수하게 만든 템플릿은 기록의 ‘복원’ 기능을 사용하게 해 저장된 데이터에서 앱이 활성 객체를 다시 만들도록 할 수 있었습니다. 단어를 복사하는 것과 앱에 데이터를 해석시키는 것 사이의 경계를 넘은 셈입니다. 연구자 보고서에는 parse_raw()와 pickle을 이용한 구체적 경로가 기록돼 있습니다. GitLab 권고문은 샌드박스 탈출과 명령 실행 영향을 확인하지만 모든 단계를 공개하지는 않습니다.[3], [6]
핵심 개념 및 용어
프레임워크 매핑
- 이 가이드에서 설명하는 약점의 CWE 참조: CWE-1336
근본 원인 분석 (Root Cause)
GitLab 권고문은 특정 조건에서 Duo Agent Platform 접근 권한이 있는 인증 사용자가 특수 흐름 설정으로 프롬프트 템플릿 샌드박스를 벗어나 AI Gateway에서 임의 명령을 실행할 수 있었다고 확인합니다. CWE-1336, CVSS 9.9입니다. 권고문은 모든 조건이나 취약 함수를 밝히지 않습니다. 2026-09-17 공개 커밋은 PromptSandboxedEnvironment를 추가해 바인딩 객체의 메서드 접근을 막고 Jinja 연산 및 필터를 강화합니다. 런타임 객체에 대한 템플릿 동작을 제한하는 것과 맞지만 커밋은 이 CVE를 언급하지 않고 공개 자료는 수정 이미지와 연결하지 않습니다. 이를 별도의 공개 보안 강화로 설명하세요. 공개 자료는 이 CVE나 수정 이미지와 연결하지 않습니다. GitLab 공개 작업 항목 #1850은 더 구체적인 경로를 설명합니다. Jinja 템플릿이 대화 기록의 LangChain HumanMessage에 parse_raw()를 호출해 pickle 역직렬화를 실행합니다. 이 작업 항목은 연구자 보고에 따른 시연이며 GitLab 스테이징 환경에서 이뤄졌다고 설명합니다. 벤더 권고는 영향을 받는 모든 조건을 밝히지 않습니다.[1], [3], [4], [2]
자체 호스팅 AI Gateway 수정 릴리스 표
| 배포 / 릴리스 계열 | 수정된 AI Gateway 릴리스 | 운영자 조치 |
|---|---|---|
| 자체 호스팅 GitLab 19.2 계열 | 19.2.4 | 해당 자체 호스팅 Gateway 이미지 태그로 업그레이드하고 배포된 이미지를 확인하세요. |
| 자체 호스팅 GitLab 19.3 계열 | 19.3.2 | 해당 자체 호스팅 Gateway 이미지 태그로 업그레이드하고 배포된 이미지를 확인하세요. |
| 자체 호스팅 GitLab 19.4 계열 | 19.4.1 | 해당 자체 호스팅 Gateway 이미지 태그로 업그레이드하고 배포된 이미지를 확인하세요. |
| GitLab 호스팅 AI Gateway | GitLab은 이미 수정됐다고 밝혔습니다. | GitLab 호스팅 Gateway를 사용하는지 확인하세요. 이 경우 자체 호스팅 이미지 안내를 적용하지 마세요. |
단계별 공격 실행 흐름
템플릿 실행이 샌드박스 경계를 넘음
GitLab 공개 작업 항목 #1850은 템플릿이 대화 기록의 LangChain HumanMessage에 parse_raw()를 호출해 pickle 역직렬화를 실행할 수 있었다고 보고합니다. 연구자가 기록한 경로이므로 모든 영향받는 flow나 벤더 패치를 완전히 설명한다고 추론하지 마세요.[3]
소스 코드 비교: 취약한 구현 vs 보안 패치
GitLab 작업 항목 1850은 취약한 flow가 LangChain HumanMessage 객체를 Jinja에 전달해 템플릿에서 parse_raw()를 호출하고 pickle 역직렬화를 실행할 수 있었다고 보고합니다. 이 방어 예제는 메시지 객체를 템플릿 컨텍스트에서 제외하고 텍스트만 전달하며 호출 가능한 속성과 메서드 접근을 거부합니다. 닫아야 할 경계를 보여주는 예시이며 GitLab이 배포한 패치가 아닙니다. 공개 커밋 89b72644는 별도의 보안 변경입니다. 실제 제목은 Jinja block-set 쓰기를 다루며, 공개 자료는 이를 CVE-2026-90970이나 수정 이미지와 연결하지 않습니다. 운영자는 벤더가 지정한 수정 릴리스를 적용해야 합니다.[3], [2], [6]
소스 코드 발췌: ai_gateway/prompts/base.py (보고된 취약 포매터; 방어 예시)
# GitLab 작업 항목 1850에서 보고된 취약 경로의 일부입니다.
from jinja2 import PackageLoader
from jinja2.sandbox import SandboxedEnvironment
from langchain_core.prompts.string import DEFAULT_FORMATTER_MAPPING
from typing import Any
jinja_loader = PackageLoader("ai_gateway.prompts", "definitions")
jinja_env = SandboxedEnvironment(loader=jinja_loader)
def jinja2_formatter(template: str, /, **kwargs: Any) -> str:
return jinja_env.from_string(template).render(**kwargs)
DEFAULT_FORMATTER_MAPPING["jinja2"] = jinja2_formatter
# 방어 패턴을 보여 주는 예시이며, 해당 CVE에 대한 GitLab 패치가 아닙니다.
from typing import Any
from jinja2 import StrictUndefined
from jinja2.sandbox import ImmutableSandboxedEnvironment
class DataOnlyPromptEnvironment(ImmutableSandboxedEnvironment):
def is_safe_attribute(self, obj: Any, attr: str, value: Any) -> bool:
if callable(value):
return False
return super().is_safe_attribute(obj, attr, value)
def is_safe_callable(self, obj: Any) -> bool:
return False
def render_prompt(template: str, history: list[Any]) -> str:
safe_history = []
for message in history:
content = message.content
if not isinstance(content, str):
raise TypeError("prompt history must contain text only")
safe_history.append({"content": content})
env = DataOnlyPromptEnvironment(undefined=StrictUndefined)
return env.from_string(template).render(history=safe_history)
엔지니어링 및 시스템 보안 강화 체크리스트
- ✓자체 호스팅 AI Gateway를 해당 GitLab 계열의 19.2.4, 19.3.2 또는 19.4.1로 업데이트하고 설치 안내의 이미지 태그를 사용하세요.[1], [5]
- ✓Gateway가 자체 호스팅인지 GitLab 호스팅인지 확인하세요. GitLab.com, GitLab Dedicated 및 GitLab 호스팅 Gateway 이용 인스턴스는 이미 수정되었습니다.[1]
- ✓애플리케이션의 살아 있는 객체를 받는 템플릿에서 샌드박스를 완전한 격리로 간주하지 마세요.[6]
- ✓비활성 데이터만 전달하고 메서드, 역직렬화기, 파일/프로세스 핸들 및 서비스 객체는 컨텍스트에서 제외하세요.[6], [2]
- ✓속성과 호출을 제한하고 메서드를 직접 부르는 내장 필터를 점검하며 운영 Jinja 버전과 설정을 테스트하세요.[3], [2], [6]
- ✓안전하지 않은 객체 연산을 거부하고 문자열 렌더링은 유지하는 테스트를 추가하세요. 실제 명령 payload는 사용하지 마세요.[3], [6]
- ✓권고문만으로 공개 악용 캠페인이나 완전한 공격 경로를 추론하지 마세요. NVD에는 2026-10-02 CISA Coordinator SSVC 평가가 “exploitation: none”으로 기록돼 있습니다. 이는 해당 날짜의 상태이며 이후 활동에 대한 주장은 아닙니다.[1], [4]
출처
- GitLab AI Gateway Critical Patch Release: 19.2.4, 19.3.2, and 19.4.1
- GitLab 커밋 89b72644 — 별도 보안 강화이며 CVE와의 연결은 확인되지 않음: “fix(prompts): block Jinja block-set NSRef writes on non-namespace objects”
- GitLab AI Gateway work item 1850 (reporter account; reproduction material omitted)
- NVD: CVE-2026-90970
- GitLab Self-Hosted AI Gateway installation guide
- Jinja 3.1 Sandbox documentation