dandruff 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+
6
+ require 'dandruff'
7
+
8
+ # Example usage demonstrating Dandruff Ruby functionality
9
+
10
+ puts 'Dandruff Ruby Examples'
11
+ puts '========================'
12
+ puts
13
+
14
+ # Basic sanitization
15
+ puts '1. Basic sanitization:'
16
+ dirty = '<script>alert("xss")</script><p>Safe content</p>'
17
+ dandruff = Dandruff.new
18
+ clean = dandruff.sanitize(dirty)
19
+ puts " Original: #{dirty}"
20
+ puts " Clean: #{clean}"
21
+ puts
22
+
23
+ # Removing dangerous attributes
24
+ puts '2. Removing dangerous attributes:'
25
+ dirty = '<div onclick="alert(\'xss\')" class="safe">Click me</div>'
26
+ dandruff = Dandruff.new
27
+ clean = dandruff.sanitize(dirty)
28
+ puts " Original: #{dirty}"
29
+ puts " Clean: #{clean}"
30
+ puts
31
+
32
+ # Configuration example
33
+ puts '3. Custom configuration:'
34
+ dandruff = Dandruff.new do |c|
35
+ c.allowed_tags = %w[p b i]
36
+ c.allowed_attributes = ['class']
37
+ end
38
+ dirty = '<p class="text"><b>Bold</b> <i>Italic</i></p>'
39
+ clean = dandruff.sanitize(dirty)
40
+ puts " Original: #{dirty}"
41
+ puts " Clean: #{clean}"
42
+ puts
43
+
44
+ # Data attributes
45
+ puts '4. Data attributes:'
46
+ dirty = '<div data-user="123" data-role="admin">User content</div>'
47
+ dandruff = Dandruff.new
48
+ clean = dandruff.sanitize(dirty)
49
+ puts " Original: #{dirty}"
50
+ puts " Clean: #{clean}"
51
+ puts
52
+
53
+ # Template safety
54
+ puts '5. Template safety:'
55
+ dirty = '<p>{{ user_input }}</p><script>${malicious()}</script>'
56
+ dandruff = Dandruff.new
57
+ clean = dandruff.sanitize(dirty, safe_for_templates: true)
58
+ puts " Original: #{dirty}"
59
+ puts " Clean: #{clean}"
60
+ puts
61
+
62
+ # Hooks example
63
+ puts '6. Using hooks:'
64
+ hook_called = false
65
+ dandruff = Dandruff.new
66
+ dandruff.add_hook(:before_sanitize_elements) do |node, _data, _config|
67
+ hook_called = true
68
+ puts " Hook: Processing #{node.name} element"
69
+ end
70
+
71
+ dandruff.sanitize('<div>Test</div>')
72
+ puts " Hook was called: #{hook_called}"
73
+ puts
74
+
75
+ # Profiles
76
+ puts '7. Using profiles:'
77
+ dandruff = Dandruff.new(use_profiles: { svg: true })
78
+ dirty = '<svg><circle r="10" fill="red"/></svg>'
79
+ clean = dandruff.sanitize(dirty)
80
+ puts " Original: #{dirty}"
81
+ puts " Clean: #{clean}"
82
+ puts
83
+
84
+ puts 'Examples completed!'
@@ -0,0 +1,268 @@
1
+ # HTML Email Sanitization Example
2
+
3
+ This example demonstrates how to use Dandruff to safely sanitize HTML emails for display, protecting against XSS while preserving formatting.
4
+
5
+ ## Use Case
6
+
7
+ When displaying HTML emails from external sources in a web application, you need to:
8
+ - Remove malicious scripts and XSS payloads
9
+ - Preserve email formatting (tables, styling, links)
10
+ - Allow safe email content like images and basic formatting
11
+ - Prevent iframe escape attempts
12
+
13
+ ## Implementation
14
+
15
+ ```ruby
16
+ require 'dandruff'
17
+
18
+ class EmailSanitizer
19
+ def self.sanitize_for_iframe(html_content)
20
+ # Configure Dandruff for email content
21
+ dandruff = Dandruff.new do |c|
22
+ # Allow email-specific tags
23
+ c.allowed_tags = [
24
+ # Basic formatting
25
+ 'p', 'br', 'div', 'span',
26
+ # Text formatting
27
+ 'strong', 'b', 'em', 'i', 'u', 's', 'strike',
28
+ # Headings
29
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
30
+ # Lists
31
+ 'ul', 'ol', 'li', 'dl', 'dt', 'dd',
32
+ # Tables (essential for emails)
33
+ 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'caption',
34
+ # Links and images
35
+ 'a', 'img',
36
+ # Block elements
37
+ 'blockquote', 'hr', 'pre', 'code',
38
+ # Email-specific
39
+ 'font', 'center'
40
+ ]
41
+
42
+ # Allow safe attributes
43
+ c.allowed_attributes = [
44
+ # Links
45
+ 'href', 'title', 'target',
46
+ # Images
47
+ 'src', 'alt', 'width', 'height', 'border',
48
+ # Tables
49
+ 'cellpadding', 'cellspacing', 'colspan', 'rowspan', 'align', 'valign',
50
+ # Text formatting
51
+ 'color', 'size', 'face', 'style', 'class',
52
+ # Lists
53
+ 'type', 'start',
54
+ # General
55
+ 'id', 'dir'
56
+ ]
57
+
58
+ # Security settings
59
+ c.forbidden_tags = ['script', 'iframe', 'object', 'embed', 'form', 'input', 'button']
60
+ c.forbidden_attributes = ['onclick', 'onload', 'onerror', 'onmouseover', 'javascript:']
61
+
62
+ # Allow data attributes for tracking (optional)
63
+ c.allow_data_attributes = true
64
+
65
+ # Allow ARIA attributes for accessibility
66
+ c.allow_aria_attributes = true
67
+
68
+ # Safe for templates (remove template expressions)
69
+ c.safe_for_templates = true
70
+
71
+ # Keep comments for email client compatibility
72
+ c.safe_for_xml = false
73
+
74
+ # Don't return whole document (we want fragment)
75
+ c.whole_document = false
76
+ end
77
+
78
+ # Add hooks for additional security
79
+ add_email_security_hooks(dandruff)
80
+
81
+ # Sanitize the email content
82
+ clean_html = dandruff.sanitize(html_content)
83
+
84
+ # Post-process for iframe safety
85
+ post_process_for_iframe(clean_html)
86
+ end
87
+
88
+ private
89
+
90
+ def self.add_email_security_hooks(dandruff)
91
+ # Hook to sanitize URLs
92
+ dandruff.add_hook(:upon_sanitize_attribute) do |node, data, config|
93
+ case data[:attr_name]
94
+ when 'href'
95
+ # Block dangerous protocols
96
+ href = data[:value]
97
+ if href.match?(/\b(javascript|data|vbscript):/i)
98
+ data[:keep_attr] = false
99
+ end
100
+ when 'src'
101
+ # Only allow http/https protocols for images
102
+ src = data[:value]
103
+ unless src.match?(/\b(https?):/i)
104
+ data[:keep_attr] = false
105
+ end
106
+ when 'style'
107
+ # Remove dangerous CSS
108
+ style = data[:value]
109
+ if style.match?(/(expression|javascript|behavior|import)/i)
110
+ data[:keep_attr] = false
111
+ end
112
+ end
113
+ end
114
+
115
+ # Hook to process table elements
116
+ dandruff.add_hook(:before_sanitize_elements) do |node, data, config|
117
+ # Remove tables with excessive nesting (potential DoS)
118
+ if node.name == 'table'
119
+ depth = count_table_depth(node)
120
+ if depth > 10
121
+ data[:keep_node] = false
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ def self.count_table_depth(node, depth = 0)
128
+ return depth if depth > 10
129
+
130
+ max_depth = depth
131
+ node.children.each do |child|
132
+ if child.name == 'table'
133
+ child_depth = count_table_depth(child, depth + 1)
134
+ max_depth = [max_depth, child_depth].max
135
+ end
136
+ end
137
+
138
+ max_depth
139
+ end
140
+
141
+ def self.post_process_for_iframe(html)
142
+ # Add sandbox attributes if iframe will be used
143
+ # This is typically done in the HTML template, but we document it here
144
+
145
+ # Example iframe usage:
146
+ # <iframe sandbox="allow-same-origin allow-popups allow-popups-to-escape-sandbox"
147
+ # srcdoc="#{sanitized_html}">
148
+ # </iframe>
149
+
150
+ html
151
+ end
152
+ end
153
+
154
+ # Usage example
155
+ class EmailController < ApplicationController
156
+ def show
157
+ # Get email from database or external source
158
+ raw_email = Email.find(params[:id]).html_content
159
+
160
+ # Sanitize for safe display
161
+ @sanitized_email = EmailSanitizer.sanitize_for_iframe(raw_email)
162
+
163
+ # Render with iframe
164
+ # In your view:
165
+ # <iframe sandbox="allow-same-origin allow-popups allow-popups-to-escape-sandbox"
166
+ # srcdoc="#{@sanitized_email}"
167
+ # width="100%" height="600">
168
+ # </iframe>
169
+ end
170
+ end
171
+ ```
172
+
173
+ ## Security Considerations
174
+
175
+ ### 1. **Iframe Sandbox Attributes**
176
+ ```html
177
+ <iframe sandbox="allow-same-origin allow-popups allow-popups-to-escape-sandbox"
178
+ srcdoc="#{@sanitized_email}"
179
+ width="100%" height="600">
180
+ </iframe>
181
+ ```
182
+
183
+ ### 2. **Content Security Policy**
184
+ ```ruby
185
+ # In your Rails app or web server config
186
+ response.headers['Content-Security-Policy'] =
187
+ "default-src 'self'; " \
188
+ "img-src https: data:; " \
189
+ "style-src 'unsafe-inline'; " \
190
+ "script-src 'none';"
191
+ ```
192
+
193
+ ### 3. **Additional Protections**
194
+ - Rate limiting email processing
195
+ - File size limits for email content
196
+ - Virus scanning for attachments
197
+ - Logging of sanitization attempts
198
+
199
+ ## Testing the Sanitizer
200
+
201
+ ```ruby
202
+ # Test malicious content
203
+ malicious_email = <<~HTML
204
+ <html>
205
+ <body>
206
+ <h1>Important Email</h1>
207
+ <p>Click <a href="javascript:alert('XSS')">here</a> for prize!</p>
208
+ <script>steal_data();</script>
209
+ <iframe src="http://evil.com"></iframe>
210
+ <table>
211
+ <tr><td>Safe content</td></tr>
212
+ </table>
213
+ <img src="data:image/svg+xml;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoJ1hTUyknPg==" />
214
+ </body>
215
+ </html>
216
+ HTML
217
+
218
+ sanitized = EmailSanitizer.sanitize_for_iframe(malicious_email)
219
+ puts sanitized
220
+ # => <h1>Important Email</h1><p>Click <a>here</a> for prize!</p><table><tbody><tr><td>Safe content</td></tr></tbody></table>
221
+ ```
222
+
223
+ ## Performance Considerations
224
+
225
+ - Cache sanitized emails when possible
226
+ - Process emails asynchronously for large volumes
227
+ - Monitor memory usage with large email attachments
228
+ - Consider streaming for very large email content
229
+
230
+ ## Integration Examples
231
+
232
+ ### Rails Integration
233
+ ```ruby
234
+ # app/helpers/email_helper.rb
235
+ module EmailHelper
236
+ def safe_email_iframe(email_content)
237
+ sanitized = EmailSanitizer.sanitize_for_iframe(email_content)
238
+ content_tag(:iframe, '',
239
+ sandbox: 'allow-same-origin allow-popups allow-popups-to-escape-sandbox',
240
+ srcdoc: sanitized,
241
+ width: '100%',
242
+ height: '600',
243
+ style: 'border: 1px solid #ccc;')
244
+ end
245
+ end
246
+
247
+ # In view:
248
+ # <%= safe_email_iframe(@email.html_content) %>
249
+ ```
250
+
251
+ ### Sinatra Integration
252
+ ```ruby
253
+ # Email processing endpoint
254
+ post '/emails/sanitize' do
255
+ content_type :json
256
+
257
+ begin
258
+ raw_html = request.body.read
259
+ sanitized = EmailSanitizer.sanitize_for_iframe(raw_html)
260
+
261
+ { success: true, html: sanitized }.to_json
262
+ rescue => e
263
+ { success: false, error: e.message }.to_json
264
+ end
265
+ end
266
+ ```
267
+
268
+ This example provides a comprehensive solution for safely displaying HTML emails in iframes while maintaining security and preserving email formatting.
@@ -0,0 +1,192 @@
1
+ # Root Causes for Scrubber vs DOMPurify Expectation Failures
2
+
3
+ This document analyzes the root causes of why the Scrubber library produces different outputs compared to the expected DOMPurify behaviors in the test suite.
4
+
5
+ ## Summary
6
+
7
+ The Scrubber library's default configuration is more restrictive than DOMPurify's in several areas:
8
+ - Data URIs are blocked by default
9
+ - Certain HTML attributes (e.g., `checked`, `selected`) are not allowed by default
10
+ - SVG and MathML attribute handling differs
11
+ - DOM clobbering protection is more aggressive
12
+ - Some attributes expected to be preserved are removed
13
+
14
+ ## Detailed Root Causes by Failure
15
+
16
+ ### 1. Data URI Handling
17
+ **Failures:** Don't remove data URIs from SVG images, Don't remove data URIs from SVG images with href attribute, src Attributes for IMG, AUDIO, VIDEO and SOURCE, Image with data URI src, Image with data URI src with whitespace
18
+
19
+ **Root Cause:** Scrubber blocks data URIs by default (`allow_data_uri = false`), while DOMPurify allows data URIs for specific attributes on specific tags (img src, audio src, video src, source src, SVG image xlink:href/href). The URI validation regex `IS_ALLOWED_URI` does not include `data:` protocol, and the special case for data URIs requires `allow_data_uri = true` or tag-specific allowances.
20
+
21
+ **Remediation Recommendation:** Implement via `dompurify` profile to allow data URIs for specific safe tags. Keep default restrictive for security. Security implications: Data URIs can contain embedded scripts or large payloads that could cause performance issues, but restricting to specific tags and validating content types mitigates most risks.
22
+
23
+ **Code Location:** `lib/scrubber.rb` `valid_attribute?` method, `lib/scrubber/expressions.rb` `IS_ALLOWED_URI`
24
+
25
+ ### 2. ARIA Attributes
26
+ **Failures:** Don't remove ARIA attributes if not prohibited
27
+
28
+ **Root Cause:** Despite `allow_aria_attributes = true` in default config, ARIA attributes are being removed. This may be due to the attribute validation logic not properly applying the permissive checks, or a bug in the order of validation.
29
+
30
+ **Remediation Recommendation:** Fix the bug in `valid_attribute?` to properly apply `allow_aria_attributes` logic. Alternatively, ensure ARIA attributes are included in the `dompurify` profile's allowed attributes. Keep the default as allowing ARIA attributes since they are essential for accessibility and pose no security risk.
31
+
32
+ **Code Location:** `lib/scrubber.rb` `valid_attribute?` method, config `allow_aria_attributes`
33
+
34
+ ### 3. Binary Attributes
35
+ **Failures:** Don't remove binary attributes if considered safe
36
+
37
+ **Root Cause:** Attributes like `checked` are not included in the default allowed attributes list. DOMPurify allows these HTML boolean attributes by default, but Scrubber requires them to be explicitly allowed.
38
+
39
+ **Remediation Recommendation:** Implement via `dompurify` profile by expanding the allowed attributes list to include common HTML boolean attributes. Keep defaults restrictive for security. Security implications: These attributes are safe and commonly used in HTML forms; they don't introduce XSS risks.
40
+
41
+ **Code Location:** `lib/scrubber/attributes.rb` `HTML` list, `lib/scrubber.rb` `valid_attribute?` default checks
42
+
43
+ ### 4. SVG Filter Elements
44
+ **Failures:** Avoid over-zealous stripping of SVG filter elements
45
+
46
+ **Root Cause:** SVG filter elements and their attributes are not fully supported in the default allowed tags/attributes. The `feGaussianBlur` element and its `in` and `stdDeviation` attributes are being removed.
47
+
48
+ **Remediation Recommendation:** Relax restrictions by ensuring all SVG filter elements and their standard attributes are included in the default allowed lists. Security implications: SVG filters are generally safe for display purposes and are commonly used in web graphics; they don't execute scripts.
49
+
50
+ **Code Location:** `lib/scrubber/tags.rb` `SVG_FILTERS`, `lib/scrubber/attributes.rb` `SVG`
51
+
52
+ ### 5. URI-like Attributes
53
+ **Failures:** safe usage of URI-like attribute values
54
+
55
+ **Root Cause:** The `href` attribute is removed when it contains `javascript:`, but `title` is kept. This is correct behavior for security, but the test expects both to be handled differently.
56
+
57
+ **Remediation Recommendation:** Keep the more restrictive mode for URI attributes like `href` to prevent XSS, while allowing non-URI attributes like `title` to contain URI-like strings. Security implications: This is actually a security feature - blocking `javascript:` in navigation attributes prevents XSS attacks.
58
+
59
+ **Code Location:** `lib/scrubber.rb` `valid_attribute?` URI validation
60
+
61
+ ### 6. DOM Clobbering Protection
62
+ **Failures:** Multiple DOM clobbering related failures (cookie, getElementById, nodeName, etc.)
63
+
64
+ **Root Cause:** Scrubber's DOM clobbering protection is more aggressive than DOMPurify's. Attributes with names that could shadow DOM properties are removed, even when DOMPurify allows them.
65
+
66
+ **Remediation Recommendation:** Keep the more restrictive mode for DOM clobbering protection as it provides better security. The `dompurify` profile could optionally disable this for compatibility. Security implications: DOM clobbering can be used to manipulate JavaScript code execution; being more restrictive prevents potential security vulnerabilities at the cost of some compatibility.
67
+
68
+ **Code Location:** `lib/scrubber.rb` `valid_attribute?` DOM clobbering check, `lib/scrubber/attributes.rb` `DOM_CLOBBERING`
69
+
70
+ ### 7. MathML Handling
71
+ **Failures:** MathML example
72
+
73
+ **Root Cause:** MathML elements and attributes are not properly supported or the serialization differs from DOMPurify's output.
74
+
75
+ **Remediation Recommendation:** Relax restrictions by improving MathML support to match DOMPurify's handling. Security implications: MathML is generally safe for mathematical content display and doesn't execute scripts; better support improves compatibility without significant security risks.
76
+
77
+ **Code Location:** `lib/scrubber/tags.rb` `MATH_ML`, `lib/scrubber/attributes.rb` `MATH_ML`
78
+
79
+ ### 8. Template and Shadow DOM
80
+ **Failures:** Img element inside shadow DOM template
81
+
82
+ **Root Cause:** Template elements and their contents are not handled the same way as DOMPurify.
83
+
84
+ **Remediation Recommendation:** Keep the more restrictive mode for template elements as they can contain executable content. Security implications: Template elements can be used to inject scripts that execute when the template is instantiated; being restrictive prevents potential XSS through template injection.
85
+
86
+ **Code Location:** `lib/scrubber.rb` `sanitize_document` forbidden tags
87
+
88
+ ### 9. Style Attributes
89
+ **Failures:** Multiple style-related failures (p[foo=bar], @import, etc.)
90
+
91
+ **Root Cause:** CSS sanitization is more restrictive, removing valid CSS that DOMPurify allows.
92
+
93
+ **Remediation Recommendation:** Partially relax restrictions for safe CSS properties while keeping restrictions on dangerous ones like `@import` with external URLs. Security implications: CSS can be used for XSS (e.g., `expression()` in IE, `url()` with javascript), so selective relaxation is needed to balance security and functionality.
94
+
95
+ **Code Location:** `lib/scrubber.rb` `sanitize_style_value`, `unsafe_inline_style?`
96
+
97
+ ### 10. Form and Input Handling
98
+ **Failures:** Various form and input attribute failures (type, method, etc.)
99
+
100
+ **Root Cause:** Form-related attributes are not all allowed by default.
101
+
102
+ **Remediation Recommendation:** Relax restrictions by adding common form attributes to the default allowed list. Security implications: Form attributes are generally safe and necessary for HTML forms; they don't introduce XSS risks when properly validated.
103
+
104
+ **Code Location:** `lib/scrubber/attributes.rb` `HTML`
105
+
106
+ ### 11. SVG and XML Namespaces
107
+ **Failures:** SVG namespace handling
108
+
109
+ **Root Cause:** XML namespace attributes and SVG-specific handling differs.
110
+
111
+ **Remediation Recommendation:** Relax restrictions to properly support SVG namespaces. Security implications: Namespaces are metadata and don't execute code; proper support improves SVG compatibility without security risks.
112
+
113
+ **Code Location:** `lib/scrubber.rb` `sanitize_element` namespace check
114
+
115
+ ### 12. Comment and Script Handling
116
+ **Failures:** Noscript content handling
117
+
118
+ **Root Cause:** Comment and script content sanitization differs.
119
+
120
+ **Remediation Recommendation:** Keep the more restrictive mode for comments and scripts. Security implications: Comments can contain sensitive information, and scripts are inherently dangerous; removing them prevents information leakage and script injection.
121
+
122
+ **Code Location:** `lib/scrubber.rb` `sanitize_comment_node`
123
+
124
+ ### 13. CDATA and Special Content
125
+ **Failures:** SVG with CDATA
126
+
127
+ **Root Cause:** CDATA sections and special HTML constructs are handled differently.
128
+
129
+ **Remediation Recommendation:** Adjust serialization to match DOMPurify's handling of CDATA and special content. Security implications: CDATA sections can contain script-like content, so careful validation is needed, but matching DOMPurify's behavior improves compatibility.
130
+
131
+ **Code Location:** `lib/scrubber.rb` `serialize_html`
132
+
133
+ ### 14. Attribute Value Sanitization
134
+ **Failures:** Various attribute value transformations
135
+
136
+ **Root Cause:** Attribute value processing (encoding, decoding, validation) differs from DOMPurify.
137
+
138
+ **Remediation Recommendation:** Adjust value processing to match DOMPurify's behavior while maintaining security. Security implications: Proper value sanitization prevents XSS through attribute injection; changes should preserve security guarantees.
139
+
140
+ **Code Location:** `lib/scrubber.rb` `valid_attribute?` value processing
141
+
142
+ ### 15. Element Content Preservation
143
+ **Failures:** Content preservation in certain elements
144
+
145
+ **Root Cause:** The `keep_content` logic differs for certain forbidden elements.
146
+
147
+ **Remediation Recommendation:** Keep the more restrictive mode for content preservation. Security implications: Preserving content from forbidden elements can lead to information leakage or script execution; being restrictive prevents these issues.
148
+
149
+ **Code Location:** `lib/scrubber.rb` `sanitize_element`
150
+
151
+ ## Alternative Solution: DOMPurify Profile
152
+
153
+ Most of these discrepancies could be addressed by adding a `dompurify` profile that configures Scrubber to match DOMPurify's more permissive behavior. This would allow users to opt into DOMPurify-compatible sanitization while maintaining Scrubber's secure defaults.
154
+
155
+ ### Profile Implementation
156
+
157
+ Add a `dompurify` profile to `process_profiles` in `lib/scrubber/config.rb`:
158
+
159
+ ```ruby
160
+ if @use_profiles[:dompurify]
161
+ @allowed_tags += Tags::HTML + Tags::SVG + Tags::SVG_FILTERS + Tags::MATH_ML
162
+ @allowed_attributes += Attributes::HTML + Attributes::SVG + Attributes::MATH_ML + Attributes::XML
163
+ @allow_data_uri = true # Allow data URIs for compatible tags
164
+ @allow_unknown_protocols = true # More permissive protocol handling
165
+ @sanitize_dom = false # Less aggressive DOM clobbering protection
166
+ @allow_style_tags = true # Allow style tags
167
+ # Add more permissive settings as needed
168
+ end
169
+ ```
170
+
171
+ ### Usage
172
+
173
+ ```ruby
174
+ Scrubber.new(dompurify: true).sanitize(html)
175
+ # or
176
+ Scrubber.new(use_profiles: { dompurify: true }).sanitize(html)
177
+ ```
178
+
179
+ ### Benefits
180
+
181
+ - **Maintains Security by Default:** Keeps Scrubber's restrictive defaults for security-conscious users
182
+ - **Provides Compatibility:** Offers DOMPurify-like behavior when needed
183
+ - **Selective Relaxation:** Only relaxes restrictions where DOMPurify differs, maintaining security where possible
184
+ - **Backward Compatible:** Doesn't break existing code
185
+
186
+ ### Security Considerations
187
+
188
+ The `dompurify` profile would be less secure than Scrubber's defaults but more compatible with DOMPurify. Users should understand the trade-offs when enabling this profile.
189
+
190
+ ### Implementation Priority
191
+
192
+ Most root causes (1-4, 7, 9-11, 13-14) could be addressed through the `dompurify` profile, while security-critical areas (5-6, 8, 12, 15) should remain restrictive by default with optional relaxation in the profile.