mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-12 19:55:14 +02:00
67 lines
2.6 KiB
JavaScript
67 lines
2.6 KiB
JavaScript
|
|
const { exec } = require('child_process');
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ADVERSARIAL — same-file identity collision.
|
||
|
|
*
|
||
|
|
* This file defines multiple entities that share the leaf name
|
||
|
|
* `runTask` with different containers and different security
|
||
|
|
* behaviours. The resolver must not confuse them.
|
||
|
|
*/
|
||
|
|
|
||
|
|
// ── Free function: SHELL-EXEC sink ──────────────────────────────────
|
||
|
|
// Bare `runTask(t)` calls (no receiver, no qualifier) MUST target
|
||
|
|
// this free function. Regression guard: before the bare-call
|
||
|
|
// free-function preference was added, same-file resolution returned
|
||
|
|
// Ambiguous whenever another container also defined `runTask`, and
|
||
|
|
// the SHELL_ESCAPE sink was silently lost.
|
||
|
|
function runTask(cmd) {
|
||
|
|
exec(cmd);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Class method: harmless passthrough ──────────────────────────────
|
||
|
|
// Shares the leaf `runTask` to create an identity collision inside
|
||
|
|
// the same file. Must NOT be picked up by bare-call resolution even
|
||
|
|
// though `NotifyQueue::runTask` matches the leaf name + arity.
|
||
|
|
class NotifyQueue {
|
||
|
|
runTask(message) {
|
||
|
|
return '[notify] ' + message;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Another class method: distinct SHELL-EXEC sink ──────────────────
|
||
|
|
// Two classes with the same method name `runTask`. When invoked via
|
||
|
|
// an instance variable the resolver cannot tell them apart without
|
||
|
|
// type inference — it must refuse to pick one silently.
|
||
|
|
class CommandRunner {
|
||
|
|
runTask(cmd) {
|
||
|
|
exec(cmd);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class SilentWorker {
|
||
|
|
runTask(msg) {
|
||
|
|
return msg.trim();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Caller 1: bare top-level call → free function ───────────────────
|
||
|
|
// `runTask` has no receiver, no qualifier. The resolver must pick
|
||
|
|
// the free function (SHELL sink) — not a method. Expected finding:
|
||
|
|
// taint-unsanitised-flow (SHELL_ESCAPE).
|
||
|
|
function handleBare(req) {
|
||
|
|
const tainted = req.query.q; // Express source
|
||
|
|
runTask(tainted); // SINK via free function
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Caller 2: method call on explicitly-named class instance ────────
|
||
|
|
// `new SilentWorker().runTask(tainted)` is syntactically a method
|
||
|
|
// call — MUST NOT be silently resolved to the free function. The
|
||
|
|
// SilentWorker method is harmless, so no sink finding is expected.
|
||
|
|
function handleSafeMethod(req) {
|
||
|
|
const tainted = req.query.q;
|
||
|
|
const w = new SilentWorker();
|
||
|
|
w.runTask(tainted);
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = { handleBare, handleSafeMethod, NotifyQueue, CommandRunner, SilentWorker };
|