Ce qui se passe
LuaRocks.org, le registre de paquets de l'écosystème Lua, a reçu le 25 septembre, via la CISA, le signalement d'une faille d'exécution de code à distance, corrigée le lendemain. L'enquête a montré qu'elle avait déjà été exploitée plusieurs fois entre le 9 juillet et le 20 août. Tout ce que le serveur pouvait lire est considéré comme exposé : le site tourne désormais sur une machine neuve, et chaque identifiant de l'ancienne a été révoqué.
Le mécanisme
Un rockspec, le fichier qui décrit un paquet, est un script Lua que le site
exécute à chaque envoi pour en lire les champs. LuaRocks.org tourne sur
OpenResty, donc sous LuaJIT, avec trois précautions : chargement par
loadstring, environnement vide posé par setfenv pour couper l'accès aux
globales, plafond d'instructions.
Le défaut tient au chargement. En Lua 5.1 comme en LuaJIT, loadstring accepte
par défaut du code source et du bytecode précompilé, reconnaissable à son
premier octet, \27. Le site n'attendait que du texte, sans jamais l'exiger.
Or LuaJIT ne vérifie pas le bytecode qu'il charge. Un fichier forgé peut lire et écrire hors de ses propres données, donc n'importe où dans la mémoire du processus. L'environnement vide ne filtre que les noms de globales : le bytecode n'en a pas besoin, il retrouve l'état Lua réel en mémoire et appelle directement les fonctions que le bac à sable devait masquer. N'importe quel compte inscrit pouvait le faire, par le site ou par l'API.
Le correctif impose le mode texte seul et refuse en plus tout fichier qui
commence par \27, car Lua 5.1 d'origine ignore l'argument de mode. La lecture
des manifestes d'autres serveurs, qui avait le même défaut, est corrigée aussi.
Le motif, pour qui évalue de la configuration écrite en Lua :
if content:byte(1) == 27 then
return nil, "bytecode refusé"
end
local chunk, err = loadstring(content, "rockspec", "t") -- "t" : texte seul (LuaJIT)
if not chunk then return nil, err end
setfenv(chunk, {})Chronologie
- 9 juillet : premières commandes shell, par des envois piégés.
- 7 août : nouvelles commandes, tentative de shell distant, trois paquets malveillants publiés.
- 16 et 20 août : plusieurs centaines d'essais automatisés par l'API.
- 25 septembre : signalement.
- 26 septembre : correctif, site en lecture seule, trois comptes suspendus, identifiants révoqués.
Le compte du serveur web pouvait obtenir les droits d'administration : la base entière est supposée lue. Soit les e-mails et hachages bcrypt des mots de passe, les clés API, les secrets 2FA, les jetons GitHub liés (profil et e-mail seulement), les sessions et journaux avec adresses IP, et les identifiants de services tiers.
Ce qui a été vérifié
Un dépôt public, rocks-moonscript-org/moonrocks-mirror, recopie chaque jour
tout ce que le site sert. Comparé à l'état du 8 juillet, il n'a révélé aucun
paquet existant altéré, et seuls les paquets des attaquants contenaient du
bytecode. Deux angles morts, reconnus : une suppression par l'attaquant
ressemble à une suppression légitime, et rien ne dit ce que le serveur
compromis a réellement servi aux clients.
Comment s'y prendre
- Créer une nouvelle clé API si vous utilisez
luarocks upload. - Se reconnecter et changer le mot de passe, partout où il est réutilisé.
- Reconfigurer la 2FA, dont les secrets ont été supprimés.
- Passer le client en 3.12 ou plus : jusqu'à la 3.11.1, sous LuaJIT ou Lua 5.1, il exécuterait un bytecode servi à la place d'un rockspec.
- Chercher les trois paquets de l'attaquant ; une machine qui les a installés est compromise.
- Mainteneurs : relire vos versions récentes depuis la page Security Audit.
luarocks --version
luarocks list | grep -E 'bcrcewon|7e0b94029db0|7e0b9402f9c8'Source : LuaRocks Security Incident September 2026, LuaRocks.org, septembre 2026. Repéré sur Lobste.rs le 27 septembre.