Skip to content

VNX-268: Privilege Chaining

The program runs sudo, doas or pkexec with a command line that includes a runtime value, chaining whatever controls that value to the root rights of the program's account.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-268
Severity Low
SARIF level note
Kind sast
Languages C, C++, Python
CWE CWE-268
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L
Tags privilege-chaining sudo cwe-268
Source internal/sast/rules/vnx-268.rego

Overview

VNX-268 maps to CWE-268: Privilege Chaining. An application account that may run commands through sudo, doas or pkexec holds two privileges: its own, and a route to root. This rule reports code that joins them with a value decided at run time, so whoever influences that value also chooses what root runs.

Why This Matters

A sudoers entry such as app ALL=(root) NOPASSWD: /usr/bin/systemctl restart * looks narrow. Combined with code that fills in the service name from a request, a job parameter or a file, it becomes “run this root command with an argument I pick”, and an argument can be an option (--now, -o), a path or a second command. Each privilege is reasonable alone; chained, they hand out root.

What Gets Flagged

subprocess.run(["sudo", "systemctl", "restart", service], check=True)
os.system(f"sudo rm -rf {path}")
subprocess.call("sudo chown " + user + " " + path, shell=True)

cmd = f"sudo useradd -m {name}"
subprocess.run(cmd, shell=True, check=True)
snprintf(cmd, sizeof(cmd), "sudo /usr/sbin/useradd -m %s", name);
return system(cmd);

execlp("sudo", "sudo", "-n", script.c_str(), (char *)NULL);
execvp("pkexec", argv);

Not flagged: a fully constant privileged command (sudo systemctl reload nginx, sudo -n true), a value checked against an allow-list just above the call (if service not in ALLOWED_SERVICES: raise), commands that do not use sudo, doas or pkexec, sudo in messages and help strings, and calls in comments. Whether the sudoers or polkit rule itself is too broad lives outside the code and is not judged.

Remediation

  1. Run a fixed privileged command, and choose any variable part from an allow-list in code (if service not in {"nginx", "cron"}: raise).
  2. Pass arguments as a list, never through a shell, and end options with -- so a value cannot become a flag.
  3. Better, move the privileged action into a dedicated helper or service with a narrow, validated interface, and drop the application’s sudo rights.

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-268
// nosec vnx-268

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

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