Skip to content

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).

Updated 02 Nov 2026Checked against cli@de9b52a
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, fchmodat with an owner-only mode as a bare statement (also behind (void)), or under an if on its failure that only logs.
  • Python: os.chmod, os.fchmod, Path.chmod with an owner-only mode in a try whose except OSError/PermissionError/Exception passes or only logs, or inside contextlib.suppress(...).
  • Go: os.Chmod/File.Chmod with an owner-only mode as a bare statement or assigned to _, or whose if err != nil only 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 by chdir("/"), in the failure branch or in the same condition (if (chdir(home) != 0 && chdir("/") != 0)).
  • C, C++: an if on EACCES/EPERM that assigns or returns a /tmp path (if (mkdir(dir, 0700) != 0 && errno == EACCES) dir = "/tmp";).
  • Go: an if os.IsPermission(err) or errors.Is(err, fs.ErrPermission) that assigns or returns os.TempDir() or a /tmp path.
  • Python: an except PermissionError/OSError that falls back to a /tmp path, tempfile.gettempdir() or os.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 0644 or 0755, whose failure exposes nothing, and modes held in variables.
  • A failed chdir that returns instead of falling back, and a plain chdir("/") (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 /tmp path that a handler only logs, prints or deletes, a handler that re-raises, and an error message that suggests /tmp to 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

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.

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