FlawOpen

flawopen.com/Teardowns/cve-2026-90970-gitlab-ai-gateway-prompt-template-sandbox-escape

● CVE-2026-90970 · CVSS 9.9[4] · Crítica
Pesquisa · FlawOpen

CVE-2026-90970: escape do sandbox de prompts do GitLab AI Gateway

Um fluxo especialmente elaborado do Duo Agent Platform podia escapar do sandbox de templates de prompt do AI Gateway e executar comandos. Operadores de Gateway próprio devem atualizar para a versão corrigida da linha GitLab correspondente.[1], [4]

Vetor CVSSCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H[4]
💡 Explicação em Linguagem Simples (ELI5)

Imagine uma pessoa preenchendo um formulário com base em registros de conversa. Ela deve copiar os campos aprovados como texto. Um template especialmente criado podia mandar essa pessoa usar o comando “restaurar” do arquivo, fazendo o aplicativo reconstruir objetos ativos a partir dos dados armazenados, em vez de apenas copiar palavras. Assim, o limite entre exibir dados e pedir ao aplicativo que os interprete era ultrapassado. O relato do pesquisador documenta o caminho específico com parse_raw() e pickle; o aviso do GitLab confirma a saída do sandbox e a execução de comandos, mas não descreve todas as etapas.[3], [6]

Conceitos Centrais e Termos

AI Gateway
Serviço GitLab que conecta recursos de IA a provedores de modelos; instalações próprias têm uma imagem Gateway com versão separada.[5], [1]
Prompt template
Template que combina instruções fixas com valores de runtime, como entradas do fluxo e contexto da conversa.[3], [6]
Sandbox escape
Uso de um comportamento disponível em ambiente restrito para atravessar o limite que ele deveria impor.[3], [6]
CWE-1336
Neutralização inadequada de elementos especiais de um mecanismo de templates; o registro CVE atribui esta fraqueza.[4], [1]

Mapeamentos de frameworks

  • Referência CWE para a fraqueza descrita neste guia: CWE-1336

Análise de Causa Raiz

O aviso do GitLab confirma que, em certas condições, uma pessoa autenticada com acesso ao Duo Agent Platform podia usar uma configuração especial de fluxo para escapar do sandbox de templates de prompt e executar comandos arbitrários no AI Gateway. O problema é CWE-1336, CVSS 9.9. O aviso não detalha todas as condições nem a função vulnerável. Um commit público de 17/09/2026 adiciona PromptSandboxedEnvironment, descrito como impedindo o acesso a métodos em objetos vinculados, e reforça operações e filtros Jinja. Isso é coerente com limitar o que templates fazem com objetos de runtime, mas o commit não cita o CVE e as fontes públicas consultadas não o vinculam às imagens corrigidas. Trate-o como uma alteração pública de reforço separada; nenhuma fonte pública o vincula a este CVE ou às imagens corrigidas. O item público do GitLab nº 1850 descreve um caminho mais específico: um template Jinja chama parse_raw() em um HumanMessage do LangChain presente no histórico da conversa, acionando a desserialização pickle. O item atribui essa demonstração ao relato do pesquisador e informa que ela ocorreu no ambiente de staging do GitLab; o aviso do fornecedor não detalha todas as condições afetadas.[1], [3], [4], [2]

Matriz de versões corrigidas do AI Gateway auto-hospedado

Implantação / linha de versãoVersão corrigida do AI GatewayAção do operador
GitLab auto-hospedado, linha 19.219.2.4Atualize para a tag correspondente da imagem auto-hospedada do Gateway e verifique a imagem implantada.
GitLab auto-hospedado, linha 19.319.3.2Atualize para a tag correspondente da imagem auto-hospedada do Gateway e verifique a imagem implantada.
GitLab auto-hospedado, linha 19.419.4.1Atualize para a tag correspondente da imagem auto-hospedada do Gateway e verifique a imagem implantada.
AI Gateway hospedado pelo GitLabO GitLab afirma que já estava corrigido.Confirme que a implantação usa o Gateway hospedado pelo GitLab; não aplique a orientação de imagem auto-hospedada a este caso.

Fluxo de Ataque Passo a Paso

Passo 1

Uma pessoa pode configurar um fluxo personalizado

O aviso exige uma pessoa autenticada com acesso ao Duo Agent Platform. Não informa papel mais específico nem todas as capacidades necessárias.[1], [3]

Passo 2

O fluxo entrega uma configuração especial de template

Uma configuração especial alcança o sandbox de templates de prompt. O aviso público não publica reprodução completa e segura nem a expressão exata do template.[1], [3]

Passo 3

A execução do template cruza a fronteira do sandbox

O item público do GitLab nº 1850 relata que um template podia chamar parse_raw() em um HumanMessage do LangChain no histórico da conversa, acionando a desserialização pickle. Esse é o caminho documentado pelo pesquisador; não presuma que cobre todos os fluxos afetados nem que corresponde ao patch do fornecedor.[3]

Passo 4

Comandos podem ser executados no Gateway

O impacto confirmado é execução de comandos arbitrários no AI Gateway, no servidor, não apenas uma falha do modelo ao seguir instruções.[1], [3]

Código-Fonte: Vulnerável vs. Seguro

O item 1850 do GitLab relata que o fluxo vulnerável expunha um objeto HumanMessage do LangChain ao Jinja, onde um template podia chamar parse_raw() e acionar a desserialização pickle. Este exemplo defensivo mantém objetos de mensagem fora do contexto do template, fornece somente texto e nega acesso a atributos chamáveis e métodos. Ele ilustra o limite que deve ser fechado; não é o patch lançado pelo GitLab. O commit público 89b72644 é uma alteração de segurança separada: seu título trata de gravações Jinja block-set, e nenhuma fonte pública o vincula à CVE-2026-90970 ou às imagens corrigidas. Operadores devem seguir as versões corrigidas indicadas pelo fornecedor.[3], [2], [6]

Trecho de origem: ai_gateway/prompts/base.py (formatador vulnerável relatado; defesa ilustrativa)

IMPLEMENTAÇÃO VULNERÁVEL
# Trecho do caminho vulnerável relatado no item de trabalho 1850 do GitLab.
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
PATCH SEGURO E ROBUSTO
# Padrão de defesa ilustrativo; não é o patch do GitLab para este CVE.
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)

Lista de Verificação de Segurança para Engenharia

Fontes