Skip to content

VNX-114: Process Control: request chooses the library or module loaded

HTTP request data names the native library, plugin or module loaded by plugin.Open, System.load, URLClassLoader, require/import(), dl(), FFI, importlib, ctypes, Ruby require/load or Fiddle.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-114
Severity Medium
SARIF level warning
Kind sast
Languages Go, Java, JavaScript / TypeScript, PHP, Python, Ruby
CWE CWE-114
CAPEC CAPEC-97
ATT&CK T1557
CWSS vector CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags process-control library-loading dynamic-import cwe-114
Source internal/sast/rules/vnx-114.rego

Overview

VNX-114 maps to CWE-114: Process Control. It reports a library- or module-loading call whose argument carries HTTP request data, inline, concatenated, interpolated, or through a variable assigned from it in the 25 lines above:

  • Go plugin.Open
  • Java System.load/loadLibrary, Runtime.getRuntime().load/loadLibrary, new URLClassLoader
  • JavaScript/TypeScript require(), dynamic import(), process.dlopen
  • PHP dl(), FFI::cdef, FFI::load
  • Python importlib.import_module, __import__, imp.load_source, spec_from_file_location, ctypes.CDLL/WinDLL/cdll.LoadLibrary
  • Ruby require, require_relative, load, Fiddle.dlopen, Fiddle::Handle.new

Not reported: constant names, values from configuration, environment or system properties, and request values checked against an allowlist or looked up in a fixed map before the load. PHP include/require is covered by VNX-98.

Why This Matters

Loading a library or module runs its initialisation code inside the process. When the requester picks the name or path, they can load any module on the import path (including ones that run commands on import), a library they uploaded earlier, or a path traversed out of the plugin directory.

What Gets Flagged

const plugin = require('../plugins/' + req.query.name);   // FLAGGED
const mod = await import(`./addons/${addon}.js`);         // FLAGGED when addon = req.body.addon
name = request.args.get("module")
mod = importlib.import_module("app.handlers." + name)    # FLAGGED
lib = ctypes.CDLL(request.args["lib"])                   # FLAGGED
name := r.URL.Query().Get("plugin")
p, err := plugin.Open("/opt/plugins/" + name + ".so")    // FLAGGED
require "reports/#{params[:kind]}"                       # FLAGGED

Not flagged: require('./greetings').for(name), importlib.import_module(HANDLERS[kind]) after if kind not in HANDLERS, System.loadLibrary("acme-native"), System.load(System.getProperty("acme.lib.path")).

Remediation

  1. Map the request value to a fixed table of permitted modules or libraries and load only entries from that table.
  2. Never build a module name or library path from request data; if a path is unavoidable, resolve it and confirm it stays inside a fixed plugin directory and names an allowlisted file.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-114
// nosec vnx-114

Or record an ignore rule: vulnetix ignore add --rule vnx-114 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-114.rego, cli/internal/sast/docs/vnx-114.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.