VNX-627: Dynamic Variable Evaluation
Detects a program variable whose name comes from the request: Python globals()/locals()/vars() indexed or updated with request data, Ruby instance_variable_set/get with params in the name, PHP variable variables named by a superglobal, and JavaScript global[...] or window[...] indexed by req input.
| Field | Value |
|---|---|
| Rule ID | VNX-627 |
| Severity | High |
| SARIF level | error |
| Kind | sast |
| Languages | Python, Ruby, PHP, JavaScript / TypeScript |
| CWE | CWE-627 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:H/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H |
| Tags | dynamic-variable variable-variables cwe-627 |
| Source | internal/sast/rules/vnx-627.rego |
Overview
VNX-627 maps to CWE-627: Dynamic Variable Evaluation. When the client chooses the name of the variable a program reads or writes, it can overwrite $is_admin, a configuration global or the instance variable that holds the current user, or read a secret the page was never meant to show.
Reported:
- Python:
globals()[k],locals()[k],vars()[k](orglobals().get(k)) wherekis a request value (request.args,form,values,json,GET,POST,data,cookies,headers,query_params), andglobals().update(...),vars(x).update(...),x.__dict__.update(...)with request data. - Ruby:
instance_variable_set/get,class_variable_set/getandbinding.local_variable_set/getwhose name interpolatesparams,cookiesor request parameters. - PHP:
$$name,${$name}and${$_GET[...]}where the name is a superglobal or a variable assigned from one. - JavaScript/TypeScript:
global[...],globalThis[...],window[...]indexed byreq.query,body,params,cookiesorheaders.
The request value may be inline or reach the sink through a variable assigned from it, a destructuring, a for loop or an each block in the 10 lines above.
What Gets Flagged
for key, value in request.POST.items():
globals()[key] = value # FLAGGED
instance_variable_set("@#{params[:field]}", params[:value]) # FLAGGED
$name = $_GET['var'];
$$name = $_GET['value']; // FLAGGED
res.send(String(global[req.query.name])); // FLAGGED
What Is Not Flagged
- Constant names (
globals()["LAST_LOOKUP"] = name,instance_variable_set(:@theme, ...)). - Names from function parameters or configuration: there is no cross-function dataflow.
- Ordinary dictionary or object lookups (
HANDLERS.get(name),handlers[req.query.name]). - PHP variable variables inside a
foreachover a superglobal andextract(): VNX-PHP-007 reports those. - The sinks inside comments or string literals.
Remediation
Never let input name a variable. Map the allowed names to values explicitly:
ALLOWED = {"theme", "locale"}
settings = {k: v for k, v in request.form.items() if k in ALLOWED}
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-627
// nosec vnx-627
Or record an ignore rule: vulnetix ignore add --rule vnx-627 --reason "...". See Suppressing findings.