happyDomain détient quelque chose de précieux : les clés d’API qui permettent de modifier vos zones DNS chez votre bureau d’enregistrement ou votre hébergeur DNS. Est-ce qu’on les manipulait vraiment correctement ? Est-ce qu’il restait, quelque part, un chemin permettant d’utiliser les clés de quelqu’un d’autre ? Nous nous posons la question depuis des années, avec les yeux de ceux qui ont écrit le code.

Grâce à notre financement NGI Zero Core obtenu auprès de NLnet, Radically Open Security a audité happyDomain courant juillet 2026.

Qu’ont-ils trouvé ? Six problèmes, ce qui est un résultat plutôt positif. Inutile de préciser que nous les avons tous corrigés dans les versions publiées en même temps que cet article, 0.7.2 et 0.8.0-rc2.
Nous vous encourageons à mettre à jour vos instances sans plus attendre.

Pourquoi faire appel à des regards extérieurs ?

Nous avons mené notre propre revue de sécurité il y a quelques mois, avec l’aide de Claude, sur l’authentification, la gestion des sessions et le flux OIDC (article de la version 0.6.0). L’exercice s’est révélé utile : 14 problèmes avaient été corrigés dans la foulée.

Mais nous avions écrit nous-mêmes les questions à poser, à partir du modèle mental qui avait produit le code. Une revue ne cherche que là où on lui demande de chercher, et nos angles morts étaient exactement là où nous n’avions pas pensé à envoyer quelqu’un.

Une équipe extérieure n’hérite pas de ce modèle : elle lit le code comme le ferait un attaquant, pose les questions que nous ne nous posons plus depuis longtemps, puis tente réellement l’attaque sur une instance en fonctionnement. Cela ne la rend pas exhaustive pour autant. Une semaine ne suffit pas à parcourir tout happyDomain, et c’est nous qui avons désigné les aspects méritant le plus d’attention : le regard extérieur est resté partiellement guidé par le nôtre. Des pans entiers du code n’ont pas été ouverts.

Ce qui suit dit donc ce qui a été regardé et ce qui y a été trouvé, pas que le reste est sain.

Qui est Radically Open Security

Radically Open Security est un cabinet de sécurité informatique établi à Amsterdam et constitué sans but lucratif.

Leur méthode de travail est à l’image de leur nom. L’audit s’est déroulé à découvert avec nous : chaque découverte arrivait dès sa confirmation, dans un outil de suivi partagé, accompagnée des requêtes exactes permettant de la reproduire. Pas de six semaines de silence suivies d’un PDF. Nous avons pu commencer à corriger dès les premiers jours, sans attendre le rapport, et discuter chaque correctif avec eux pendant qu’ils poursuivaient leurs tests.

Le rapport complet est public, disponible à cette adresse :

happyDomain Code Audit Report, v1.0

Vous y trouverez les descriptions techniques complètes, les preuves de concept et les captures de notre propre interface en train d’être détournée.

Le périmètre de l’audit

L’audit a porté sur happyDomain lui-même : l’API REST écrite en Go, l’interface web et l’interface d’administration, examinés au dernier commit de la branche master du moment (a1de404f), avec confirmation des découvertes sur une instance réelle adossée à une installation PowerDNS.

La question posée est celle qui compte pour un service multi-utilisateurs détenant des clés d’API : qu’est-ce qui sépare un utilisateur inscrit mais malveillant des identifiants d’un autre utilisateur, ou de la zone d’un autre utilisateur ? Le pire scénario étant la prise de contrôle du DNS d’un domaine qui ne lui appartient pas.

Les bonnes nouvelles d’abord

Cette question centrale est revenue sans réponse pour l’attaquant.

L’isolation entre utilisateurs tient. Radically Open Security a tenté d’atteindre les identifiants d’un autre utilisateur par la lecture d’un fournisseur, par la liste des fournisseurs et par export.json, puis a construit une matrice complète d’accès croisés sur une instance en fonctionnement, étendue aux domaines et aux zones. Aucune fuite.

Les écritures de zone entre utilisateurs tiennent également. Ils ont essayé l’application et le déploiement directs, le détournement de fournisseur, l’injection d’enregistrements de correction forgés, ainsi que la variante différée où un utilisateur écrit dans la zone en attente d’un autre en espérant que celui-ci la publiera. La frontière a tenu sur tous les chemins.

La fixation de session tient : un identifiant de session préétabli ne survit pas à une connexion, l’enregistrement étant supprimé et un identifiant aléatoire frais généré. Enfin, aucune route modifiant des données n’est accessible sans être connecté. Les contournements habituels ont été essayés sans succès : changer la méthode HTTP de la requête, écrire l’URL autrement (avec ou sans barre oblique finale, en jouant sur la casse ou l’encodage) pour passer à côté du contrôle d’authentification, ou envoyer plusieurs fois le même paramètre en espérant que la vérification lise l’une des valeurs et le traitement une autre.

Les six découvertes

Une clé de récupération vide réinitialisait n’importe quel compte (haute)

Le problème. La récupération de mot de passe comparait la clé envoyée par courriel à celle fournie par l’appelant. Quand aucune récupération n’était en cours, la clé stockée était vide : soumettre une clé vide passait le contrôle. Tout compte ayant changé de mot de passe au moins une fois était dans cet état en permanence.

L’impact. Une seule requête, sans être connecté, suffisait à prendre le contrôle d’un compte : ses domaines, ses zones et ses clés d’API de fournisseur.

