diff --git a/src/HtmlSanitizer/HtmlSanitizer.cs b/src/HtmlSanitizer/HtmlSanitizer.cs
index bb7443e..d612581 100644
--- a/src/HtmlSanitizer/HtmlSanitizer.cs
+++ b/src/HtmlSanitizer/HtmlSanitizer.cs
@@ -99,6 +99,8 @@ public HtmlSanitizer(HtmlSanitizerOptions options)
AllowedClasses = new HashSet(options.AllowedCssClasses, StringComparer.OrdinalIgnoreCase);
AllowedCssProperties = new HashSet(options.AllowedCssProperties, StringComparer.OrdinalIgnoreCase);
AllowedAtRules = new HashSet(options.AllowedAtRules);
+ AllowCssCustomProperties = options.AllowCssCustomProperties;
+ AllowDataAttributes = options.AllowDataAttributes;
}
///
@@ -204,6 +206,11 @@ public HtmlSanitizer(HtmlSanitizerOptions options)
///
public ISet AllowedCssProperties { get; private set; }
+ ///
+ /// Allow all custom CSS properties (variables) prefixed with --.
+ ///
+ public bool AllowCssCustomProperties { get; set; }
+
///
/// Gets or sets a regex that must not match for legal CSS property values.
///
@@ -726,6 +733,19 @@ protected void SanitizeStyle(IElement element, string baseUrl)
SanitizeStyleDeclaration(element, styles, baseUrl);
}
+ ///
+ /// Verify if the given CSS property name is allowed. By default this will
+ /// check if the property is in the set,
+ /// or if the property is a custom property and is true.
+ ///
+ /// The name of the CSS property.
+ /// True if the property is allowed or not.
+ protected virtual bool IsAllowedCssProperty(string propertyName)
+ {
+ return AllowedCssProperties.Contains(propertyName)
+ || AllowCssCustomProperties && propertyName != null && propertyName.StartsWith("--");
+ }
+
private void SanitizeStyleDeclaration(IElement element, ICssStyleDeclaration styles, string baseUrl)
{
var removeStyles = new List>();
@@ -736,7 +756,7 @@ private void SanitizeStyleDeclaration(IElement element, ICssStyleDeclaration sty
var key = DecodeCss(style.Name);
var val = DecodeCss(style.Value);
- if (!AllowedCssProperties.Contains(key))
+ if (!IsAllowedCssProperty(key))
{
removeStyles.Add(new Tuple(style, RemoveReason.NotAllowedStyle));
continue;
diff --git a/src/HtmlSanitizer/HtmlSanitizerOptions.cs b/src/HtmlSanitizer/HtmlSanitizerOptions.cs
index 05e38e1..def25da 100644
--- a/src/HtmlSanitizer/HtmlSanitizerOptions.cs
+++ b/src/HtmlSanitizer/HtmlSanitizerOptions.cs
@@ -43,5 +43,15 @@ public class HtmlSanitizerOptions
/// Gets or sets the HTML attributes that can contain a URI such as "href".
///
public ISet UriAttributes { get; set; } = new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ ///
+ /// Allow all custom CSS properties (variables) prefixed with --.
+ ///
+ public bool AllowCssCustomProperties { get; set; }
+
+ ///
+ /// Allow all HTML5 data attributes; the attributes prefixed with data-.
+ ///
+ public bool AllowDataAttributes { get; set; }
}
}
diff --git a/test/HtmlSanitizer.Tests/Tests.cs b/test/HtmlSanitizer.Tests/Tests.cs
index a8ad6d0..aec4a6e 100644
--- a/test/HtmlSanitizer.Tests/Tests.cs
+++ b/test/HtmlSanitizer.Tests/Tests.cs
@@ -2903,7 +2903,7 @@ public void ThreadTest()
var waiting = numThreads;
var methods = typeof(HtmlSanitizerTests).GetTypeInfo().GetMethods()
.Where(m => m.GetCustomAttributes(typeof(Xunit.FactAttribute), false).Cast().Any(f => f.Skip == null))
- .Where(m => m.Name != "ThreadTest" && m.Name != "HexColorTest");
+ .Where(m => m.Name != nameof(ThreadTest) && m.Name != nameof(HexColorTest));
var threads = Shuffle(methods, random)
.Take(numThreads)
.Select(m => new Thread(() =>
@@ -3589,4 +3589,44 @@ public void KeepChildNodesTextTest()
var sanitized = sanitizer.Sanitize(input);
Assert.Equal("<img><img>", sanitized);
}
+
+ [Fact]
+ public void AllowStyleAttributeCssCustomPropertiesTest()
+ {
+ var input = "";
+ var sanitizer = new HtmlSanitizer { AllowCssCustomProperties = true };
+ sanitizer.AllowedTags.Remove("iframe");
+ var sanitized = sanitizer.Sanitize(input);
+ Assert.Equal("", sanitized);
+ }
+
+ [Fact]
+ public void AllowStyleTagCssCustomPropertiesTest()
+ {
+ var input = "";
+ var sanitizer = new HtmlSanitizer { AllowCssCustomProperties = true };
+ sanitizer.AllowedTags.Add("style");
+ var sanitized = sanitizer.Sanitize(input);
+ Assert.Equal("", sanitized);
+ }
+
+ [Fact]
+ public void DisallowStyleAttributeCssCustomPropertiesTest()
+ {
+ var input = "";
+ var sanitizer = new HtmlSanitizer();
+ sanitizer.AllowedTags.Remove("iframe");
+ var sanitized = sanitizer.Sanitize(input);
+ Assert.Equal("", sanitized);
+ }
+
+ [Fact]
+ public void DisallowStyleTagCssCustomPropertiesTest()
+ {
+ var input = "";
+ var sanitizer = new HtmlSanitizer();
+ sanitizer.AllowedTags.Add("style");
+ var sanitized = sanitizer.Sanitize(input);
+ Assert.Equal("", sanitized);
+ }
}