
Laboratoire de recherche en sécurité : reproduction de CVE-2025-61584 (GHSA-9g7x-737f-5xpc) — injection de commande via github.head_ref dans le workflow pull_request_target (.github/workflows/pr.yml)
Artéfact de recherche automatisé — pas le projet en amont.
Ce dépôt est un laboratoire jetable construit par un harnais automatisé pour un mémoire de maîtrise à l'Université Laval sur la reproduction de vulnérabilités publiées dans les workflows GitHub Actions. Il s'agit d'un instantané verbatim de
serverless-dns/serverless-dnsau commitb0b1a1538aeb1991b5bc13dfe4e18e686913b12e(2025-04-26), redistribué sous la licence propre de ce projet, dont le fichier est inclus inchangé dans cet instantané.Le projet en amont n'est pas impliqué, n'est jamais ciblé, et la vulnérabilité étudiée ici est déjà publique. Chaque secret et variable dans ce dépôt est une valeur factice générée aléatoirement — aucune information d'identification réelle n'est présente. Les références d'actions et les images d'exécuteurs sont épinglées à ce qu'elles résolvaient au 2025-04-26 ; voir
pinning.mddans la sortie du harnais pour chaque modification apportée à l'instantané.Questions ou objections : [email protected]
serverless-dns est un résolveur DNS-over-HTTPS (DoH) et DNS-over-TLS (DoT) stub, sans serveur, de type Pi-Hole, avec blocage de contenu. Fonctionne prêt à l'emploi sur , , , et . Les niveaux gratuits de tous ces services devraient suffire à couvrir le trafic DNS de 10 à 20 appareils par mois.
RethinkDNS exécute serverless-dns en production à ces points de terminaison :
| Plateforme cloud | Emplacements des serveurs | Protocole | Domaine | Utilisation |
|---|---|---|---|---|
| ⛅ Cloudflare Workers | 280+ (ping) | DoH | sky.rethinkdns.com | configurer |
| 🦕 Deno Deploy | 30+ (ping) | DoH | bêta privée | |
| ⏱️ Fastly Compute@Edge | 80+ (ping) | DoH | bêta privée | |
| 🪂 Fly.io | 30+ (ping) | DoH et DoT | max.rethinkdns.com | configurer |
Le traitement côté serveur prend de 0 milliseconde (ms) à 2 ms (médiane), et la latence de bout en bout (varie selon les régions et les réseaux) est entre 10 ms et 30 ms (médiane).
Le résolveur Rethink DNS sur Fly.io est sponsorisé par FOSS United.
Cloudflare Workers est la plateforme la plus simple pour configurer serverless-dns :
Pour des instructions étape par étape, référez-vous à :
| Plateforme | Difficulté | Runtime | Doc |
|---|---|---|---|
| ⛅ Cloudflare | Facile | v8 Isolates | Hébergement sur Cloudflare Workers |
| 🦕 Deno.com | Modérée | Deno Isolates | Hébergement sur Deno.com |
| ⏱️ Fastly Compute@Edge | Facile | Fastly JS | Hébergement sur Fastly Compute@Edge |
| 🪂 Fly.io | Difficile | Node MicroVM | Hébergement sur Fly.io |
Pour configurer les listes de blocage, visitez https://<mon-domaine>.tld/configure depuis votre navigateur (cela devrait charger quelque chose de similaire à la page configure de RethinkDNS).
Pour de l'aide ou de l'assistance, n'hésitez pas à ouvrir un problème ou à soumettre un correctif.
Code :
# naviguer vers le répertoire de travail
cd /my/work/dir
# cloner ce dépôt
git clone https://github.com/serverless-dns/serverless-dns.git
# naviguer vers serverless-dns
cd ./serverless-dns
Node :
# installer node v22+ via nvm, si nécessaire
# 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
# télécharger les dépendances
npm i
# (facultatif) mettre à jour les dépendances
npm update
# exécuter serverless-dns sur node
./run n
# exécuter un profileur clinicjs.org
./run n [cpu|fn|mem]
Deno :
# installer deno.land v2+
# https://github.com/denoland/deno/#install
curl -fsSL https://deno.land/install.sh | sh
# exécuter serverless-dns sur deno
./run d
Fastly :
# installer node v22+ via nvm, si nécessaire
# installer la CLI Fastly
# https://developer.fastly.com/learning/tools/cli
# exécuter serverless-dns sur Fastly Compute@Edge
./run f
Wrangler :
# installer Cloudflare Workers (cli) alias Wrangler
# https://developers.cloudflare.com/workers/cli-wrangler/install-update
npm i wrangler --save-dev
# exécuter serverless-dns sur Cloudflare Workers (cli)
# Assurez-vous de configurer Wrangler d'abord :
# https://developers.cloudflare.com/workers/cli-wrangler/authentication
./run w
# profiler wrangler avec Chrome DevTools
# blog.cloudflare.com/profiling-your-workers-with-wrangler
Les commits sur ce dépôt appliquent le guide de style JavaScript de Google (réf : .eslintrc.cjs).
Un hook git pre-commit exécute le linter (eslint) et le formateur (prettier) sur les fichiers .js. Utilisez git commit --no-verify
pour contourner ce hook.
Les demandes de tirage (pull requests) sont également vérifiées pour les violations de style de code et corrigées automatiquement lorsque c'est possible.
Configurez env.js si vous devez ajuster les valeurs par défaut.
Pour Cloudflare Workers, configurez les variables d'environnement dans wrangler.toml à la place.
Pour Fastly Compute@Edge, configurez les variables d'environnement dans fastly.toml à la place.
serverless-dns prend en charge l'authentification avec un jeton porteur alphanumérique pour DoH et DoT. Pour un jeton, msg-key (secret), ajoutez la sortie de hex(hmac-sha256(msg-key|domain.tld), msg) à la variable d'environnement ACCESS_KEYS au format csv. Remarque : msg est actuellement fixé à sdns-public-auth-info.
msg-key à la fin du bloc-tampon (blockstamp), comme ceci :
1:1:4AIggAABEGAgAA:<msg-key> (ici, 1 est la version, 1:4AIggAABEGAgAA
est le bloc-tampon, <msg-key> est le secret d'authentification, et : est le délimiteur).msg-key à la fin du SNI (nom de domaine) contenant le bloc-tampon :
1-4abcbaaaaeigaiaa-<msg-key> (ici 1 est la version, 4abcbaaaaeigaiaa
est le bloc-tampon, <msg-key> est le secret d'authentification, et - est le délimiteur).Si l'intention est d'utiliser l'authentification aussi avec DoT, gardez msg-key plus court (8 à 24 caractères), car les sous-domaines ne peuvent faire que 63 caractères au total.
Vous pouvez générer les clés d'accès pour votre fork depuis max.rethinkdns.com, comme ceci :
msgkey="ShortAlphanumericSecret"
domain="my-serverless-dns-domain.tld"
curl 'https://max.rethinkdns.com/genaccesskey?key='"$msgkey"'&dom='"$domain"
# sortie
# {"accesskey":["my-serverless-dns-domain.tld|deadbeefd3adb33fa2bb33fd3eadf084beef3b152beefdead49bbb2b33fdead83d3adbeefdeadb33f"],"context":"sdns-public-auth-info"}
serverless-dns peut être configuré pour téléverser des journaux 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>
# facultatif, configurez un filtre pour que seuls les journaux de ce worker soient poussés ; mais si vous
# n'avez pas besoin d'un filtre sur le nom du Worker (script-name), modifiez le champ "filter" ci-dessous en conséquence.
SCRIPT_NAME=<name-of-the-worker-as-in-wrangler-toml>
# pour plus d'options, réf : developers.cloudflare.com/logs/get-started/api-configuration
# API Logpush avec cURL : developers.cloudflare.com/logs/tutorials/examples/example-logpush-curl
# Champs Logpull disponibles : 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 dans wrangler.toml, ce qui active Logpush.LOG_LEVEL = "logpush", qui augmente le niveau de journalisation afin que seuls les journaux de requêtes et d'erreurs soient émis.LOGPUSH_SRC = "csv,of,subdomains", ce qui fait que log-pusher.js n'émet des journaux de requêtes que si le hostname des Workers contient l'un des sous-domaines.Les journaux publiés sur R2 peuvent être récupérés soit en utilisant R2 Workers, l'API R2, ou l'API Logpush.
Workers Analytics, si activé, est poussé contre une clé de journal, lid, qui, si non spécifiée, est définie sur le hostname du déploiement serverless avec les points, ., remplacés par des underscores, _. L'authentification doit être configurée lors de l'interrogation des Analytiques via l'API qui renvoie un json ; ex : https://max.rethinkdns.com/1:<optional-stamp>:<msg-key>/analytics?t=<time-interval-in-mins>&f=<field-name>. Les champs possibles sont ip (ip du client), qname (nom de la requête DNS), region (région du résolveur), qtype (type de requête DNS), dom (domaines de premier niveau), ansip (ips de réponse DNS), et cc (codes pays des ips de réponse).
La capture de journaux et les analytiques ne sont pas encore implémentées pour Fly et Deno Deploy.
Deno Deploy (cloud) et Deno (le runtime) n'exposent pas la même surface d'API (par exemple, Deno Deploy ne prend en charge que les écouteurs de serveur HTTP/S ; alors que Deno prend en charge le TCP/UDP/TLS brut en plus du HTTP simple et du HTTP/S).
Sauf sur Node, serverless-dns utilise des résolveurs en amont DoH définis par des variables d'environnement, CF_DNS_RESOLVER_URL / CF_DNS_RESOLVER_URL_2.
Sur Node, le résolveur DNS en amont par défaut est 1.1.1.2 (réf) ou le résolveur DNS récursif à fdaa::3 lorsqu'il s'exécute sur Fly.io.
Les points d'entrée pour Node et Deno sont respectivement src/server-node.js, src/server-deno.ts,
et les deux écoutent les connexions TCP-over-TLS, HTTP/S ; alors que le point d'entrée pour Cloudflare Workers, qui n'écoute que sur HTTP (cli) ou
sur HTTP/S (prod), est src/server-workers.js ; et pour Fastly c'est src/server-fastly.js.
Les configurations locales (non-prod) sur Node, les fichiers key (privée) et cert (chaîne publique), par défaut, sont lus depuis
les chemins définis dans les variables d'environnement, TLS_KEY_PATH et TLS_CRT_PATH.
Alors que pour la configuration de prod sur Node (sur Fly.io), soit TLS_OFFLOAD doit être défini sur true, soit key et cert doivent être
encodés en base64 dans la variable d'environnement TLS_CERTKEY (réf), comme ceci :
# SOIT : décharger tls vers fly.io et définir tls_offload sur true
TLS_OFFLOAD="true"
# OU : représentation base64 de key (privée) et cert (chaîne publique)
TLS_CERTKEY="KEY=b64_key_content\nCRT=b64_cert_content"
Pour Deno, les fichiers key et cert sont lus depuis les chemins définis dans les variables d'environnement, TLS_KEY_PATH et TLS_CRT_PATH (réf).
Le démarrage du processus est différent pour chacun de ces runtimes : Pour Node, src/core/node/config.js régit le démarrage ;
alors que pour Deno, c'est src/core/deno/config.ts, et pour Workers c'est src/core/workers/config.js.
src/system.js pub-sub coordonne la phase de démarrage entre les différents modules.
Sur Node et Deno, la mise en cache DNS en processus est soutenue par @serverless-dns/lfu-cache ; Cloudflare Workers est soutenu à la fois par Cache Web API et
les caches lfu en processus. Pour désactiver complètement la mise en cache sur les trois plateformes, définissez la variable d'environnement, PROFILE_DNS_RESOLVES=true.
Cloudflare Workers et Deno Deploy sont éphémères, c'est-à-dire que le « processus » qui sert les requêtes des clients n'est pas de longue durée, et en fait, deux requêtes consécutives peuvent être servies par deux isolates (« processus ») différents. Fastly Compute@Edge est également éphémère mais n'utilise pas d'isolates ; à la place, Fastly crée et détruit un bac à sable wasmtime pour chaque requête. Le résolveur sur Fly.io, exécutant Node, est soutenu par des VM persistantes et est donc de plus longue durée, comme les environnements « serverfull » traditionnels.
Pour Deno Deploy, la base de code est regroupée dans un seul fichier javascript avec deno bundle puis remise
à Deno.com.
Les configurations de compilation et d'exécution de Cloudflare Workers sont définies dans wrangler.toml.
Webpack5 regroupe les fichiers dans un module ESM qui est ensuite téléversé vers Cloudflare par Wrangler.
Les configurations de compilation et d'exécution de Fastly Compute@Edge sont définies dans fastly.toml.
Webpack5 regroupe les fichiers dans un module ESM qui est ensuite compilé en WASM par npx js-compute-runtime
puis empaqueté et publié vers Fastly Compute@Edge avec la CLI Fastly.
Pour Fly.io, qui exécute Node, les directives d'exécution sont définies dans fly.toml (utilisé par les types de déploiement dev et live),
tandis que les directives de déploiement sont dans node.Dockerfile. flyctl configure en conséquence
serverless-dns sur l'infrastructure de Fly.io.
# compiler et déployer pour cloudflare workers.dev
npm run build
# généralement, env-name est prod
npx wrangler publish [-e <env-name>]
# regrouper, compiler et déployer pour fastly compute@edge
# developer.fastly.com/reference/cli/compute/publish
fastly compute publish
# compiler et déployer vers fly.io
npm run build:fly
flyctl deploy --dockerfile node.Dockerfile --config <fly.toml> [-a <app-name>] [--image-label <some-uniq-label>]
Pour les déploiements déchargeant la terminaison TLS vers Fly.io (type de déploiement B1), les directives d'exécution sont plutôt définies dans
fly.tls.toml, qui configure HTTP2 Cleartext et HTTP/1.1 sur le port 443, et DNS sur TCP sur le port 853.
Réf : github/workflows.
190+ listes de blocage sont compressées dans un arbre radix succinct (Succinct Radix Trie) (basé sur l'impl de Steve Hanov) avec des modifications
pour accélérer la recherche de chaînes (lookup) au détriment de la « succinctité ». Les listes de blocage sont versionnées
avec un horodatage unix (défini dans src/basicconfig.json téléchargé par pre.sh), qui est généré une fois par semaine, mais nous aimerions les générer quotidiennement / toutes les heures,
si possible voir), et hébergées sur Cloudflare R2 (variable d'environnement : CF_BLOCKLIST_URL).
serverless-dns télécharge 3 fichiers de listes de blocage
nécessaires pour configurer l'arbre radix pendant le démarrage du runtime ou les télécharge paresseusement,
lors du service d'une requête DNS.
serverless-dns compile environ ~13M d'entrées (en janvier 2023) à partir d'environ 190+ listes de blocage. Celles-ci sont définies dans le dépôt serverless-dns/blocklists.