Skip to content

Commit 3a68fa5

Browse files
MikeAlhayekCopilot
andcommitted
fix: Prevent path traversal in FileSystemFileStore
Resolve CodeQL 'Uncontrolled data used in path expression' alerts by validating that resolved file paths stay within the base directory. Uses Path.GetFullPath() canonicalization and prefix check to block directory traversal via ../ sequences in user-supplied file names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b1bed23 commit 3a68fa5

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

src/Startup/CrestApps.Mvc.Web/Services/FileSystemFileStore.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ public sealed class FileSystemFileStore
66

77
public FileSystemFileStore(string basePath)
88
{
9-
_basePath = basePath;
10-
Directory.CreateDirectory(basePath);
9+
_basePath = Path.GetFullPath(basePath);
10+
Directory.CreateDirectory(_basePath);
1111
}
1212

1313
public async Task<string> SaveFileAsync(string fileName, Stream content)
1414
{
15-
var filePath = Path.Combine(_basePath, fileName);
15+
var filePath = GetSafePath(fileName);
1616
var directory = Path.GetDirectoryName(filePath);
1717
Directory.CreateDirectory(directory);
1818

@@ -24,7 +24,7 @@ public async Task<string> SaveFileAsync(string fileName, Stream content)
2424

2525
public Task<Stream> GetFileAsync(string fileName)
2626
{
27-
var filePath = Path.Combine(_basePath, fileName);
27+
var filePath = GetSafePath(fileName);
2828

2929
if (!File.Exists(filePath))
3030
{
@@ -36,7 +36,7 @@ public Task<Stream> GetFileAsync(string fileName)
3636

3737
public Task<bool> DeleteFileAsync(string fileName)
3838
{
39-
var filePath = Path.Combine(_basePath, fileName);
39+
var filePath = GetSafePath(fileName);
4040

4141
if (File.Exists(filePath))
4242
{
@@ -46,4 +46,17 @@ public Task<bool> DeleteFileAsync(string fileName)
4646

4747
return Task.FromResult(false);
4848
}
49+
50+
private string GetSafePath(string fileName)
51+
{
52+
var fullPath = Path.GetFullPath(Path.Combine(_basePath, fileName));
53+
54+
if (!fullPath.StartsWith(_basePath + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)
55+
&& !string.Equals(fullPath, _basePath, StringComparison.OrdinalIgnoreCase))
56+
{
57+
throw new ArgumentException("The file name contains an invalid path.");
58+
}
59+
60+
return fullPath;
61+
}
4962
}

0 commit comments

Comments
 (0)