From 3f6d9cceeeb50d4d961bd0d9a85375238d5f41fb Mon Sep 17 00:00:00 2001 From: ludicious-claw Date: Sun, 1 Nov 2026 16:59:29 +0500 Subject: [PATCH 1/4] Fix math.random polyfill condition for zero-argument calls --- src/prometheus.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prometheus.lua b/src/prometheus.lua index d5b27366..bb3eeeb4 100644 --- a/src/prometheus.lua +++ b/src/prometheus.lua @@ -20,7 +20,7 @@ if not pcall(function() end) then local oldMathRandom = math.random; math.random = function(a, b) - if not a and b then + if not a then return oldMathRandom(); end if not b then From edbd6b7e16bddedf86145e689590d00043d23c35 Mon Sep 17 00:00:00 2001 From: ludicious-claw Date: Sun, 1 Nov 2026 16:59:33 +0500 Subject: [PATCH 2/4] Fix seed overflow and resource handling in pipeline random generation --- src/prometheus/pipeline.lua | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/prometheus/pipeline.lua b/src/prometheus/pipeline.lua index fe21f853..1eb9f4c5 100644 --- a/src/prometheus/pipeline.lua +++ b/src/prometheus/pipeline.lua @@ -166,19 +166,34 @@ function Pipeline:apply(code, filename) else --> use secure random number generator local success, seed = pcall(function() - local seedStr = io.popen("openssl rand -hex 12"):read("*a"):gsub("\n", "").."" + local handle = io.popen("openssl rand -hex 12") + if not handle then + error("Failed to execute openssl") + end + local seedStr = handle:read("*a") + local ok = handle:close() + if ok == false or ok == nil then + error("openssl command failed") + end + if not seedStr then + error("Failed to read from openssl") + end + seedStr = seedStr:gsub("%s+", "") + if #seedStr ~= 24 or not seedStr:match("^%x+$") then + error("Invalid openssl output") + end + local seedNum = 0; - --> NOTE: tonumber caps at 1.844674407371e+19. So we use this instead. + --> NOTE: accumulate modulo 2147483647 so it fits in signed 32-bit integer without double overflow for i = 1, #seedStr do local char = seedStr:sub(i, i):lower() local digit = char:match("%d") and (char:byte() - 48) or (char:byte() - 87) - seedNum = seedNum * 16 + digit + seedNum = (seedNum * 16 + digit) % 2147483647 end - --> Random Number Generator in Lua 5.1 is limited to 9.007199254741e+15. - if _VERSION == "Lua 5.1" and not jit then - seedNum = seedNum % 9.007199254741e+15 + if seedNum == 0 then + seedNum = 1 end return seedNum @@ -188,7 +203,11 @@ function Pipeline:apply(code, filename) math.randomseed(seed) else logger:warn("OpenSSL is unavailable. Falling back to unix time."); - math.randomseed(os.time()) + local fallback = (os.time() + math.floor(os.clock() * 1000000)) % 2147483647 + if fallback == 0 then + fallback = 1 + end + math.randomseed(fallback) end end From a7c8f50d0a72eb18bbb22dda09cbc37dc6558f33 Mon Sep 17 00:00:00 2001 From: ludicious-claw Date: Sun, 1 Nov 2026 16:59:37 +0500 Subject: [PATCH 3/4] Add regression tests for math.random polyfill and random seed generation --- tests/harness/random-seed.lua | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/harness/random-seed.lua diff --git a/tests/harness/random-seed.lua b/tests/harness/random-seed.lua new file mode 100644 index 00000000..cef58afa --- /dev/null +++ b/tests/harness/random-seed.lua @@ -0,0 +1,72 @@ +require("src.prometheus") +local Prometheus = require("src.prometheus") +Prometheus.Logger.logLevel = Prometheus.Logger.LogLevel.Error + +-- 1. Verify math.random() polyfill behavior +for i = 1, 20 do + local val = math.random() + assert(type(val) == "number", "math.random() must return a number") + assert(val >= 0 and val < 1, "math.random() must be in [0, 1), got " .. tostring(val)) +end + +local intVal = math.random(10) +assert(intVal >= 1 and intVal <= 10 and intVal == math.floor(intVal), "math.random(10) out of range") + +local rangeVal = math.random(5, 15) +assert(rangeVal >= 5 and rangeVal <= 15 and rangeVal == math.floor(rangeVal), "math.random(5, 15) out of range") + +local largeVal = math.random(1, 2^40) +assert(largeVal >= 1 and largeVal <= 2^40, "math.random(1, 2^40) out of range") + +-- 2. Verify deterministic pipeline with explicit seed +local code = 'local a = 10; local b = 20; return a + b' +local configDeterministic = { + LuaVersion = "Lua51", + Seed = 12345, + NameGenerator = "Mangled", + Steps = { + { Name = "Vmify" }, + { Name = "EncryptStrings" }, + { Name = "ConstantArray" }, + } +} + +local pipe1 = Prometheus.Pipeline:fromConfig(configDeterministic) +local out1 = pipe1:apply(code, "test.lua") +local pipe2 = Prometheus.Pipeline:fromConfig(configDeterministic) +local out2 = pipe2:apply(code, "test.lua") + +assert(out1 == out2, "Configured seed must produce deterministic identical output") +local res1 = assert(loadstring(out1))() +assert(res1 == 30, "Obfuscated code with fixed seed must execute correctly, got " .. tostring(res1)) + +-- 3. Verify non-deterministic pipeline without configured seed (Seed = 0) +local configRandom = { + LuaVersion = "Lua51", + Seed = 0, + Steps = { + { Name = "Vmify" }, + { Name = "EncryptStrings" }, + { Name = "ConstantArray" }, + } +} + +local randomOutputs = {} +for i = 1, 5 do + local p = Prometheus.Pipeline:fromConfig(configRandom) + local o = p:apply(code, "test.lua") + local res = assert(loadstring(o))() + assert(res == 30, "Obfuscated code with random seed must execute correctly") + randomOutputs[i] = o +end + +local hasDifference = false +for i = 2, 5 do + if randomOutputs[i] ~= randomOutputs[1] then + hasDifference = true + break + end +end +assert(hasDifference, "Repeated runs without configured seed must produce different outputs") + +print("Random seed and math.random regression checks passed") From eaab48a15cf8465fa87941b642023b89bd054c76 Mon Sep 17 00:00:00 2001 From: ludicious-claw Date: Sun, 1 Nov 2026 17:30:04 +0500 Subject: [PATCH 4/4] Make random-seed test and pipeline fallback portable across runtimes --- src/prometheus/pipeline.lua | 7 ++++++- tests/harness/random-seed.lua | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/prometheus/pipeline.lua b/src/prometheus/pipeline.lua index 1eb9f4c5..bfc85e18 100644 --- a/src/prometheus/pipeline.lua +++ b/src/prometheus/pipeline.lua @@ -166,6 +166,9 @@ function Pipeline:apply(code, filename) else --> use secure random number generator local success, seed = pcall(function() + if not io or not io.popen then + error("io.popen is unavailable") + end local handle = io.popen("openssl rand -hex 12") if not handle then error("Failed to execute openssl") @@ -203,7 +206,9 @@ function Pipeline:apply(code, filename) math.randomseed(seed) else logger:warn("OpenSSL is unavailable. Falling back to unix time."); - local fallback = (os.time() + math.floor(os.clock() * 1000000)) % 2147483647 + local now = (os and os.time) and os.time() or 1 + local clock = (os and os.clock) and math.floor(os.clock() * 1000000) or 0 + local fallback = (now + clock) % 2147483647 if fallback == 0 then fallback = 1 end diff --git a/tests/harness/random-seed.lua b/tests/harness/random-seed.lua index cef58afa..fe83a647 100644 --- a/tests/harness/random-seed.lua +++ b/tests/harness/random-seed.lua @@ -1,7 +1,10 @@ +-- @runtime lua51 luajit require("src.prometheus") local Prometheus = require("src.prometheus") Prometheus.Logger.logLevel = Prometheus.Logger.LogLevel.Error +local loadstring = loadstring or load + -- 1. Verify math.random() polyfill behavior for i = 1, 20 do local val = math.random() @@ -69,4 +72,14 @@ for i = 2, 5 do end assert(hasDifference, "Repeated runs without configured seed must produce different outputs") +-- 4. Verify fallback path when OpenSSL / io.popen is unavailable +local savedPopen = io.popen +io.popen = nil +local pFallback = Prometheus.Pipeline:fromConfig(configRandom) +local oFallback = pFallback:apply(code, "fallback.lua") +io.popen = savedPopen + +local resFallback = assert(loadstring(oFallback))() +assert(resFallback == 30, "Fallback obfuscation must execute correctly") + print("Random seed and math.random regression checks passed")