VNX-274: Improper Handling of Insufficient Privileges
Detects privilege changes whose failure is noticed and then ignored: an if on a failed setuid/setgid/setresuid/setgroups/chroot or impersonation call that only logs (C, C++), an except OSError/PermissionError that passes or logs around os.setuid/os.chroot (Python), an err != nil after syscall/unix Setuid that only logs (Go), and an if on a failed posix_setuid/posix_setgid that only logs (PHP).
| Field | Value |
|---|---|
| Rule ID | VNX-274 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | C, C++, Python, Go, PHP |
| CWE | CWE-274 |
| 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 | insufficient-privileges privilege-drop error-handling cwe-274 |
| Source | internal/sast/rules/vnx-274.rego |
Overview
VNX-274 maps to CWE-274: Improper Handling of Insufficient Privileges. When the process lacks the privilege to change identity or enter a jail, the call fails. Detecting the failure is not enough: if the failure branch only prints a warning and falls through, the program carries on as root, or outside the jail, exactly as if the check were missing. VNX-273 covers the call that is not checked at all; this rule covers the check that does not stop.
Reported:
- C and C++: an
ifon the failure ofsetuid,setgid,seteuid,setegid,setreuid,setregid,setresuid,setresgid,setgroups,initgroupsorchroot(!= 0,< 0,== -1, or the bare call), directly or through a result variable assigned just above, and on the failure ofImpersonateNamedPipeClient,ImpersonateLoggedOnUser,ImpersonateSelf,ImpersonateAnonymousTokenorSetThreadToken, whose branch has noreturn,exit,abort,std::terminate(), fatalraise(SIGKILL),goto,err()/errx(), glibcerror()with a nonzero status,break,continueorfatal()/die()-style call. Words inside the log message (“return code”, “will exit”) do not count as stopping. - Python:
os.setuid,os.setgid,os.seteuid,os.setegid,os.setreuid,os.setresuid,os.setresgid,os.setgroups,os.initgroupsoros.chroot(also called bare afterfrom os import setuid) in atrywhoseexcept OSError/PermissionError/Exception/bareexceptneither raises, returns nor exits, or insidecontextlib.suppress(OSError). - Go:
if err != nilaftersyscall/unixSetuid,Setgid,Setresuid,Setgroups,Chrootand similar, whose body neither returns, panics, callsos.Exit,syscall.Exitnorlog.Fatal. - PHP: an
ifon the failure ofposix_setuid,posix_setgid,posix_seteuid,posix_setegidorposix_initgroups(!posix_setuid(...),!@posix_setuid(...),=== false, or Yodafalse === posix_setuid(...)) whose body neither throws, returns, exits nor dies.
What Gets Flagged
// FLAGGED: the failure is printed, then serve_clients() runs as root
if (setuid(pw->pw_uid) != 0) {
perror("setuid");
}
serve_clients();
# FLAGGED: a failed drop is swallowed
try:
os.setuid(uid)
except PermissionError as exc:
logger.warning("could not drop to uid %s: %s", uid, exc)
serve()
// FLAGGED
if err := syscall.Setuid(uid); err != nil {
log.Printf("setuid: %v", err)
}
serve()
// FLAGGED: the worker keeps running as root
if (!posix_setgid($gid) || !posix_initgroups($user, $gid) || !posix_setuid($uid)) {
$this->log("Warning: change gid or uid failed.");
}
What Is Not Flagged
- A failure branch that stops:
return -1,exit(1),err(1, "setgid"),error(EXIT_FAILURE, errno, ...),abort(),goto fail,raise,sys.exit(...),return False,log.Fatalf(...),panic(err),throw new RuntimeException(...),die(...). - A check on success (
if (setuid(uid) == 0) { run_unprivileged(); }). - An unchecked call, which is VNX-273, and a raise back to root (
if (seteuid(0) != 0) perror(...)): failing to gain root leaves the program less privileged. - An
exceptfor an unrelated exception (except KeyError:).
Remediation
Treat a failed privilege change as fatal:
if (setuid(pw->pw_uid) != 0) {
perror("setuid");
exit(EXIT_FAILURE);
}
try:
os.setuid(uid)
except OSError:
log.exception("cannot drop privileges")
raise
References
- CWE-274: Improper Handling of Insufficient Privileges
- CWE-273: Improper Check for Dropped Privileges
- setuid(2)
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-274
// nosec vnx-274
Or record an ignore rule: vulnetix ignore add --rule vnx-274 --reason "...". See Suppressing findings.