diff --git a/QuickLook/Helpers/ExtensionFilterHelper.cs b/QuickLook/Helpers/ExtensionFilterHelper.cs
new file mode 100644
index 000000000..0027e2919
--- /dev/null
+++ b/QuickLook/Helpers/ExtensionFilterHelper.cs
@@ -0,0 +1,198 @@
+// Copyright © 2017-2025 QL-Win Contributors
+//
+// This file is part of QuickLook program.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using QuickLook.Common.Helpers;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace QuickLook.Helpers;
+
+///
+/// Helper class for managing file extension allowlist/blocklist filtering.
+///
+/// Blocklist mode (default): All extensions are allowed except those in the blocklist.
+/// If the blocklist is empty, all files are allowed.
+///
+///
+/// Allowlist mode: Only extensions in the allowlist can be previewed.
+/// If the allowlist is empty in allowlist mode, all files are allowed (no filtering).
+///
+///
+/// Directories and files without extensions are always allowed regardless of the mode.
+///
+///
+public static class ExtensionFilterHelper
+{
+ private const string AllowlistKey = "ExtensionAllowlist";
+ private const string BlocklistKey = "ExtensionBlocklist";
+ private const string UseAllowlistModeKey = "UseExtensionAllowlistMode";
+ private static readonly char[] ExtensionSeparators = [';', ','];
+
+ private static HashSet _allowlistCache;
+ private static HashSet _blocklistCache;
+ private static bool? _useAllowlistModeCache;
+
+ ///
+ /// Gets or sets whether to use allowlist mode.
+ /// When true, only extensions in the allowlist can be previewed.
+ /// When false (default), extensions in the blocklist are blocked from preview.
+ ///
+ public static bool UseAllowlistMode
+ {
+ get
+ {
+ _useAllowlistModeCache ??= SettingHelper.Get(UseAllowlistModeKey, false);
+ return _useAllowlistModeCache.Value;
+ }
+ set
+ {
+ _useAllowlistModeCache = value;
+ SettingHelper.Set(UseAllowlistModeKey, value);
+ }
+ }
+
+ ///
+ /// Gets the current allowlist of file extensions.
+ /// Extensions should be in the format ".ext" (with leading dot).
+ ///
+ public static HashSet Allowlist
+ {
+ get
+ {
+ if (_allowlistCache == null)
+ {
+ var list = SettingHelper.Get(AllowlistKey, string.Empty);
+ _allowlistCache = ParseExtensionList(list);
+ }
+ return _allowlistCache;
+ }
+ }
+
+ ///
+ /// Gets the current blocklist of file extensions.
+ /// Extensions should be in the format ".ext" (with leading dot).
+ ///
+ public static HashSet Blocklist
+ {
+ get
+ {
+ if (_blocklistCache == null)
+ {
+ var list = SettingHelper.Get(BlocklistKey, string.Empty);
+ _blocklistCache = ParseExtensionList(list);
+ }
+ return _blocklistCache;
+ }
+ }
+
+ ///
+ /// Sets the allowlist of file extensions.
+ ///
+ /// Collection of extensions in the format ".ext" (with leading dot).
+ public static void SetAllowlist(IEnumerable extensions)
+ {
+ var normalized = NormalizeExtensions(extensions);
+ _allowlistCache = normalized;
+ SettingHelper.Set(AllowlistKey, string.Join(";", normalized));
+ }
+
+ ///
+ /// Sets the blocklist of file extensions.
+ ///
+ /// Collection of extensions in the format ".ext" (with leading dot).
+ public static void SetBlocklist(IEnumerable extensions)
+ {
+ var normalized = NormalizeExtensions(extensions);
+ _blocklistCache = normalized;
+ SettingHelper.Set(BlocklistKey, string.Join(";", normalized));
+ }
+
+ ///
+ /// Checks if a file path is allowed for preview based on the current filter settings.
+ ///
+ /// The file path to check.
+ /// True if the file is allowed for preview, false if it should be blocked.
+ public static bool IsExtensionAllowed(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ return true;
+
+ var extension = Path.GetExtension(path);
+
+ // Files without extensions are always allowed (includes directories)
+ if (string.IsNullOrEmpty(extension))
+ return true;
+
+ extension = extension.ToLowerInvariant();
+
+ if (UseAllowlistMode)
+ {
+ // In allowlist mode: only allow if extension is in the allowlist
+ // If allowlist is empty, allow all (no filtering)
+ return Allowlist.Count == 0 || Allowlist.Contains(extension);
+ }
+ else
+ {
+ // In blocklist mode: block if extension is in the blocklist
+ return !Blocklist.Contains(extension);
+ }
+ }
+
+ ///
+ /// Clears the cached settings, forcing a reload from the config file.
+ ///
+ public static void ClearCache()
+ {
+ _allowlistCache = null;
+ _blocklistCache = null;
+ _useAllowlistModeCache = null;
+ }
+
+ private static HashSet ParseExtensionList(string list)
+ {
+ if (string.IsNullOrWhiteSpace(list))
+ return new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ return new HashSet(
+ list.Split(ExtensionSeparators, StringSplitOptions.RemoveEmptyEntries)
+ .Select(NormalizeExtension)
+ .Where(e => !string.IsNullOrEmpty(e)),
+ StringComparer.OrdinalIgnoreCase);
+ }
+
+ private static HashSet NormalizeExtensions(IEnumerable extensions)
+ {
+ return new HashSet(
+ extensions.Select(NormalizeExtension).Where(e => !string.IsNullOrEmpty(e)),
+ StringComparer.OrdinalIgnoreCase);
+ }
+
+ private static string NormalizeExtension(string ext)
+ {
+ if (string.IsNullOrWhiteSpace(ext))
+ return null;
+
+ ext = ext.Trim().ToLowerInvariant();
+ if (!ext.StartsWith("."))
+ ext = "." + ext;
+
+ return ext;
+ }
+}
+
diff --git a/QuickLook/ViewWindowManager.cs b/QuickLook/ViewWindowManager.cs
index ee1ce2bdd..563ead67b 100644
--- a/QuickLook/ViewWindowManager.cs
+++ b/QuickLook/ViewWindowManager.cs
@@ -151,10 +151,15 @@ public void InvokePreview(string path = null)
if (_viewerWindow.IsVisible && path == _invokedPath)
return;
- if (!Directory.Exists(path) && !File.Exists(path))
+ var isDirectory = Directory.Exists(path);
+ if (!isDirectory && !File.Exists(path))
if (!path.StartsWith("::")) // CLSID
return;
+ // Check extension filtering before proceeding (skip for directories)
+ if (!isDirectory && !ExtensionFilterHelper.IsExtensionAllowed(path))
+ return;
+
_invokedPath = path;
RunFocusMonitor();
@@ -172,7 +177,12 @@ public void InvokePluginPreview(string plugin, string path = null)
if (string.IsNullOrEmpty(path))
return;
- if (!Directory.Exists(path) && !File.Exists(path))
+ var isDirectory = Directory.Exists(path);
+ if (!isDirectory && !File.Exists(path))
+ return;
+
+ // Check extension filtering before proceeding (skip for directories)
+ if (!isDirectory && !ExtensionFilterHelper.IsExtensionAllowed(path))
return;
RunFocusMonitor();