VNX-280: Improper Handling of Insufficient Permissions or Privileges
Detects code that is refused access to or control over a resource and carries on as if it had it: an owner-only chmod (0600, S_IRUSR|S_IWUSR) whose failure is ignored in C, C++, Python and Go, and a refused directory replaced by a broader one (chdir("/") after a failed chdir, a /tmp, gettempdir() or os.TempDir() fallback after a permission error).
| Field | Value |
|---|---|
| Rule ID | VNX-280 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | C, C++, Python, Go |
| CWE | CWE-280 |
| 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-permissions error-handling file-permissions cwe-280 |
| Source | internal/sast/rules/vnx-280.rego |
Overview
VNX-280 maps to CWE-280: Improper Handling of Insufficient Permissions or Privileges. When the process is not allowed to do something, the right response is usually to stop. Carrying on puts the program in a state its author did not plan for. The rule reports two concrete shapes.
A protective chmod whose failure is ignored. Restricting a file to its owner (0600, 0400, 0700, S_IRUSR | S_IWUSR) fails when the process does not own the file (EPERM) or the filesystem is read-only. If the failure is ignored, the secret written next stays readable by others. Reported:
- C, C++:
chmod,fchmod,fchmodatwith an owner-only mode as a bare statement (also behind(void)), or under anifon its failure that only logs. - Python:
os.chmod,os.fchmod,Path.chmodwith an owner-only mode in atrywhoseexcept OSError/PermissionError/Exceptionpasses or only logs, or insidecontextlib.suppress(...). - Go:
os.Chmod/File.Chmodwith an owner-only mode as a bare statement or assigned to_, or whoseif err != nilonly logs.
A refused location replaced by a broader one. A server that cannot enter a user’s home directory and puts the session at the filesystem root instead (CVE-2004-0148) exposes everything the jail was meant to hide. Reported:
- C, C++: a failed
chdir(dir)followed bychdir("/"), in the failure branch or in the same condition (if (chdir(home) != 0 && chdir("/") != 0)). - C, C++: an
ifonEACCES/EPERMthat assigns or returns a/tmppath (if (mkdir(dir, 0700) != 0 && errno == EACCES) dir = "/tmp";). - Go: an
if os.IsPermission(err)orerrors.Is(err, fs.ErrPermission)that assigns or returnsos.TempDir()or a/tmppath. - Python: an
except PermissionError/OSErrorthat falls back to a/tmppath,tempfile.gettempdir()oros.chdir("/").
What Gets Flagged
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
fchmod(fd, 0600); // FLAGGED: may fail, the key is written anyway
write(fd, key, strlen(key));
if (chdir(pw->pw_dir) < 0) { // FLAGGED: falls back to the filesystem root
syslog(LOG_WARNING, "cannot enter %s, using /", pw->pw_dir);
chdir("/");
}
try:
os.makedirs(CACHE_DIR, exist_ok=True)
return CACHE_DIR
except PermissionError:
return "/tmp/myapp-cache" # FLAGGED: shared, predictable location
What Is Not Flagged
- A failure that stops:
return -1,err(1, ...),raise,sys.exit(...),return err. - Ordinary modes such as
0644or0755, whose failure exposes nothing, and modes held in variables. - A failed
chdirthat returns instead of falling back, and a plainchdir("/")(daemons do this deliberately). - A restrictive chmod made only so the owner can remove the entry right after (
chmod(dir, 0700); rmdir(dir);,os.Chmod(dir, 0o700); os.RemoveAll(dir)). - A
/tmppath that a handler only logs, prints or deletes, a handler that re-raises, and an error message that suggests/tmpto the user. - Fallbacks to a private directory created for the run (
tempfile.mkdtemp()), and handlers for unrelated errors (except FileNotFoundError). access()-style permission probes: those are a race between check and use (CWE-367), not this weakness.- Test code.
Remediation
Create secrets with the restrictive mode from the start, so there is nothing to tighten afterwards, and stop when a permission change fails:
int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0 || fchmod(fd, 0600) != 0)
return -1;
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
When the intended directory is refused, refuse the session (or use tempfile.mkdtemp() for scratch space) rather than switching to / or a fixed /tmp path.
References
- CWE-280: Improper Handling of Insufficient Permissions or Privileges
- CVE-2004-0148
- CWE-377: Insecure Temporary File
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-280
// nosec vnx-280
Or record an ignore rule: vulnetix ignore add --rule vnx-280 --reason "...". See Suppressing findings.