Ce qui a été fait. La requête est rejetée s’il n’y a pas de récupération en cours ou pas de clé soumise (8db85c61), et le scénario d’attaque exact est couvert par un test automatisé pour qu’il ne revienne pas. La même relecture a durci deux points voisins : les comparaisons de clés ne peuvent plus être devinées par le temps de réponse, et ces points d’entrée ouverts sont désormais soumis à une limitation du nombre de tentatives.

Le fournisseur BIND donnait accès aux fichiers du serveur (élevée)

Le problème. Une fonctionnalité optionnelle (-with-bind-provider) permet de lire et d’écrire des fichiers de zone sur le serveur. L’emplacement de ces fichiers était choisi par l’utilisateur, sans aucune restriction.

L’impact. Sur une instance où cette option était activée, un utilisateur inscrit pouvait lire ou écrire des fichiers arbitraires du serveur. La documentation déconseillait déjà cette option en instance partagée, mais une recommandation n’empêche rien.

Ce qui a été fait. L’option prend maintenant la liste des répertoires autorisés, et tout accès en dehors est refusé, y compris pour les fournisseurs déjà enregistrés (b671165e).

Les limites anti-abus pouvaient être contournées (modérée)

Le problème. happyDomain identifiait ses visiteurs à partir d’une information que le visiteur fournissait lui-même, et qu’il pouvait donc changer à volonté.

L’impact. Les protections contre les tentatives répétées de connexion devenaient inopérantes, rendant praticable un test massif de mots de passe sur de nombreux comptes.

Ce qui a été fait. L’identification repose maintenant sur l’adresse réelle de connexion. Un administrateur qui place happyDomain derrière un proxy le déclare explicitement (-trusted-proxy) (da31f536). Ce travail a aussi révélé, de notre côté, que le décompte par adresse IPv6 était trop fin pour être efficace : il est désormais calculé par plage d’abonné (8c1e5f13).

happyDomain se connectait partout où on le lui demandait (modérée)

Le problème. Plusieurs fonctionnalités laissent l’utilisateur indiquer une adresse à laquelle happyDomain se connecte : fournisseurs auto-hébergés, outil de résolution, récupération de certificat, webhooks… Aucune vérification de destination n’était faite.

L’impact. Il était possible de faire sonder par happyDomain le réseau interne sur lequel il tourne, et, plus grave, de lui faire envoyer une clé d’API de fournisseur à une adresse choisie par l’attaquant.

Ce qui a été fait. Un contrôle centralisé vérifie désormais chaque destination avant connexion et refuse les réseaux internes par défaut, y compris après redirection. Les destinations des fournisseurs sont validées dès leur enregistrement, avant qu’une clé ne circule (3b054501). Pour les cas légitimes, comme un serveur DNS hébergé à côté d’happyDomain, l’administrateur autorise explicitement les adresses concernées.

L’interface d’administration n’avait pas de mot de passe (modérée)

Le problème. L’interface d’administration introduite en 0.6.0 reposait uniquement sur le fait de n’être accessible que localement. Là encore, c’était documenté, mais rien ne l’imposait.

L’impact. Quiconque atteignait cette interface pouvait télécharger une copie complète de la base, clés d’API de fournisseur en clair comprises, ou changer le mot de passe de n’importe quel compte.

Ce qui a été fait. L’interface d’administration est protégée par un mot de passe (c1adebbe), et happyDomain refuse de démarrer si cette interface est exposée sur le réseau sans mot de passe configuré.

C’est le point à vérifier en priorité si vous auto-hébergez happyDomain et que vous aviez ouvert ce port par commodité.

Un changement de mot de passe laissait les autres sessions ouvertes (faible)

Le problème. Changer ou réinitialiser son mot de passe ne fermait pas les autres sessions du compte, qui restaient valides jusqu’à 15 jours.

L’impact. Une session volée survivait à la réinitialisation de mot de passe censée en reprendre le contrôle.

Ce qui a été fait. Un changement de mot de passe ferme les sessions ouvertes depuis l’interface web (bd0236dd). Les jetons créés pour un usage automatisé via l’API sont volontairement conservés : ils ne s’obtiennent pas avec le mot de passe et se révoquent séparément.

La suite : chiffrer les identifiants en base

Un point a été volontairement écarté de cette campagne, en accord avec les auditeurs, et c’est celui que nous jugeons le plus important.

happyDomain stocke les clés d’API de fournisseur DNS en clair dans sa base. C’est l’exposition durable derrière plusieurs des découvertes ci-dessus : une clé qui fuit continue de contrôler votre DNS chez le fournisseur, indépendamment d’happyDomain, jusqu’à ce que vous la remplaciez. Colmater la fuite n’annule pas la fuite.

NLnet a accepté de financer ce chantier comme une étape supplémentaire, et il démarre maintenant. L’objectif : qu’une copie de la base seule ne suffise plus à lire vos clés, que celles-ci ne ressortent plus par l’API ou les sauvegardes, et que la clé de chiffrement reste gérée séparément.

Où nous en sommes

Aucune des six découvertes n’est exotique. Ce sont les erreurs qui surviennent quand un projet grandit. Et c’est précisément l’intérêt de les faire relire par quelqu’un d’autre.

Voici nos engagements, sans cérémonie :

  • Le rapport complet est public.
  • Les découvertes sont corrigées et livrées dès aujourd’hui, pas mises en suivi. Les six sont dans la 0.7.2 et la 0.8.0-rc2.
  • Signalez-nous ce que vous trouvez, à security@happydomain.org ou par la procédure décrite dans notre SECURITY.md.

Merci à NLnet d’avoir financé ce travail, et à Radically Open Security de l’avoir bien mené.