Dev News Daily ENDE

LuaRocks.org was breached through rockspecs loaded as bytecode

LuaRocks.org, the package repository for the Lua language, has published a report on a remote code execution vulnerability that was exploited on its server. The report says the issue was reported on 25 September, coordinated through CISA, and fixed on 26 September - and that the investigation found it had been exploited several times from 9 July. The site has moved to a newly built server, and every credential the old one held has been revoked.

The mechanism is the useful part. A rockspec is a Lua file, and when one is uploaded the site runs it to read fields such as the package name and version. To do that safely it loaded the file with loadstring, ran it with an empty environment and limited how many instructions it could execute. But in Lua 5.1 and LuaJIT, loadstring accepts two kinds of input by default: source code and precompiled bytecode. The parser only expected source and never told loadstring to reject bytecode. LuaJIT does not verify bytecode, so a hand-crafted file can read and write memory outside its own data, find the real Lua state and call the functions the sandbox meant to hide. Any registered user could trigger it by uploading a rockspec.

The fix passes the text-only mode to loadstring and also rejects any file starting with the bytecode marker byte, because PUC Lua 5.1 ignores the mode argument. Code that reads manifests from other servers had the same flaw. The project found three purpose-made accounts that ran shell commands and published three malicious packages on 7 August - bcrcewon, 7e0b94029db0 and 7e0b9402f9c8 - now removed; anyone who installed them should treat the machine as compromised. By comparing stored files against a daily mirror kept outside the server, the team found no evidence that existing packages were modified.

Users are asked to create new API keys, log in again, change their passwords (the bcrypt hashes should be considered exposed), re-enrol two-factor authentication, and upgrade the LuaRocks client to 3.12 or newer - older clients load rockspecs and manifests the same way and, on LuaJIT or Lua 5.1, would run bytecode if a server sent it.

LuaRocks.org was breached through rockspecs loaded as bytecode
LuaRocks.org was breached through rockspecs loaded as bytecode — Dev News Daily

What it means

"Run the untrusted file in an empty environment" sounds like a sandbox, but it only restricts which names the code can look up. Bytecode does not need names. The lesson generalises to any language with a loader that accepts more than one format: specify the format you expect, and reject the others explicitly.

The report is also a model of how to handle a breach: a timeline, the exact mechanism, the named malicious packages, what was exposed, and an external mirror that let the team check integrity against a copy the attacker could not touch.

Primary source
LuaRocks.org security incident report
https://luarocks.org/security-incident-september-2026