Dans un billet publié le 26 mai 2026 par Jonatan Männchen, la fondation Erlang Ecosystem Foundation (EEF) alerte sur une vulnérabilité persistante au sein de l’écosystème BEAM (Erlang, Elixir, etc.). Alors que les développeurs perçoivent parfois l’épuisement des atomes comme un « piège » anecdotique, les chiffres montrent qu’il s’agit d’un problème majeur de sécurité.
Une part prépondérante des CVE
Selon la fondation, 35,8 % des CVE (Common Vulnerabilities and Exposures) publiées par son CNA (CVE Numbering Authority) tombent dans la catégorie « consommation non contrôlée de ressources ». Dans l’écosystème BEAM, une grande partie de ces vulnérabilités provient d’un seul et même problème : l’épuisement de la table des atomes. La distribution complète des faiblesses est consultable sur la page Common Weaknesses du CNA de l’EEF.
L’épuisement des atomes est une vulnérabilité de déni de service (DoS). Les atomes ne sont pas soumis au ramasse-miettes et sont stockés dans une table globale. Lorsque cette table est pleine, la machine virtuelle (VM) plante. Créer des atomes à partir de valeurs non finies, en particulier issues de données utilisateur, constitue donc une faille DoS latente.
Des schémas de code dangereux
Ce problème ne se limite pas aux appels évidents comme binary_to_atom/1, list_to_atom/1 en Erlang, ou String.to_atom/1 et List.to_atom/1 en Elixir. Des motifs moins évidents posent également problème, comme le montre le billet :
- En Erlang :
list_to_atom("field_" ++ UserInput) - En Elixir :
Jason.decode(json, keys: :atoms) - En Elixir :
:"field_#{user_input}"
Ce qui rend cette classe de vulnérabilité persistante, ce n’est pas la négligence, mais le fait qu’elle apparaît souvent dans du code où l’entrée était supposée contrôlée ou finie. Les schémas d’URI en sont un bon exemple : il peut sembler n’y avoir que quelques schémas à gérer, mais si la valeur provient d’une source externe, l’ensemble n’est plus garanti fini.
Recommandations et bonnes pratiques
La fondation rappelle un principe fondamental : « Créer des atomes à partir d’une entrée est dangereux, sauf si l’ensemble des valeurs possibles est fini, connu et contrôlé. »
L’approche la plus sûre consiste à éviter complètement la création de nouveaux atomes à l’exécution. Il est recommandé d’utiliser des tables de correspondances explicites lorsque les valeurs acceptées sont connues, par exemple en Erlang :
case Scheme of
<<"http">> -> http;
<<"https">> -> https;
_ -> error
end
Lorsqu’une table de correspondance n’est pas pratique, les variantes « atome existant » sont plus sûres : elles lèvent une erreur au lieu de créer un nouvel atome. Il s’agit de binary_to_existing_atom/1 ou list_to_existing_atom/1 en Erlang, et de String.to_existing_atom/1 ou List.to_existing_atom/1 en Elixir.
Des outils pour prévenir ces failles
Les linters peuvent aider à détecter ces motifs avant qu’ils ne deviennent des vulnérabilités. Pour les projets Elixir, la fondation recommande d’activer le test Credo.Check.Warning.UnsafeToAtom de Credo, qui signale les appels dangereux à String.to_atom/1, List.to_atom/1, Module.concat/1,2, et Jason.decode/2 avec l’option keys: :atoms. Ce test est désactivé par défaut.
Appel à l’action
L’EEF invite les mainteneurs de projets Erlang ou Elixir à rechercher dans leur codebase toute création d’atomes à partir de chaînes binaires, de chaînes de caractères, de clés JSON, de composants d’URI, d’en-têtes et de valeurs de configuration. Selon la fondation, il s’agit de l’une des classes de vulnérabilités les plus faciles à corriger avant qu’elle ne donne lieu à une CVE.
Un guide détaillé sur la prévention de l’épuisement des atomes est disponible sur le site du groupe de travail sécurité de l’EEF.