Skip to content

VNX-270: Privilege Context Switching Error

Another program is executed after only the effective user ID was lowered (seteuid, setreuid(-1, uid), os.seteuid), so it starts with root as its real user ID and can switch straight back to root.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-270
Severity Low
SARIF level note
Kind sast
Languages C, C++, Python
CWE CWE-270
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-context-switching privilege-drop cwe-270
Source internal/sast/rules/vnx-270.rego

Overview

VNX-270 maps to CWE-270: Privilege Context Switching Error. It reports an exec, system, popen, posix_spawn or subprocess call that follows a temporary privilege drop in the same function, with no permanent drop in between.

Why This Matters

seteuid(uid) changes only the effective user ID; the real user ID stays root. That is the right tool for a short unprivileged section inside a root process, but it is not a context switch for a new program. A program started afterwards inherits root as its real user ID, and any process whose real user ID is root may call setuid(0) again. A user’s hook script, an editor or a plugin started this way can take back full root with one call.

What Gets Flagged

if (setegid(gid) != 0 || seteuid(uid) != 0)
    return -1;
execl("/bin/sh", "sh", "-c", hook, (char *)NULL);   /* flagged */
::setresuid(-1, uid, -1);
::execvp(argv[0], argv);                            // flagged
os.seteuid(uid)
subprocess.run(cmd, check=True)                     # flagged

Not flagged: a permanent drop before the exec (setuid(uid), setresuid(uid, uid, uid), setreuid(uid, uid), os.setuid(uid), or a drop_privileges()-style wrapper); root restored with seteuid(0) before the exec, where the program runs as root on purpose (VNX-272 judges whether that is necessary); subprocess.run(..., user=uid); the two calls in different functions; and the names in comments or string literals.

Remediation

  1. Fork, then in the child drop permanently before exec: setgroups, setgid(gid), setuid(uid) (or setresgid/setresuid with all three IDs), and check each result.
  2. In Python, use subprocess.run(cmd, user=uid, group=gid, extra_groups=[]), which performs the permanent drop in the child.

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

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

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