Prevent pooled and non-pooled goja runtimes from
being reused or cleaned up when the `RunProgram`
goroutine fails to exit after context cancellation
and `Interrupt()`. In that state, the goroutine
may still be mutating runtime state, so touching
the runtime/returning it to the pool can cause
fatal concurrent map access panics.
Add an explicit `errRuntimeTerminationTimeout`
path that abandons the runtime, keeps the related
concurrency slot reserved, and releases that slot
only from a reaper after the orphaned goroutine
exits. Preserve `errors.Is` compatibility with the
original context cancellation cause.
Keep normal cleanup behavior unchanged, including
callback panic cleanup, and add regression tests
for stuck-interrupt handling that verify runtime
abandonment and delayed slot release.
Fixes#7376
* fix race condition
* fixing review comments
* fix(js): defer runtime cleanup
When a runtime is abandoned, we must not touch the
goja runtime after `RunProgram` has exceeded the
interrupt grace period. At the same time, cleanup
still needs to run on every normal exit before
returning the runtime to the pool, including setup
callback panics.
Signed-off-by: Dwi Siswanto <git@dw1.io>
---------
Signed-off-by: Dwi Siswanto <git@dw1.io>
Co-authored-by: Dwi Siswanto <git@dw1.io>
Add shared auth, options, result, redaction, and
adapter support for GoExec-backed JavaScript
helpers, including:
* `nuclei/wmi`
* `nuclei/tsch`
* `nuclei/scmr`
* `nuclei/dcom`
through generated bindings, and register them with
the JS compiler.
Also make JS generators to skip internal helper
packages and test files.
Signed-off-by: Dwi Siswanto <git@dw1.io>
* Interrupt goja runtime on context cancel
* undo import formats
* do both actions in same go-routine to prevent any possible race condition
* Convert the watchdog, into a simpeler construction which still guarantees the same promises
* move the recover to the go routine, and return named return since we now can use the channel
* remove unnecessary tests
* add extra safety in case process refuses to get interrupted
* remove unnecessary ExecFuncWithTwoReturns
* remove named return values
* fix(js): respect `allow-local-file-access` in `require`
The goja `require() `function used the default
host filesystem loader which let JavaScript
templates import any local files even when
`allow-local-file-access` was disabled.
Pooled runtimes kept `require()` state around so
a module loaded during a privileged execution
could remain cached for a later restricted one.
Rebuild the require registry per execution after
setting the execution context, and route file-
backed module loads to preserve native modules
while enforcing the same sandbox rules (as
`nuclei/fs`).
Signed-off-by: Dwi Siswanto <git@dw1.io>
* fix: cross-platform sandbox path checks
Replace lexical prefix checks in the template file
sandbox with a shared path containment helper that
canonicalizes both paths before comparing them to
prevent false rejections when the configured
templates directory and the resolved file path
differ only due to symlink expansion on macOS or
path normalization on Windows.
Apply the helper in `protocolstate.NormalizePath()`
and `Options.GetValidAbsPath()` so JS `require()`-
based module loads and helper file resolution use
the same rules.
Signed-off-by: Dwi Siswanto <git@dw1.io>
---------
Signed-off-by: Dwi Siswanto <git@dw1.io>
* fix(js): prevent pool slot starvation under load
Zombie goroutines from timed-out JS executions held pool slots
indefinitely: Add() blocked with context.Background(), and defer Done()
only ran when the goroutine eventually completed. Under load, both
pools (80 pooled + 20 non-pooled slots) filled with zombies, silently
dropping all subsequent matches.
Three changes fix slot lifecycle management:
1. Propagate the 20s deadline context into ExecuteProgram (compiler.go)
so both execution paths can respect the deadline.
2. Replace Add() with AddWithContext(ctx) in both pool.go and
non-pool.go so goroutines waiting for a slot fail fast when the
deadline expires instead of blocking indefinitely.
3. Add a watchdog goroutine that releases the slot when the deadline
expires, even if the zombie is still running. An atomic.Bool
ensures exactly one Done() call between the watchdog and the
normal defer path.
* adding context
* refactor(js): derived the ctx to remaining tractable deadline leaks (#7302)
* refactor(js): use `context.Background` as default instead
Signed-off-by: Dwi Siswanto <git@dw1.io>
* refactor(js): derived the ctx to remaining tractable deadline leaks
Signed-off-by: Dwi Siswanto <git@dw1.io>
* test(js): add `NucleiJS.Context` tests
Signed-off-by: Dwi Siswanto <git@dw1.io>
* fix(cmd): context param exclusion in memoization hash
The memoization template condition for excluding
context parameters from hash keys was incorrect.
The memoize package represents context.Context
types as "&{context Context}" (AST string
representation), not "context.Context".
Signed-off-by: Dwi Siswanto <git@dw1.io>
* chore(js): memogen'ed
Signed-off-by: Dwi Siswanto <git@dw1.io>
---------
Signed-off-by: Dwi Siswanto <git@dw1.io>
* fix(js): hangs in checkRDPEncryption
by bounding socket I/O
Add `setConnDeadlineFromContext` helper to set
deadlines on conns derived from context timeouts.
Move conn cleanup out of loop-scoped defers to
make sure immediate cleanup per probe attempt.
Signed-off-by: Dwi Siswanto <git@dw1.io>
---------
Signed-off-by: Dwi Siswanto <git@dw1.io>
Co-authored-by: Niek den Breeje <AuditeMarlow@users.noreply.github.com>
Co-authored-by: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
Co-authored-by: Dwi Siswanto <git@dw1.io>
* feat: conditionally panic-recover
As discussed with @Mzack9999, we should avoid
overusing panic-recover. We need to review the RCA
first to determine whether this is an exceptional
situation or if it's a higher-level function meant
to recover from a panic. This approach will help
us establish a robust error-handling strategy.
The implementation of panic-recover should be
conditional and NOT applied when running in a CI
environment AND IS temporary. Once we've caught
all errors and made the necessary corrections, we
can remove the deferred recover function.
Signed-off-by: Dwi Siswanto <git@dw1.io>
* chore(deps): bump `go-ci` to v1.0.2
Signed-off-by: Dwi Siswanto <git@dw1.io>
* chore(make): add `-race` to `GOFLAGS` in `test`
Signed-off-by: Dwi Siswanto <git@dw1.io>
---------
Signed-off-by: Dwi Siswanto <git@dw1.io>
* feat http response memory optimization + reuse buffers
* update nuclei version
* feat: reuse js vm's and compile to programs
* fix failing http integration test
* remove dead code + add -jsc
* feat reuse js vms in pool with concurrency
* update comments as per review
* bug fix+ update interactsh test to look for dns interaction
* try enabling all interactsh integration tests
---------
Co-authored-by: mzack <marco.rivoli.nvh@gmail.com>