CWE-31 covers path traversal using multiple internal backslash dot-dot sequences, as in "dir....\filename". The product builds a path from external input and does not neutralize these sequences, so the path ends up outside the directory it was supposed to stay in.
MITRE explains that the manipulation helps bypass some protection schemes, and gives two reasons. Some programs remove only one ".." sequence, so multiple sequences survive. Or the code checks for ".." at the start of the input, and the attacker moves up more than one level after a normal looking directory name.
How it happens
Picture a cleanup routine that finds ".." in the input and removes it once. A single sequence disappears and the code feels safe. Send "dir....\filename" and one sequence remains after the pass. The path still climbs.
The same logic fails for start-of-string checks. "dir" looks harmless. The two climbs after it carry the path above the directory where it began, and out of the restricted tree if that tree is only a level or two deep.
Both failures share a cause. The code reasons about characters in the input instead of the location the path resolves to.
What an attacker gains
MITRE lists reading files or directories and modifying files or directories. The observed case is CVE-2002-0160, where the administration function in an access control server let remote attackers read HTML, Java class and image files outside the web root through a "...." sequence in the URL to port 2002.
Note what that shows. The exposed file types were not exotic. Class files and web content can reveal how a product works, which helps the next step of an attack.
How to find it
Automated static analysis can trace external input into file access calls. In testing, vary the depth. A test with one climb can pass while two or three climbs succeed. Try several levels, and try both slash types.
How to fix it
- Resolve the complete path first, using the platform resolver.
- Compare the result to the permitted base, component by component.
- If you remove sequences at all, repeat until the string stops changing, and still verify the resolved path afterward. Rejecting the input is cleaner than repairing it.
- Use identifiers for files wherever the client does not need to name one.
- Limit the service account to the content directory.
A short C# version of the resolve and compare step:
string baseDir = Path.GetFullPath(@"C:\app\files") + Path.DirectorySeparatorChar;
string full = Path.GetFullPath(Path.Combine(baseDir, userInput));
if (!full.StartsWith(baseDir, StringComparison.OrdinalIgnoreCase))
throw new UnauthorizedAccessException("outside base directory");
The trailing separator on the base matters, since without it a sibling folder with a similar name would pass the prefix test.
Quick check
Why does depth matter when testing?
Filters that strip one sequence fail only when more than one is present. Testing a single climb never reaches that case.