Safeguard
Application Security•

CWE-363 Race Condition Enabling Link Following

CWE-363 is checking a file, then opening it, while an attacker swaps in a symbolic link between the two steps. Learn the pattern and the safer open.

Safeguard Security Team
3 min read

CWE-363, Race Condition Enabling Link Following, is a file handling bug. The product checks the status of a file or directory before accessing it. In the gap, the file can be replaced with a link, and the product accesses the wrong file.

It matters on systems where more than one user or process can write to the directory involved, such as shared temporary folders, and it matters most for privileged programs.

How it happens

The code asks a question about a path: does it exist, is it a regular file, can I write to it. Then it acts on the path. Between question and action, an attacker with write access to the directory removes the file and creates a symbolic link under the same name, pointing at something sensitive.

MITRE stresses that a narrow window is not a safe window. An attacker may slow the product down, for example by consuming memory, so the window widens. Or they may simply attempt the swap a very large number of times until they win once.

What an attacker gains

MITRE lists confidentiality and integrity: reading files or directories, and modifying files or directories. A privileged program that follows the planted link reads or overwrites a file the attacker could never touch directly.

The record has no observed CVEs for this entry.

How to find it

MITRE notes static analysis can find some instances by analyzing source code. A manual pass is also easy.

  • Search for the pairing of a path based check followed by a path based open: stat, lstat or access, then open.
  • Check whether the directory is writable by anyone other than the program's owner.
  • Check whether the program runs with more privilege than the user who triggers it.

How to fix it

MITRE has no mitigation list here, but the related TOCTOU entry (CWE-367) points the way: avoid the separate check, and bind the check and use to the same object.

A vulnerable shape in C:

struct stat st;
if (lstat(path, &st) == 0 && S_ISREG(st.st_mode)) {
    int fd = open(path, O_WRONLY);   /* path may now be a link */
}

A safer shape opens first, refuses links, and checks the handle:

int fd = open(path, O_WRONLY | O_NOFOLLOW);
if (fd < 0) { /* refuse */ }
struct stat st;
if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode)) { close(fd); /* refuse */ }

The check now runs on the opened file, so there is nothing to swap. Also prefer private directories owned by the program over shared ones, and avoid predictable names.

Quick check

Why does a tiny time window not make this safe?

An attacker can widen the window by slowing the product, or can retry a huge number of times until one attempt lands in the gap.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.