MCPSafe.io
RegistryThreatsMethodologyDocsPricingScanSign in
MCPSafe.io

Security checks for MCP servers — public packages and private repos, fast or deep.

Legal

Privacy PolicyCookie PolicyTerms of ServiceSecurity disclosure

Resources

State of MCP SecuritySupportSystem statusMade in Germany 🇩🇪

© 2026 MCPSafe. All rights reserved.

GDPR — Privacy Policy
← Threat Catalog

Server Implementation

Time-of-check-to-time-of-use file race

HIGHCWE: CWE-367Rule: MCP-250

An MCP tool checks file properties (existence, ownership, size) and then opens the file in a separate operation — an attacker swaps the file in the gap, defeating the check.

What it is

TOCTOU bugs come from doing a check (`os.path.exists`, `os.stat`, `Path.is_file`) on a path, then doing an action (`open`, `read`, `chmod`) on the same path. Between check and use, an attacker can replace the file with a symlink or a different file, and the action runs against the substitute. The fix is to do the action atomically — open the path, then check the open file descriptor's properties.

Why it matters for MCP

MCP servers that handle uploads, temporary files, or user-named paths are the most common offenders. The check-then-use pattern is intuitive but unsafe; opening first, checking second is the safe pattern but feels backwards to most developers.

Vulnerable example

example.py
1
import os
2
3
@server.tool()
4
def safe_read(path: str) -> str:
5
    if not os.path.isfile(path):
6
        raise ValueError("not a file")
7
    if os.stat(path).st_size > 1_000_000:
8
        raise ValueError("too large")
9
    with open(path) as f:
10
        return f.read()

Secure example

example.py
1
import os
2
3
@server.tool()
4
def safe_read(path: str) -> str:
5
    fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
6
    try:
7
        st = os.fstat(fd)
8
        if not stat.S_ISREG(st.st_mode):
9
            raise ValueError("not a regular file")
10
        if st.st_size > 1_000_000:
11
            raise ValueError("too large")
12
        return os.fdopen(fd).read()
13
    except BaseException:
14
        os.close(fd)
15
        raise

How MCPSafe detects this

MCPSafe flags Python files where `os.path.isfile(p)` / `os.stat(p)` / `Path(p).is_file()` is followed by `open(p)` / `Path(p).read_text()` against the same variable. JS-side flags `fs.existsSync(p)` followed by `fs.readFileSync(p)`. Atomic alternatives (`os.open` + `os.fstat`) are exempted.

See the full threat catalog for every documented detection.

Further reading

  • CWE-367: TOCTOU Race Condition
  • OWASP: Race Condition

Scan an MCP server for this issue

MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.

Scan now