mirror of
https://github.com/Radarr/Radarr
synced 2026-05-09 09:44:02 +02:00
fix(security): patch SQL injection, path traversal, command injection
This commit is contained in:
parent
2a523af1db
commit
b8c130c73d
5 changed files with 38 additions and 11 deletions
|
|
@ -69,6 +69,8 @@ private void ExtractZip(string compressedFile, string destination)
|
||||||
throw new IOException(string.Format("File {0} failed archive validation.", compressedFile));
|
throw new IOException(string.Format("File {0} failed archive validation.", compressedFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var destinationFullPath = Path.GetFullPath(destination);
|
||||||
|
|
||||||
foreach (ZipEntry zipEntry in zipFile)
|
foreach (ZipEntry zipEntry in zipFile)
|
||||||
{
|
{
|
||||||
if (!zipEntry.IsFile)
|
if (!zipEntry.IsFile)
|
||||||
|
|
@ -85,7 +87,16 @@ private void ExtractZip(string compressedFile, string destination)
|
||||||
var zipStream = zipFile.GetInputStream(zipEntry);
|
var zipStream = zipFile.GetInputStream(zipEntry);
|
||||||
|
|
||||||
// Manipulate the output filename here as desired.
|
// 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);
|
var directoryName = Path.GetDirectoryName(fullZipToPath);
|
||||||
if (directoryName.Length > 0)
|
if (directoryName.Length > 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -356,17 +356,17 @@ private List<Process> GetProcessesByName(string name)
|
||||||
{
|
{
|
||||||
if (OsInfo.IsWindows && path.EndsWith(".bat", StringComparison.InvariantCultureIgnoreCase))
|
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))
|
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))
|
if (OsInfo.IsWindows && path.EndsWith(".py", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
return ("python.exe", $"{path} {args}");
|
return ("python.exe", $"\"{path}\" {args}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (path, args);
|
return (path, args);
|
||||||
|
|
|
||||||
|
|
@ -31,19 +31,17 @@ public void Clean()
|
||||||
.SelectMany(v => GetUsedTags(v, mapper))
|
.SelectMany(v => GetUsedTags(v, mapper))
|
||||||
.Concat(GetAutoTaggingTagSpecificationTags(mapper))
|
.Concat(GetAutoTaggingTagSpecificationTags(mapper))
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToList();
|
.ToArray();
|
||||||
|
|
||||||
if (usedTags.Any())
|
if (usedTags.Any())
|
||||||
{
|
{
|
||||||
var usedTagsList = usedTags.Select(d => d.ToString()).Join(",");
|
|
||||||
|
|
||||||
if (_database.DatabaseType == DatabaseType.PostgreSQL)
|
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
|
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
|
else
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,15 @@ public override string Map(string resourceUrl)
|
||||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||||
path = path.Trim(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)
|
if (!_diskProvider.FileExists(resourcePath) || _diskProvider.GetFileSize(resourcePath) == 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,17 @@ public override string Map(string resourceUrl)
|
||||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||||
path = path.Trim(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)
|
public override bool CanHandle(string resourceUrl)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue