fix(security): patch SQL injection, path traversal, command injection

This commit is contained in:
admin 2025-12-17 19:30:35 -06:00
parent 2a523af1db
commit b8c130c73d
5 changed files with 38 additions and 11 deletions

View file

@ -69,6 +69,8 @@ private void ExtractZip(string compressedFile, string destination)
throw new IOException(string.Format("File {0} failed archive validation.", compressedFile));
}
var destinationFullPath = Path.GetFullPath(destination);
foreach (ZipEntry zipEntry in zipFile)
{
if (!zipEntry.IsFile)
@ -85,7 +87,16 @@ private void ExtractZip(string compressedFile, string destination)
var zipStream = zipFile.GetInputStream(zipEntry);
// Manipulate the output filename here as desired.
var fullZipToPath = Path.Combine(destination, entryFileName);
var fullZipToPath = Path.GetFullPath(Path.Combine(destination, entryFileName));
// Prevent path traversal attacks - ensure extracted path is within destination
if (!fullZipToPath.StartsWith(destinationFullPath + Path.DirectorySeparatorChar) &&
!fullZipToPath.Equals(destinationFullPath, StringComparison.Ordinal))
{
_logger.Warn("Skipping zip entry with path traversal attempt: {0}", entryFileName);
continue;
}
var directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
{

View file

@ -356,17 +356,17 @@ private List<Process> GetProcessesByName(string name)
{
if (OsInfo.IsWindows && path.EndsWith(".bat", StringComparison.InvariantCultureIgnoreCase))
{
return ("cmd.exe", $"/c {path} {args}");
return ("cmd.exe", $"/c \"{path}\" {args}");
}
if (OsInfo.IsWindows && path.EndsWith(".ps1", StringComparison.InvariantCultureIgnoreCase))
{
return ("powershell.exe", $"-ExecutionPolicy Bypass -NoProfile -File {path} {args}");
return ("powershell.exe", $"-ExecutionPolicy Bypass -NoProfile -File \"{path}\" {args}");
}
if (OsInfo.IsWindows && path.EndsWith(".py", StringComparison.InvariantCultureIgnoreCase))
{
return ("python.exe", $"{path} {args}");
return ("python.exe", $"\"{path}\" {args}");
}
return (path, args);

View file

@ -31,19 +31,17 @@ public void Clean()
.SelectMany(v => GetUsedTags(v, mapper))
.Concat(GetAutoTaggingTagSpecificationTags(mapper))
.Distinct()
.ToList();
.ToArray();
if (usedTags.Any())
{
var usedTagsList = usedTags.Select(d => d.ToString()).Join(",");
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" = ANY (\'{{{usedTagsList}}}\'::int[])");
mapper.Execute("DELETE FROM \"Tags\" WHERE NOT \"Id\" = ANY (@UsedTags)", new { UsedTags = usedTags });
}
else
{
mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" IN ({usedTagsList})");
mapper.Execute("DELETE FROM \"Tags\" WHERE \"Id\" NOT IN @UsedTags", new { UsedTags = usedTags });
}
}
else

View file

@ -27,7 +27,15 @@ public override string Map(string resourceUrl)
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
path = path.Trim(Path.DirectorySeparatorChar);
var resourcePath = Path.Combine(_appFolderInfo.GetAppDataPath(), path);
var basePath = Path.GetFullPath(_appFolderInfo.GetAppDataPath());
var resourcePath = Path.GetFullPath(Path.Combine(basePath, path));
// Prevent path traversal attacks - ensure path stays within AppData folder
if (!resourcePath.StartsWith(basePath + Path.DirectorySeparatorChar) &&
!resourcePath.Equals(basePath, StringComparison.Ordinal))
{
return null;
}
if (!_diskProvider.FileExists(resourcePath) || _diskProvider.GetFileSize(resourcePath) == 0)
{

View file

@ -23,7 +23,17 @@ public override string Map(string resourceUrl)
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
path = path.Trim(Path.DirectorySeparatorChar);
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path);
var basePath = Path.GetFullPath(Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder));
var fullPath = Path.GetFullPath(Path.Combine(basePath, path));
// Prevent path traversal attacks - ensure path stays within UI folder
if (!fullPath.StartsWith(basePath + Path.DirectorySeparatorChar) &&
!fullPath.Equals(basePath, StringComparison.Ordinal))
{
return null;
}
return fullPath;
}
public override bool CanHandle(string resourceUrl)