Two slashes at the start of a path look like a typo. On many systems //etc/passwd and /etc/passwd mean the same thing, and that is the foothold for CWE-50, path equivalence using multiple leading slashes, //multiple/leading/slash. The product accepts that form without appropriate validation and ends up with ambiguous path resolution.
It is one branch of the path equivalence family under CWE-41, and it is easy to confuse with the absolute path cases such as CWE-36. The difference is the purpose. Here the extra slash is used to produce a second name for something the attacker may already be able to name, so that a rule written against one form misses it.
Anything that takes a path from a request, a message or a file and applies a rule before opening it can be affected. The weakness is not language specific.
How it happens
A rule compares the beginning of the string. It may say deny paths that start with /etc/, or require authentication when the path starts with /private/. A request that starts with // fails the comparison. The file system, however, collapses repeated separators and resolves the same file.
The record's examples show how consistently that has worked against servers:
- A server allowed remote attackers to read arbitrary files via a GET request with more than one leading slash in the filename (CVE-1999-1456).
- A server allowed reading arbitrary files via leading slash characters in a URL request (CVE-2004-0578).
- A server allowed attackers to bypass authentication and read restricted files via an extra slash in the requested URL (CVE-2002-0275).
- Reading files with a full pathname using a multiple internal slash (CVE-2002-1483), which also connects to CWE-51.
The entries are old, but the logic is not tied to any one era. It appears whenever the rule layer and the file layer normalize a path at different times.
# Vulnerable: prefix check on the raw request path
def allowed(path, user):
if path.startswith("/private/") and not user.logged_in:
return False
return True
# allowed("//private/report.pdf", anon) -> True
# the file layer later reads /private/report.pdf
What an attacker gains
MITRE lists reading and modifying files and directories, which maps to confidentiality and integrity impact. The record adds a specific flavor: authentication bypass plus reading of files that were supposed to be restricted. If the readable file holds credentials or keys, the damage extends beyond the one file.
How to find it
The record lists no specific detection technique, so rely on direct tests and review.
- Find every point where a path or URL is compared with a string, a prefix or a pattern to make an allow or deny decision.
- Note which layer does the comparison and which layer opens the file. Different layers are a warning sign.
- In a staging environment, request protected resources with a doubled leading slash, a doubled internal slash and a doubled trailing slash. Compare status and body to the plain request.
- Test through every hop. A reverse proxy and an application server may normalize differently, and the gap sits between them.
How to fix it
The principle is to compare only canonical paths. In practice:
- Normalize once, early, at the edge of your code, using the platform's own path function.
- Make every later check, in every layer you control, use the normalized value.
- Use a deny by default policy. Authentication should be required for an area, with specific public routes opened on purpose, rather than the reverse.
- Prefer directory or prefix rules applied to canonical paths over exact string matches.
- Reject input that is not already in canonical form if you can afford to, and answer with a 400 or a redirect to the clean URL.
- Enforce permissions in the file system too, so a bypass in one layer does not hand over the file.
import posixpath
from urllib.parse import unquote
def canonical(raw):
p = posixpath.normpath("/" + unquote(raw).lstrip("/"))
return p
p = canonical(request.path)
if p.startswith("/private/") and not user.logged_in:
abort(401)
For a vulnerability in a third party web server or proxy rather than your own code, the fix is to update the component. The free dependency scan at gold.safeguard.sh/scan runs in your browser with no login, keeps the file on your machine and covers up to 100 dependencies. Reachability analysis then tells you whether your code actually calls the affected function.
Quick check
Why does a doubled leading slash bypass a prefix check?
The string no longer begins with the protected prefix, so the rule does not match. The file system treats repeated slashes as one, so it still opens the protected file.
Which fix closes the whole class?
Normalize the path once, early, and run every access decision on the normalized value, with deny as the default.
Why test through a proxy as well as the application?
Two components may normalize differently. A request that the proxy considers safe can still resolve to a protected file in the application behind it.