aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers
diff options
context:
space:
mode:
authorJoshua M. Boniface <joshua@boniface.me>2026-04-06 09:37:59 -0400
committerGitHub <noreply@github.com>2026-04-06 09:37:59 -0400
commit179db631f73a7e34e89acbdabc555a9d3b92ff6d (patch)
treef3c202a880ee05241ad46c9e54e7a2076e303b9c /MediaBrowser.Providers
parentc008f28d3126186e0a646121a3f69bd1624e37f5 (diff)
parent740e9f8749ccf54afe8c0c2b1ff39a9775ed305b (diff)
Merge pull request #16577 from Bond-009/security-backports
Backport security fixes
Diffstat (limited to 'MediaBrowser.Providers')
-rw-r--r--MediaBrowser.Providers/MediaInfo/ProbeProvider.cs21
-rw-r--r--MediaBrowser.Providers/Subtitles/SubtitleManager.cs30
2 files changed, 45 insertions, 6 deletions
diff --git a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
index 9f5463b82c..c3ff26202f 100644
--- a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
@@ -262,9 +262,28 @@ namespace MediaBrowser.Providers.MediaInfo
private void FetchShortcutInfo(BaseItem item)
{
- item.ShortcutPath = File.ReadAllLines(item.Path)
+ var shortcutPath = File.ReadAllLines(item.Path)
.Select(NormalizeStrmLine)
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i) && !i.StartsWith('#'));
+
+ if (string.IsNullOrWhiteSpace(shortcutPath))
+ {
+ return;
+ }
+
+ // Only allow remote URLs in .strm files to prevent local file access
+ if (Uri.TryCreate(shortcutPath, UriKind.Absolute, out var uri)
+ && (string.Equals(uri.Scheme, "http", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(uri.Scheme, "rtsp", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(uri.Scheme, "rtp", StringComparison.OrdinalIgnoreCase)))
+ {
+ item.ShortcutPath = shortcutPath;
+ }
+ else
+ {
+ _logger.LogWarning("Ignoring invalid or non-remote .strm path in {File}: {Path}", item.Path, shortcutPath);
+ }
}
/// <summary>
diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
index 420dd39a48..a78ec995cf 100644
--- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
+++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Naming.Common;
using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Entities;
@@ -32,6 +33,7 @@ namespace MediaBrowser.Providers.Subtitles
private readonly ILibraryMonitor _monitor;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly ILocalizationManager _localization;
+ private readonly HashSet<string> _allowedSubtitleFormats;
private readonly ISubtitleProvider[] _subtitleProviders;
@@ -41,7 +43,8 @@ namespace MediaBrowser.Providers.Subtitles
ILibraryMonitor monitor,
IMediaSourceManager mediaSourceManager,
ILocalizationManager localizationManager,
- IEnumerable<ISubtitleProvider> subtitleProviders)
+ IEnumerable<ISubtitleProvider> subtitleProviders,
+ NamingOptions namingOptions)
{
_logger = logger;
_fileSystem = fileSystem;
@@ -51,6 +54,9 @@ namespace MediaBrowser.Providers.Subtitles
_subtitleProviders = subtitleProviders
.OrderBy(i => i is IHasOrder hasOrder ? hasOrder.Order : 0)
.ToArray();
+ _allowedSubtitleFormats = new HashSet<string>(
+ namingOptions.SubtitleFileExtensions.Select(e => e.TrimStart('.')),
+ StringComparer.OrdinalIgnoreCase);
}
/// <inheritdoc />
@@ -171,6 +177,12 @@ namespace MediaBrowser.Providers.Subtitles
/// <inheritdoc />
public Task UploadSubtitle(Video video, SubtitleResponse response)
{
+ var format = response.Format;
+ if (string.IsNullOrEmpty(format) || !_allowedSubtitleFormats.Contains(format))
+ {
+ throw new ArgumentException($"Unsupported subtitle format: '{format}'");
+ }
+
var libraryOptions = BaseItem.LibraryManager.GetLibraryOptions(video);
return TrySaveSubtitle(video, libraryOptions, response);
}
@@ -193,7 +205,13 @@ namespace MediaBrowser.Providers.Subtitles
}
var savePaths = new List<string>();
- var saveFileName = Path.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLowerInvariant();
+ var language = response.Language.ToLowerInvariant();
+ if (language.AsSpan().IndexOfAny(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) >= 0)
+ {
+ throw new ArgumentException("Language contains invalid characters.");
+ }
+
+ var saveFileName = Path.GetFileNameWithoutExtension(video.Path) + "." + language;
if (response.IsForced)
{
@@ -230,11 +248,13 @@ namespace MediaBrowser.Providers.Subtitles
foreach (var savePath in savePaths)
{
- var path = savePath + "." + extension;
+ var path = Path.GetFullPath(savePath + "." + extension);
try
{
- if (path.StartsWith(video.ContainingFolderPath, StringComparison.Ordinal)
- || path.StartsWith(video.GetInternalMetadataPath(), StringComparison.Ordinal))
+ var containingFolder = video.ContainingFolderPath + Path.DirectorySeparatorChar;
+ var metadataFolder = video.GetInternalMetadataPath() + Path.DirectorySeparatorChar;
+ if (path.StartsWith(containingFolder, StringComparison.Ordinal)
+ || path.StartsWith(metadataFolder, StringComparison.Ordinal))
{
var fileExists = File.Exists(path);
var counter = 0;