I have a rootPath
that I trust and a relativePath
that I don't. I want to combine them in such a way that I can be sure that the result is under rootPath
and that the user can't use ..
to get back past the starting point. I do want the relative path to allow things like: hello\..\world
== world

- 61,417
- 20
- 137
- 189

- 75,627
- 68
- 187
- 294
3 Answers
To expand: use Path.Combine, then call GetFullPath on the result and check that that result starts with rootPath.
It won't protect you against hardlinks, but it should catch simple things like double-dots.
the above as code:
string Resolve(string fileName)
{
string root = FileRoot();
string ret = Path.GetFullPath(Path.Combine(root, fileName));
if (ret.StartsWith(root.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar)) return ret;
throw new ArgumentException("path resolved to out of accesable directroy");
}

- 3,556
- 1
- 20
- 24
-
4However, if root does not end with \, it's still possible to play a limited trick -- end up in a different directory, a sibling of the root one, which starts with that as a prefix. E.g., root may be \zip\zop, relative path ..\zopper\zup, you end up in \zip\zopper\zup, outside of the tree rooted in \zip\zop but still satisfying the StartsWith test. Small risk, but not zero. – Alex Martelli Apr 29 '09 at 23:48
-
1You can mitigate that attack by using .StartsWith(root.TrimEnd('\\') + '\\'), to ensure the correct path is used. – technophile Apr 29 '09 at 23:52
You could just call Path.GetFullPath()
and check if it starts with your trusted rootPath
. If you tend to paranoia, check also that rootPath
is rooted.
public Boolean IsPathSafe(String rootPath, String relativePath)
{
return rootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
Path.IsPathRooted(rootPath) &&
Path.Combine(rootPath, relativePath).GetFullPath().StartsWith(rootPath);
}
For an explaination of the first test see Alex Martelli's comment on technophile's answer.

- 3,257
- 3
- 30
- 39

- 59,031
- 16
- 99
- 143
One thing you can do is to count the number of backslashes (\
) and double-dots (..
), and make sure that the number of double-dots is smaller than the number of backslashes. In order to go above the rootPath
in your folder structure, you'll need at least as many backslashes as double dots - thus, if you only allow relativePath
s with at least one more backslash, you should be safe.

- 58,548
- 56
- 243
- 402