csharp.lang.security.filesystem.unsafe-path-combine.unsafe-path-combine
semgrep
Author
unknown
Download Count*
License
String argument $A is used to read or write data from a file via Path.Combine without direct sanitization via Path.GetFileName. If the path is user-supplied data this can lead to path traversal.
Run Locally
Run in CI
Defintion
rules:
- id: unsafe-path-combine
mode: taint
pattern-sources:
- patterns:
- pattern: $A
- pattern-inside: |
Path.Combine(...,$A,...)
- pattern-inside: |
public $TYPE $M(...,$A,...){...}
- pattern-not-inside: |
<... Path.GetFileName($A) != $A ...>
pattern-sinks:
- patterns:
- focus-metavariable: $X
- pattern: |
File.$METHOD($X,...)
- metavariable-regex:
metavariable: $METHOD
regex: (?i)^(read|write)
pattern-sanitizers:
- pattern: |
Path.GetFileName(...)
- patterns:
- pattern-inside: |
$X = Path.GetFileName(...);
...
- pattern: $X
- patterns:
- pattern: $X
- pattern-inside: |
if(<... Path.GetFileName($X) != $X ...>){
...
throw new $EXCEPTION(...);
}
...
message: String argument $A is used to read or write data from a file via
Path.Combine without direct sanitization via Path.GetFileName. If the path
is user-supplied data this can lead to path traversal.
languages:
- csharp
severity: WARNING
metadata:
category: security
confidence: MEDIUM
references:
- https://www.praetorian.com/blog/pathcombine-security-issues-in-aspnet-applications/
- https://docs.microsoft.com/en-us/dotnet/api/system.io.path.combine?view=net-6.0#remarks
technology:
- .net
cwe:
- "CWE-22: Improper Limitation of a Pathname to a Restricted Directory
('Path Traversal')"
owasp:
- A05:2017 - Broken Access Control
- A01:2021 - Broken Access Control
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- vuln
likelihood: LOW
impact: MEDIUM
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
vulnerability_class:
- Path Traversal
Examples
unsafe-path-combine.cs
public class Foo{
public static bytes[] GetFileBad(string filename) {
// Ensure that all path elements are safe path elements.
if (string.IsNullOrEmpty(filename))
{
throw new ArgumentNullException("error");
}
string filepath = Path.Combine("\\FILESHARE\images", filename);
// ruleid: unsafe-path-combine
return File.ReadAllBytes(filepath);
}
public static bytes[] GetFileSafe(string filename) {
// Ensure that all path elements are safe path elements.
if (string.IsNullOrEmpty(filename))
{
throw new ArgumentNullException("error");
}
filename = Path.GetFileName(filename);
// ok: unsafe-path-combine
string filepath = Path.Combine("\\FILESHARE\images", filename);
return File.ReadAllBytes(filepath);
}
public static bytes[] GetFileSafe2(string filename) {
// Ensure that all path elements are safe path elements.
if (string.IsNullOrEmpty(filename) || Path.GetFileName(filename) != filename)
{
throw new ArgumentNullException("error");
}
string filepath = Path.Combine("\\FILESHARE\images", filename);
// ok: unsafe-path-combine
return File.ReadAllBytes(filepath);
}
public static bytes[] GetFileSafe3(string filename) {
// Ensure that all path elements are safe path elements.
if (string.IsNullOrEmpty(filename))
{
throw new ArgumentNullException("error");
}
// ok: unsafe-path-combine
string filepath = Path.Combine("\\FILESHARE\images", Path.GetFileName(filename));
}
public static bytes[] GetFileSafe4(string filename) {
// Ensure that all path elements are safe path elements.
if (string.IsNullOrEmpty(filename))
{
throw new ArgumentNullException("error");
}
string otherPath = Path.GetFileName(filename);
string safePath = Path.Combine("\\FILESHARE\images",otherPath);
// ok: unsafe-path-combine
return File.ReadAllBytes(safePath);
}
}
Short Link: https://sg.run/1RvG