
# Laboratório de pesquisa em segurança: reprodução do CVE-2025-61584 (GHSA-9g7x-737f-5xpc) — injeção de comandos via github.head_ref no fluxo de trabalho pull_request_target (.github/workflows/pr.yml)
Artefacto de pesquisa automatizado — não é o projeto original.
Este repositório é um laboratório descartável criado por um harness automatizado para uma tese de mestrado na Université Laval sobre a reprodução de vulnerabilidades publicadas em workflows do GitHub Actions. É um snapshot verbatim de
serverless-dns/serverless-dnsno commitb0b1a1538aeb1991b5bc13dfe4e18e686913b12e(2025-04-26), redistribuído sob a licença do próprio projeto, cujo ficheiro está incluído inalterado neste snapshot.O projeto original não está envolvido, nunca é alvo, e a vulnerabilidade aqui estudada já é pública. Todos os segredos e variáveis neste repositório são valores fictícios gerados aleatoriamente — nenhuma credencial real está presente. Referências a ações e imagens de runners estão fixadas no que resolveram em 2025-04-26; consulte
pinning.mdna saída do harness para todas as alterações feitas ao snapshot.Perguntas ou objeções: [email protected]
serverless-dns é um resolvedor de DNS-over-HTTPS (DoH) e DNS-over-TLS (DoT) stub, serverless e de bloqueio de conteúdo, estilo Pi-Hole. Funciona imediatamente em Cloudflare Workers, , e . Os níveis gratuitos de todos estes serviços devem ser suficientes para cobrir o tráfego de DNS de 10 a 20 dispositivos por mês.
O RethinkDNS executa serverless-dns em produção nestes endpoints:
| Plataforma cloud | Localizações dos servidores | Protocolo | Domínio | Utilização |
|---|---|---|---|---|
| ⛅ Cloudflare Workers | 280+ (ping) | DoH | sky.rethinkdns.com | configurar |
| 🦕 Deno Deploy | 30+ (ping) | DoH | beta privado | |
| ⏱️ Fastly Compute@Edge | 80+ (ping) | DoH | beta privado | |
| 🪂 Fly.io | 30+ (ping) | DoH e DoT | max.rethinkdns.com | configurar |
O processamento no servidor leva de 0 milissegundos (ms) a 2ms (mediana), e a latência de ponta a ponta (varia entre regiões e redes) é entre 10ms e 30ms (mediana).
O resolvedor Rethink DNS no Fly.io é patrocinado pela FOSS United.
O Cloudflare Workers é a plataforma mais fácil para configurar serverless-dns:
Para instruções passo a passo, consulte:
| Plataforma | Dificuldade | Runtime | Documentação |
|---|---|---|---|
| ⛅ Cloudflare | Fácil | v8 Isolates | Hospedagem no Cloudflare Workers |
| 🦕 Deno.com | Moderada | Deno Isolates | Hospedagem no Deno.com |
| ⏱️ Fastly Compute@Edge | Fácil | Fastly JS | Hospedagem no Fastly Compute@Edge |
| 🪂 Fly.io | Difícil | Node MicroVM | Hospedagem no Fly.io |
Para configurar listas de bloqueio, visite https://<my-domain>.tld/configure no seu navegador (deve carregar algo semelhante à página de configuração do RethinkDNS).
Para ajuda ou assistência, sinta-se à vontade para abrir uma issue ou submeter um patch.
Código:
# navigate to work dir
cd /my/work/dir
# clone this repository
git clone https://github.com/serverless-dns/serverless-dns.git
# navigate to serverless-dns
cd ./serverless-dns
Node:
# install node v22+ via nvm, if required
# https://github.com/nvm-sh/nvm#installing-and-updating
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install --lts
# download dependencies
npm i
# (optional) update dependencies
npm update
# run serverless-dns on node
./run n
# run a clinicjs.org profiler
./run n [cpu|fn|mem]
Deno:
# install deno.land v2+
# https://github.com/denoland/deno/#install
curl -fsSL https://deno.land/install.sh | sh
# run serverless-dns on deno
./run d
Fastly:
# install node v22+ via nvm, if required
# install the Fastly CLI
# https://developer.fastly.com/learning/tools/cli
# run serverless-dns on Fastly Compute@Edge
./run f
Wrangler:
# install Cloudflare Workers (cli) aka Wrangler
# https://developers.cloudflare.com/workers/cli-wrangler/install-update
npm i wrangler --save-dev
# run serverless-dns on Cloudflare Workers (cli)
# Make sure to setup Wrangler first:
# https://developers.cloudflare.com/workers/cli-wrangler/authentication
./run w
# profile wrangler with Chrome DevTools
# blog.cloudflare.com/profiling-your-workers-with-wrangler
Os commits neste repositório aplicam o guia de estilo JavaScript do Google (ref: .eslintrc.cjs).
Um hook git pre-commit executa o linter (eslint) e o formatador (prettier) em ficheiros .js. Use git commit --no-verify
para contornar este hook.
Os pull requests também são verificados quanto a violações de estilo de código e corrigidos automaticamente quando possível.
Configure env.js se precisar de ajustar os padrões.
Para Cloudflare Workers, configure as variáveis de ambiente em wrangler.toml, em vez disso.
Para Fastly Compute@Edge, configure as variáveis de ambiente em fastly.toml, em vez disso.
O serverless-dns suporta autenticação com um token de portador alfanumérico tanto para DoH como para DoT. Para um token, msg-key (segredo), anexe a saída de hex(hmac-sha256(msg-key|domain.tld), msg) à variável de ambiente ACCESS_KEYS em formato csv. Nota: msg está atualmente fixado em sdns-public-auth-info.
msg-key no final do blockstamp, assim:
1:1:4AIggAABEGAgAA:<msg-key> (aqui, 1 é a versão, 1:4AIggAABEGAgAA
é o blockstamp, <msg-key> é o segredo de autenticação, e : é o delimitador).msg-key no final do SNI (nome de domínio) que contém o blockstamp:
1-4abcbaaaaeigaiaa-<msg-key> (aqui 1 é a versão, 4abcbaaaaeigaiaa
é o blockstamp, <msg-key> é o segredo de autenticação, e - é o delimitador).Se a intenção for usar autenticação também com DoT, mantenha o msg-key mais curto (8 a 24 caracteres), pois os subdomínios podem ter apenas 63 caracteres no total.
Pode gerar as chaves de acesso para o seu fork a partir de max.rethinkdns.com, assim:
msgkey="ShortAlphanumericSecret"
domain="my-serverless-dns-domain.tld"
curl 'https://max.rethinkdns.com/genaccesskey?key='"$msgkey"'&dom='"$domain"
# output
# {"accesskey":["my-serverless-dns-domain.tld|deadbeefd3adb33fa2bb33fd3eadf084beef3b152beefdead49bbb2b33fdead83d3adbeefdeadb33f"],"context":"sdns-public-auth-info"}
O serverless-dns pode ser configurado para carregar registos via Cloudflare Logpush.
CF_ACCOUNT_ID=<hex-cloudflare-account-id>
CF_API_KEY=<api-key-with-logs-edit-permission-at-account-level>
R2_BUCKET=<r2-bucket-name>
R2_ACCESS_KEY=<r2-access-key-for-the-bucket>
R2_SECRET_KEY=<r2-secret-key-with-read-write-permissions>
# optional, setup a filter such that only logs form this worker ends up being pushed; but if you
# do not need a filter on Worker name (script-name), edit the "filter" field below accordingly.
SCRIPT_NAME=<name-of-the-worker-as-in-wrangler-toml>
# for more options, ref: developers.cloudflare.com/logs/get-started/api-configuration
# Logpush API with cURL: developers.cloudflare.com/logs/tutorials/examples/example-logpush-curl
# Available Logpull fields: developers.cloudflare.com/logs/reference/log-fields/account/workers_trace_events
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/logpush/jobs" \
-H "Authorization: Bearer ${CF_API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"name": "dns-logpush",
"logpull_options": "fields=EventTimestampMs,Outcome,Logs,ScriptName×tamps=rfc3339",
"destination_conf": "r2://'"$R2_BUCKET"'/{DATE}?access-key-id='"${R2_ACCESS_KEY}"'&secret-access-key='"${R2_SECRET_KEY}"'&account-id='"{$CF_ACCOUNT_ID}"',
"dataset": "workers_trace_events",
"filter": "{\"where\":{\"and\":[{\"key\":\"ScriptName\",\"operator\":\"contains\",\"value\":\"'"${SCRIPT_NAME}"'\"},{\"key\":\"Outcome\",\"operator\":\"eq\",\"value\":\"ok\"}]}}",
"enabled": true,
"frequency": "low"
}'
logpush = true em wrangler.toml, o que ativa o Logpush.LOG_LEVEL = "logpush", que aumenta o nível de registo para que apenas os registos de pedidos e erros sejam emitidos.LOGPUSH_SRC = "csv,of,subdomains", que faz com que log-pusher.js emita registos de pedidos apenas se o hostname dos Workers contiver um dos subdomínios.Os registos publicados no R2 podem ser recuperados usando R2 Workers, a API R2, ou a API Logpush.
O Workers Analytics, se ativado, é enviado contra uma chave de registo, lid, que, se não for especificada, é definida como o hostname da implementação serverless com os pontos, ., substituídos por underscores, _. A autenticação deve ser configurada ao consultar o Analytics via API, que retorna um json; ex: https://max.rethinkdns.com/1:<optional-stamp>:<msg-key>/analytics?t=<time-interval-in-mins>&f=<field-name>. Os fields possíveis são ip (ip do cliente), qname (nome da consulta DNS), region (região do resolvedor), qtype (tipo de consulta DNS), dom (domínios de topo), ansip (ips de resposta DNS) e cc (códigos de país dos ips de resposta).
A captura de registos e analytics ainda não está implementada para Fly e Deno Deploy.
O Deno Deploy (cloud) e o Deno (o runtime) não expõem a mesma superfície de API (por exemplo, o Deno Deploy apenas suporta listeners de servidor HTTP/S; enquanto o Deno suporta TCP/UDP/TLS brutos, além de HTTP simples e HTTP/S).
Exceto no Node, serverless-dns usa upstreams DoH definidos por variáveis de ambiente, CF_DNS_RESOLVER_URL / CF_DNS_RESOLVER_URL_2.
No Node, o upstream DNS padrão é 1.1.1.2 (ref) ou o resolvedor DNS recursivo em fdaa::3 quando executa no Fly.io.
Os pontos de entrada para Node e Deno são src/server-node.js, src/server-deno.ts respetivamente,
e ambos escutam conexões TCP-over-TLS, HTTP/S; enquanto o ponto de entrada para Cloudflare Workers, que apenas escuta HTTP (cli) ou
HTTP/S (prod), é src/server-workers.js; e para Fastly é src/server-fastly.js.
Em configurações locais (não-prod) no Node, os ficheiros key (privada) e cert (cadeia pública), por padrão, são lidos de
caminhos definidos em variáveis de ambiente, TLS_KEY_PATH e TLS_CRT_PATH.
Enquanto para configurações de prod no Node (no Fly.io), ou TLS_OFFLOAD deve ser definido como true ou key e cert devem ser
codificados em base64 na variável de ambiente TLS_CERTKEY (ref), assim:
# EITHER: offload tls to fly.io and set tls_offload to true
TLS_OFFLOAD="true"
# OR: base64 representation of both key (private) and cert (public chain)
TLS_CERTKEY="KEY=b64_key_content\nCRT=b64_cert_content"
Para Deno, os ficheiros key e cert são lidos de caminhos definidos em variáveis de ambiente, TLS_KEY_PATH e TLS_CRT_PATH (ref).
O arranque do processo é diferente para cada um destes runtimes: Para Node, src/core/node/config.js governa o arranque;
enquanto para Deno, é src/core/deno/config.ts, e para Workers é src/core/workers/config.js.
O pub-sub de src/system.js coordena a fase de arranque entre vários módulos.
No Node e Deno, o cache DNS em processo é suportado por @serverless-dns/lfu-cache; o Cloudflare Workers é suportado tanto pela Cache Web API como
por caches lfu em processo. Para desativar completamente o cache nas três plataformas, defina a variável de ambiente PROFILE_DNS_RESOLVES=true.
O Cloudflare Workers e o Deno Deploy são efémeros, ou seja, o "processo" que atende pedidos de clientes não é de longa duração, e, de facto, dois pedidos consecutivos podem ser atendidos por dois isolates ("processos") diferentes. O Fastly Compute@Edge também é efémero, mas não usa isolates; em vez disso, o Fastly cria e destrói uma sandbox wasmtime para cada pedido. O resolvedor no Fly.io, que executa Node, é suportado por VMs persistentes e, portanto, tem maior longevidade, como ambientes tradicionais "serverfull".
Para Deno Deploy, o código é empacotado num único ficheiro javascript com deno bundle e depois entregue
ao Deno.com.
As configurações de tempo de compilação e de execução do Cloudflare Workers são definidas em wrangler.toml.
O Webpack5 agrupa os ficheiros num módulo ESM que é depois carregado para o Cloudflare pelo Wrangler.
As configurações de tempo de compilação e de execução do Fastly Compute@Edge são definidas em fastly.toml.
O Webpack5 agrupa os ficheiros num módulo ESM que é depois compilado para WASM por npx js-compute-runtime
e subsequentemente empacotado e publicado no Fastly Compute@Edge com a Fastly CLI.
Para Fly.io, que executa Node, as diretivas de execução são definidas em fly.toml (usado pelos tipos de implementação dev e live),
enquanto as diretivas de implementação estão em node.Dockerfile. O flyctl configura
adequadamente o serverless-dns na infraestrutura do Fly.io.
# build and deploy for cloudflare workers.dev
npm run build
# usually, env-name is prod
npx wrangler publish [-e <env-name>]
# bundle, build, and deploy for fastly compute@edge
# developer.fastly.com/reference/cli/compute/publish
fastly compute publish
# build and deploy to fly.io
npm run build:fly
flyctl deploy --dockerfile node.Dockerfile --config <fly.toml> [-a <app-name>] [--image-label <some-uniq-label>]
Para implementações que descarregam a terminação TLS para o Fly.io (tipo de implementação B1), as diretivas de execução são, em vez disso, definidas em
fly.tls.toml, que configura HTTP2 Cleartext e HTTP/1.1 na porta 443, e DNS sobre TCP na porta 853.
Ref: github/workflows.
190+ listas de bloqueio são comprimidas numa Succinct Radix Trie (baseada na impl de Steve Hanov) com modificações
para acelerar a pesquisa de strings (lookup) à custa da "succintness". As listas de bloqueio são versionadas
com timestamp unix (definido em src/basicconfig.json descarregado por pre.sh), que é gerado uma vez por semana, mas gostaríamos de gerá-las diariamente / de hora em hora,
se possível ver), e hospedadas no Cloudflare R2 (variável de ambiente: CF_BLOCKLIST_URL).
O serverless-dns descarrega 3 ficheiros de listas de bloqueio
necessários para configurar a radix-trie durante o arranque do runtime ou descarrega-os lazily,
ao atender um pedido DNS.
O serverless-dns compila cerca de ~13M entradas (desde jan 2023) de cerca de 190+ listas de bloqueio. Estas são definidas no repositório serverless-dns/blocklists.