Please report security issues privately — do not open a public issue for an unpatched vulnerability.
- Use GitHub's "Report a vulnerability" (Security → Advisories) on this repository: https://github.com/htcom-code/go-lua-perf/security/advisories/new, or
- email the maintainer at htjulia1@gmail.com.
Include a description, the affected version/commit, and a minimal reproducer (a failing Go test is ideal). We'll acknowledge the report and work with you on a fix and coordinated disclosure.
Vulnerabilities in the Lua engine itself (VM/compiler, chunk loading,
string.pack, sandbox escape at the language level) belong to
lua-pure — luart embeds it.
luart is pre-1.0; fixes land on the active line, and the public API may change between minor versions.
| Version | Supported |
|---|---|
| 0.0.x | ✅ |
luart can run untrusted Lua at scale (bytecode cache + per-script VM pool + dynamic registry), but the host owns the policy. luart adds runtime controls on top of the lua-pure engine; the engine-level caveats (lua-pure SECURITY.md) still apply.
- Sandbox the library set. With
Config.Libsunset, pooled States open the lua-pure 5.4 safe set (base/table/string/math/utf8/coroutine) and removeload/loadfile/dofile— noio,os,debug, orpackage. If you setConfig.Libs, you choose exactly what opens; do not addio/os/debugfor untrusted scripts.SkipOpenLibsopens nothing by default. - Bound CPU and wall-clock — two orthogonal limits.
Config.ExecTimeoutis a per-execution wall-clock cap, and a cancelablectxpassed toRunis also honored;Config.MaxInstructionscaps executed Lua opcodes perRun(returnsErrInstructionLimit). Both guard pure-Lua loops — they are checked between VM instructions.0disables each (zero overhead). - A blocking or spinning Go callback escapes those limits. A callback blocked
inside a Go call (channel receive, network read, syscall) — or spinning on
pure Go CPU — is not interrupted until control returns to the VM, so it can pin
the goroutine and its pool slot indefinitely. Make callbacks cancellable
(read the
ctxandselectonDone()) and keep them short. - The memory budget caps pool size, not per-script allocation.
Config.MemoryBudgetBytesderivesMaxStates(budget ÷ measured per-State cost) and drives idle-LRU eviction + backpressure at the cap. It bounds how many live States exist — it is not a per-script memory quota; a hostile script can still allocate heavily within a State. Run untrusted workloads under OS/container memory limits too. - Don't let a State's values escape its owner. Pooled States are never shared
across goroutines.
RunWithhands you results while the State is still owned — read or call them inside the handler, but never let a referencelua.Value(table/function/userdata) escape to another goroutine or outlive the call. Materialize data you need to keep. - Cached bytecode is keyed by
key:version. ASourceLoaderthat returns a stale or attacker-controlledversionfor a changed script can serve stale compiled code from cache. Ensure your loader's version reflects content (e.g.HashVersion) so hot reload and cache invalidation are sound.
In scope: luart runtime bugs with security impact — a pooled State leaking across
goroutines, an eviction/backpressure flaw, a cache-key collision serving wrong
bytecode, or ExecTimeout/MaxInstructions failing to stop a pure-Lua runaway.
Out of scope: resource exhaustion from a script run in a deliberately fully-opened state (that's a configuration choice — sandbox it), and Lua language/VM issues (report those to lua-pure).