CWE-182, Collapse of Data into Unsafe Value, describes a filter that reduces or "collapses" input into a value that violates a security property. The filter meant to clean the data is the thing that makes it unsafe.
Web servers and anything that sanitises paths are the common home of this bug.
How it happens
Think of a filter that deletes every occurrence of "./" from a path. Feed it "..//" patterns with extra characters and the deletion pulls the survivors together. One pass removes the evil pieces, but what is left spells something new.
MITRE's observed examples are all path collapses. In CVE-2004-0815, a string of "/.////" in a pathname collapsed to an absolute path. In CVE-2005-3123, "/.//..//////././" was collapsed into "/.././" after dot dot and double slash sequences were removed. CVE-2002-0325 describes ".../...//" collapsing to "..." because "./" was removed. In CVE-2002-0784, an HTTP server guarded against "..", but variants such as "////./../.../" allowed a result that collapsed into the unsafe "////../".
# Vulnerable: single pass removal
def clean(p):
return p.replace("../", "") # "....//" becomes "../"
# Fixed: resolve the path properly and check where it lands
import os
def clean(p, base="/srv/data"):
full = os.path.realpath(os.path.join(base, p))
if not full.startswith(base + os.sep):
raise ValueError("outside base")
return full
What an attacker gains
MITRE lists access control impact through bypass of a protection mechanism. In the examples, that meant reaching files outside the intended folder.
How to find it
MITRE says automated static analysis (SAST) can find some instances by modelling data flow in source or compiled code. Add targeted tests: feed nested and interleaved sequences and check the final value. Reviewers should flag any replace-and-remove approach to sanitising paths.
How to fix it
The record lists no mitigations, so these are general practice.
- Do not sanitise by deleting substrings. Resolve the path with the platform call, then compare against the allowed base.
- If you must filter, loop until the value stops changing, then validate it.
- Prefer allowlists of expected names.
Quick check
Why does one pass of removal fail?
Removing a pattern can bring the surrounding characters together into the same pattern. Resolving the whole path avoids that.