### Chaining Scrubbers Source: https://github.com/flavorjones/loofah/blob/main/README.md Scrubbers can be chained together for sequential HTML sanitization. This example prunes unsafe tags and then converts spans to divs. ```ruby Loofah.html5_fragment("hello ") \ .scrub!(:prune) \ .scrub!(span2div).to_s # => "
hello
" ``` -------------------------------- ### Initialize Firehose UI and Event Handlers Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html This JavaScript code initializes the firehose UI, sets up focus and blur event handlers for the filter input, and applies updates. It configures various firehose settings like start date, mode, and sorting. ```javascript firehose_exists = 1; $(function(){ $('#firehose-filter'). focus(function(event){ gFocusedText = this; }). blur(function(event){ if ( gFocusedText === this ) { gFocusedText = null; } }); var $fhitems = firehose_init_tag_ui(); firehose_init_idle($fhitems); apply_updates_when( 'at-end', true); }); firehose_settings.startdate = ""; firehose_settings.mode = "mixed"; firehose_settings.fhfilter = ""; firehose_settings.orderdir = "DESC"; firehose_settings.orderby = "createtime"; firehose_settings.duration = -1; firehose_settings.color = "green"; firehose_settings.view = "stories"; firehose_settings.viewtitle = "Stories"; firehose_settings.tab = ""; firehose_settings.base_filter = ""; firehose_settings.user_view_uid = ""; firehose_settings.sectionname = "Main"; firehose_settings.issue = ""; firehose_settings.section = 13; $('#searchquery').val(firehose_settings.fhfilter); view_change_hide_show(firehose_settings.view); firehose_sitename = "Slashdot"; firehose_slogan = "News for nerds, stuff that matters"; firehose_update_title_count(); fh_idle_skin = 1; firehose_settings.index = 1; var firehose_action_time = 0; var firehose_user_class = 0; var fh_color = "green"; fh_colors = [ "red", "orange", "yellow", "green", "blue", "indigo", "violet", "black" ]; var fh_colors_hash = new Array(0); for (var i=0; i< fh_colors.length; i++) { fh_colors_hash[fh_colors[i]] = i; } var fh_view_mode = "mixed"; firehose_settings.page = 0; fh_is_admin = 0; var updateIntervalType = 2; var inactivity_timeout = 3600; setFirehoseAction(); var update_time = "2009-07-01 01:58:36"; var maxtime = "2009-07-01 01:58:36"; var insert_new_at = "top"; firehose_play("init"); fh_adTimerUrl = '/images/iframe/firehose.html'; fh_ticksize = 15; sitename = 'idle.slashdot.org'; ``` -------------------------------- ### Create Custom Scrubber to Change Tag Names Source: https://github.com/flavorjones/loofah/blob/main/README.md A Loofah::Scrubber can be initialized with a block to define custom scrubbing logic. This example changes all `` tags to `
` tags. ```ruby # change all tags to
tags span2div = Loofah::Scrubber.new do |node| node.name = "div" if node.name == "span" end ``` -------------------------------- ### Sanitize HTML with Allowed Tags in Ruby Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Demonstrates how to use Rails::Html::WhiteListSanitizer to sanitize HTML input, specifying a list of allowed tags. This example highlights a vulnerability when 'svg' and 'style' tags are allowed, leading to script execution. ```ruby #! /usr/bin/env ruby require "bundler/inline" gemfile do source "https://rubygems.org" gem "rails-html-sanitizer", "=1.4.3" # contains the select/style fix end require "rails-html-sanitizer" def sanitize(input, tags) Rails::Html::WhiteListSanitizer.new.sanitize(input, tags: tags) end input, tags = "", %w(svg style) sanitize(input, tags) # => "" input, tags = "", %w(math style img) sanitize(input, tags) # => "" ``` -------------------------------- ### Chaining multiple scrubbers Source: https://context7.com/flavorjones/loofah/llms.txt Demonstrates applying multiple Loofah transformations in sequence for comprehensive HTML processing. ```ruby require 'loofah' ``` -------------------------------- ### Create and Manipulate HTML Elements Source: https://context7.com/flavorjones/loofah/llms.txt Shows how to create a new HTML structure, add child elements dynamically, and serialize the result. ```ruby doc = Loofah.html5_fragment("
    ") ul = doc.at_css("ul") 3.times { |i| ul.add_child("
  • Item #{i + 1}
  • ") } doc.to_s ``` -------------------------------- ### Escape unsafe tags to HTML entities Source: https://context7.com/flavorjones/loofah/llms.txt Use the :escape scrubber to convert unsafe HTML tags into visible HTML entities. This is useful for safely displaying code examples. ```ruby require 'loofah' unsafe_html = "Check this:
    safe
    tag" result = Loofah.html5_fragment(unsafe_html).scrub!(:escape).to_s # => "Check this:
    safe
    <script>alert('XSS')</script> <custom>tag</custom>" ``` ```ruby require 'loofah' # Useful when you want to display code examples safely code_example = "" safe_display = Loofah.scrub_html5_fragment(code_example, :escape).to_s # => "<script>document.write('Hello')</script>" ``` -------------------------------- ### Shorthand XML Scrubbing Methods Source: https://context7.com/flavorjones/loofah/llms.txt Demonstrates shorthand methods for scrubbing XML fragments and documents, including the use of custom scrubbers. ```ruby xml = "ok" custom_scrubber = Loofah::Scrubber.new { |n| n.remove if n["attr"] == "bad" } Loofah.scrub_xml_fragment(xml, custom_scrubber).to_s Loofah.scrub_xml_document(xml, custom_scrubber).to_s ``` -------------------------------- ### Get Text Content from HTML Fragment Source: https://github.com/flavorjones/loofah/blob/main/README.md The `text` method returns the plain text content of the document. For better handling of whitespace around block elements, use `to_text`. ```ruby doc = Loofah.html5_fragment("

    Title

    Content
    Next line
    ") doc.text # => "TitleContentNext line" # probably not what you want doc.to_text # => "\nTitle\n\nContent\nNext line\n" # better ``` -------------------------------- ### Input HTML String Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md The initial HTML input string used for demonstrating parsing behavior. ```html ``` -------------------------------- ### Google Analytics Initialization Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html Initializes Google Analytics tracking for the page. Requires the _gat object to be available. ```javascript dfp_ord=Math.random()* 10000000000000000; dfp_tile = 1; var pageTracker = _gat._getTracker("UA-32013-5"); pageTracker._setDomainName("slashdot.org"); pageTracker._initData(); ``` -------------------------------- ### Equivalent HTML5 for Math Case Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md The HTML string equivalent to the HTML5 DOM, demonstrating the 'img' tag as a sibling. ```html ``` -------------------------------- ### Initialize and Update Section Metadata Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html Initializes metadata for a section element and updates section signatures. Used for matching properties to existing sections. ```javascript function init_metadata( el ){ var $el=$(el), result=$el.metadata({ type:'elem', name:'script' }); $el.find('script[type=data]').remove(); return result; } ``` ```javascript update_section = function( el, update, opts ){ var section = init_metadata(el), id = section.id, // assert(id); oldsig = signatures[id], newsig = signature($.extend(section, // Make the color explicit. !section.color && { color:default_color[section.viewname] }, // Roll-in the updated data, if any; but protect the id. update, { id:id } )); // Update the signatures that let us match properties to existing sections. if ( id!=='unsaved' && newsig!==oldsig ) { ids[ signatures[id]=newsig ] = id; if ( oldsig ) { delete ids[ oldsig ]; // Discard cached skin if the search has changed. section.skin && oldsig.split(';')[2]!==newsig.split(';')[2] && delete section.skin; // This must be a change to an existing menu item, so let's save the menu as a whole. save_menu(); } } if ( opts ) { opts.highlight && highlight_menu_item(id); opts.make_default && ($section_menu.metadata().default_id=id); } }; ``` -------------------------------- ### Sanitizer Behavior Comparison for Select/Style Input Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Compares the sanitization output for a specific input involving `" v1.4.2: "" v1.4.3: "" proposed: "" ``` -------------------------------- ### Create Custom Scrubber Classes Source: https://context7.com/flavorjones/loofah/llms.txt Define reusable scrubber classes by inheriting from `Loofah::Scrubber` for complex or frequently used transformations. Specify the `direction` in the initializer. ```ruby require 'loofah' # Custom scrubber class that adds a CSS class to all elements class AddClassScrubber < Loofah::Scrubber def initialize(class_name) @class_name = class_name @direction = :top_down # or :bottom_up end def scrub(node) return Loofah::Scrubber::CONTINUE unless node.element? existing_class = node["class"] || "" node["class"] = "#{existing_class} #{@class_name}".strip Loofah::Scrubber::CONTINUE # Continue traversing children end end # Use the custom scrubber html = "

    Paragraph

    Span
    " scrubber = AddClassScrubber.new("processed") result = Loofah.html5_fragment(html).scrub!(scrubber).to_s # => '

    Paragraph

    Span
    ' ``` ```ruby require 'loofah' # Custom scrubber that removes elements by attribute class RemoveByAttribute < Loofah::Scrubber def initialize(attr_name, attr_value) @attr_name = attr_name @attr_value = attr_value @direction = :top_down end def scrub(node) if node.element? && node[@attr_name] == @attr_value node.remove return Loofah::Scrubber::STOP end Loofah::Scrubber::CONTINUE end end html = '
    Remove me
    Keep me
    ' result = Loofah.html5_fragment(html).scrub!(RemoveByAttribute.new("data-remove", "true")).to_s # => '
    Keep me
    ' ``` -------------------------------- ### Shorthand HTML Scrubbing Methods Source: https://context7.com/flavorjones/loofah/llms.txt Provides convenience methods for common HTML parsing and scrubbing operations, supporting both fragments and documents, and HTML4/HTML5. ```ruby require 'loofah' unsafe_html = "

    Safe

    " # These shorthand methods combine parsing and scrubbing Loofah.scrub_html5_fragment(unsafe_html, :prune).to_s # HTML5 fragment Loofah.scrub_html5_document(unsafe_html, :prune).to_s # HTML5 document Loofah.scrub_html4_fragment(unsafe_html, :prune).to_s # HTML4 fragment Loofah.scrub_html4_document(unsafe_html, :prune).to_s # HTML4 document ``` -------------------------------- ### Contextual Suggestions Object Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html Defines objects mapping context keywords to lists of suggestion types. Used for categorizing user feedback or content. ```javascript var suggestions_for_context = { nod: 'fresh funny insightful interesting maybe ', nix: 'binspam dupe notthebest offtopic slownewsday stale stupid ', feedback: 'typo dupe error', metanod: 'insightful interesting informative funny underrated', metanix: 'offtopic flamebait troll redundant overrated' }; ``` -------------------------------- ### Add security rel attributes to hyperlinks Source: https://context7.com/flavorjones/loofah/llms.txt Use :noopener and :noreferrer scrubbers to add security-related `rel` attributes to hyperlinks. These prevent `window.opener` access and the sending of the referer header, respectively. Scrubbers can be chained for comprehensive security. ```ruby require 'loofah' link_html = 'Click here' # Add rel="noopener" to prevent window.opener access result = Loofah.html5_fragment(link_html).scrub!(:noopener).to_s # => 'Click here' ``` ```ruby require 'loofah' link_html = 'Click here' # Add rel="noreferrer" to prevent referer header result = Loofah.html5_fragment(link_html).scrub!(:noreferrer).to_s # => 'Click here' ``` ```ruby require 'loofah' link_html = 'Click here' # Chain multiple scrubbers for comprehensive link security secure_links = Loofah.html5_fragment(link_html) .scrub!(:nofollow) .scrub!(:noopener) .scrub!(:noreferrer) .to_s # => 'Click here' ``` -------------------------------- ### Chain Scrubbers for HTML Sanitization Source: https://context7.com/flavorjones/loofah/llms.txt Chain multiple scrubbers to progressively clean and secure HTML content. Use `html5_fragment` for HTML fragments or `scrub_html5_fragment` with shorthand. ```ruby user_content = <<-HTML

    Check this link

    custom content
    HTML clean = Loofah.html5_fragment(user_content) .scrub!(:prune) # Remove unsafe tags .scrub!(:nofollow) # Add nofollow to links .scrub!(:targetblank) # Open links in new tab .to_s clean = Loofah.scrub_html5_fragment(user_content, :strip) .scrub!(:nofollow) .scrub!(:noopener) .to_s ``` -------------------------------- ### Initialize Slashdot Search Functionality Source: https://github.com/flavorjones/loofah/blob/main/benchmark/fragment.html Initializes the search functionality for Slashdot, including event listeners for search input and button clicks. Requires jQuery and assumes the presence of specific HTML elements and a `has_hose()` function. ```javascript var slash_search; $(function(){ if (has_hose()) { var $search_text = $any('searchquery'), $panel = $search_text.closest('fieldset'); $search_buttons = $('#viewsearch,#fhsearch'), ws = /\s+/; // The search buttons set the firehose option named by their class. $search_buttons. click(function(){ var which=this.className; $search_text.each(function(){ firehose_set_options(which, this.value); }); return false; }); // Provide a globally available function that does whatever clicking the search button would do. slash_search = function( query ){ query!==undefined && $search_text.val(query); $search_buttons.filter(':visible:first').click(); }; $search_text. keydown(function( e ){ // ESCAPE restores the filter in-effect. if ( e.which == $.ui.keyCode.ESCAPE ) { $search_text.val(firehose_settings.fhfilter||""); return true; } if ( e.which == $.ui.keyCode.ENTER ) { slash_search(); return false; } }); $(document). bind('firehose-setting-setfhfilter firehose-setting-setsearchfilter', function( e, new_query ){ $('fieldset input[type=text]').each(function(){ $(this).blur().val(new_query); }); }). bind('set-options.firehose', function( e, data ){ data.select_section && $panel.toggleClass('mode-filter', data.id!=='unsaved'); }); } }); ``` -------------------------------- ### Ad Management Script Initialization Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html Initializes an ad script, likely for DoubleClick, by dynamically writing a script tag to the document. This snippet includes CDATA for script content. ```javascript var ad6 = 'inactive'; //<\/script>'); dfp_tile++; //]]> ``` -------------------------------- ### Create Custom Scrubber with Block Source: https://github.com/flavorjones/loofah/blob/main/README.md Define a custom document transformation by wrapping a block of code. This scrubber renames 'span' nodes to 'div'. ```ruby span2div = Loofah::Scrubber.new do |node| node.name = "div" if node.name == "span" end ``` -------------------------------- ### Parse HTML4 Fragments and Documents with Loofah Source: https://context7.com/flavorjones/loofah/llms.txt Use Loofah.html4_fragment and Loofah.html4_document for HTML4 parsing. Shorthand aliases Loofah.fragment and Loofah.document are also available, currently pointing to HTML4 parsing. ```ruby require 'loofah' # HTML4 fragment parsing fragment = Loofah.html4_fragment("Hello World") fragment.scrub!(:strip).to_s # => "Hello World" # HTML4 document parsing doc = Loofah.html4_document("

    Content

    ") doc.scrub!(:prune).to_s # Shorthand aliases (currently point to HTML4, may change in future) Loofah.fragment("

    text

    ") # Same as html4_fragment Loofah.document("...") # Same as html4_document ``` -------------------------------- ### Sanitizer Behavior for Allowed Img Tag Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Illustrates the sanitization output when an `` tag is allowed within a `` and `" v1.4.2: "" v1.4.3: "" proposed: "" ``` -------------------------------- ### Built-In HTML Scrubbers Source: https://github.com/flavorjones/loofah/blob/main/README.md Use these scrubbers with `Loofah.html5_document` for different sanitization strategies. They are based on html5lib's safelist algorithm. ```ruby doc = Loofah.html5_document(input) doc.scrub!(:strip) # replaces unknown/unsafe tags with their inner text doc.scrub!(:prune) # removes unknown/unsafe tags and their children doc.scrub!(:escape) # escapes unknown/unsafe tags, like this: <script> doc.scrub!(:whitewash) # removes unknown/unsafe/namespaced tags and their children, # and strips all node attributes ``` ```ruby doc.scrub!(:nofollow) # adds rel="nofollow" attribute to links doc.scrub!(:noopener) # adds rel="noopener" attribute to links doc.scrub!(:noreferrer) # adds rel="noreferrer" attribute to links doc.scrub!(:unprintable) # removes unprintable characters from text nodes doc.scrub!(:targetblank) # adds target="_blank" attribute to links doc.scrub!(:double_breakpoint) # where `

    ` appears in a `p` tag, close the `p` and open a new one ``` -------------------------------- ### Shorthand Scrubbing Methods Source: https://github.com/flavorjones/loofah/blob/main/README.md Use these shorthand class methods for common sanitization tasks, providing a more direct way to apply a scrubber to HTML content. ```ruby Loofah.scrub_html5_fragment(unsafe_html, :prune) Loofah.scrub_html5_document(unsafe_html, :prune) Loofah.scrub_html4_fragment(unsafe_html, :prune) Loofah.scrub_html4_document(unsafe_html, :prune) Loofah.scrub_xml_fragment(bad_xml, custom_scrubber) Loofah.scrub_xml_document(bad_xml, custom_scrubber) ``` ```ruby Loofah.html5_fragment(unsafe_html).scrub!(:prune) Loofah.html5_document(unsafe_html).scrub!(:prune) Loofah.html4_fragment(unsafe_html).scrub!(:prune) Loofah.html4_document(unsafe_html).scrub!(:prune) Loofah.xml_fragment(bad_xml).scrub!(custom_scrubber) Loofah.xml_document(bad_xml).scrub!(custom_scrubber) ``` -------------------------------- ### Handle Section Menu Mouse Down and Click Events Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html Manages user interactions with the section menu, including activating sections on mouse down and initiating modal dialogs for editing on click. ```javascript $any('links-sections'). mousedown(function( event ){ // "activate" a section (immediately) on mousedown in the section menu $(event.originalTarget||event.target). // mouseDown was on this element... closest('li,div.title').not('.active,:has(.active)'). each(function(){ var section = $(this).metadata(); if ( section.id !== 'unsaved' ) { } else { } }); // allow other handlers to run (by not returning false) }). click(function( event ){ // edit only for a click in the edit button var handled; $(event.originalTarget||event.target). // mouseDown was on this element... closest('a.links-sections-edit'). // ...in this edit icon (if any) each(function(){ var id = $(this).closest('li,div.title').metadata().id; id==='unsaved' && (id=void(0)); getModalPrefs('firehoseview', 'Save Custom Section', 0, { id: id }); handled = true; }); return !handled; }); ``` -------------------------------- ### Apply Custom Scrubber to HTML Fragment Source: https://github.com/flavorjones/loofah/blob/main/README.md The custom scrubber can be applied to a document or fragment using the scrub! method. The result is the modified HTML string. ```ruby Loofah.html5_fragment("foo

    bar

    ").scrub!(span2div).to_s # => "
    foo

    bar

    " ``` -------------------------------- ### Lazy Load Image Initialization Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html Initializes lazy loading for images, likely to improve page performance. This snippet is commented out. ```javascript // $("img\[src*='images.slashdot.org'\]").lazyload({ threshold : 150 }); ``` -------------------------------- ### Sanitizer Behavior for Disallowed Img Tag Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Compares sanitization results when an `` tag is disallowed within a `` and `` tag is completely removed, ensuring security. ```text input: "" v1.4.2: "" v1.4.3: "" proposed: "" ``` -------------------------------- ### Style Tag Sanitization Comparison Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Compares the output of HTML sanitization for a style tag with simple CSS across different versions (v1.4.2, v1.4.3, proposed). Useful for understanding version-specific behavior changes. ```text input: "" v1.4.2: "" v1.4.3: "" proposed: "" ``` -------------------------------- ### Save Firehose Section Menu Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html Saves the current order of firehose sections to the server. Requires user to be logged in. ```javascript function save_menu(){ if ( !check_logged_in() ) { return false; } // tell the server our current (ordered) list of sections ajax_update({ op: 'firehose_save_section_menu', reskey: reskey_static, fsids: $section_menu. children('li:not(#fhsection-unsaved)'). map(function(){ return this.id.slice(10); }).get().join(',') }); } ``` -------------------------------- ### Serialized HTML4 for Math Case Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md The serialized HTML string corresponding to the HTML4 DOM of the 'math' case. ```html ``` -------------------------------- ### Handle Firehose Setting Events Source: https://github.com/flavorjones/loofah/blob/main/benchmark/www.slashdot.com.html Listens for custom events to update the UI when firehose settings change, such as section selection or view options. ```javascript $(document). bind('firehose-setting-section', function( e, section_id ){ // Request to change sections is on its way to the server; update the UI now (don't wait for response) var section = highlight_menu_item(section_id).metadata(); $(document). trigger('firehose-setting-setfhfilter', section.filter). trigger('firehose-setting-view', section.viewname). trigger('firehose-setting-color', section.color); }). bind('set-options.firehose', function( e, data ){ // Changing some option (possibly even the 'section' option) if ( !data.select_section ) { // OK, _not_ the 'section' option. Activate a section that matches the new options, or else "unsaved" delete data.id; data = section_matching(data)||data; if ( !data.id ) { var $unsaved = unsaved(); data = $.extend($unsaved.metadata(), data); $(document). one('update.firehose', function( e, updated ){ $unsaved. }); } } }); ``` -------------------------------- ### Modify HTML using Nokogiri API and Scrub Source: https://context7.com/flavorjones/loofah/llms.txt Demonstrates modifying an HTML fragment using CSS selectors and then scrubbing it to remove unwanted elements like scripts. ```ruby doc = Loofah.html5_fragment("

    Text

    ") doc.at_css("p")["class"] = "highlight" doc.at_css("div").add_child("") doc.scrub!(:prune).to_s ``` -------------------------------- ### Generic Shorthand Scrubbing Source: https://context7.com/flavorjones/loofah/llms.txt Utilizes generic shorthand methods for scrubbing HTML fragments and documents. Note that the underlying implementation defaults to HTML4 and may change in future versions. ```ruby Loofah.scrub_fragment(unsafe_html, :strip).to_s Loofah.scrub_document(unsafe_html, :strip).to_s ``` -------------------------------- ### Require Loofah Helpers Source: https://github.com/flavorjones/loofah/blob/main/README.md To use Loofah's view helpers, which mimic Rails Action View helpers, you must explicitly require the `loofah/helpers` file. ```ruby require 'loofah/helpers' ``` -------------------------------- ### Sanitize HTML with Allowed Tags in Ruby Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Demonstrates how to use Rails::Html::WhiteListSanitizer to sanitize HTML input, specifying allowed tags. Useful for controlling which HTML elements are permitted in the output. ```ruby #! /usr/bin/env ruby require "bundler/inline" gemfile do source "https://rubygems.org" gem "rails-html-sanitizer", path: "." end puts Rails::Html::Sanitizer::VERSION require "rails-html-sanitizer" def sanitize(input, tags) Rails::Html::WhiteListSanitizer.new.sanitize(input, tags: tags) end input, tags = "", %w(select style) sanitize(input, tags) # => "" input, tags = "", %w(style) sanitize(input, tags) # => "" input, tags = "", %w(select style) sanitize(input, tags) # => "" input, tags = "", %w(select style) sanitize(input, tags) # => "" input, tags = "", %w(svg style) sanitize(input, tags) # => "" input, tags = "", %w(math style) sanitize(input, tags) # => "" input, tags = "", %w(math style img) sanitize(input, tags) # => "" ``` -------------------------------- ### Sanitize HTML with Allowed Tags in Ruby Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Demonstrates how to use Rails::Html::WhiteListSanitizer to sanitize HTML input, specifying allowed tags. This is useful for cleaning user-provided HTML to prevent XSS attacks. ```ruby #! /usr/bin/env ruby require "bundler/inline" gemfile do source "https://rubygems.org" gem "rails-html-sanitizer", path: "." end require "rails-html-sanitizer" def sanitize(input, tags) Rails::Html::WhiteListSanitizer.new.sanitize(input, tags: tags) end input, tags = "", %w(select style) sanitize(input, tags) # => "" input, tags = "", %w(style) sanitize(input, tags) # => "" input, tags = "", %w(select style) sanitize(input, tags) # => "" input, tags = "", %w(select style) sanitize(input, tags) # => "" input, tags = "", %w(svg style) sanitize(input, tags) # => "" input, tags = "", %w(math style) sanitize(input, tags) # => "" input, tags = "", %w(math style img) sanitize(input, tags) # => "" ``` -------------------------------- ### Foreign Element Image Sanitization Comparison Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Compares the output of HTML sanitization for an image tag within MathML and style tags across different versions. Shows that permitting 'img' does not affect the sanitization of onerror attributes in this context. ```text input: "" v1.4.2: "" v1.4.3: "" proposed: "" ``` -------------------------------- ### HTML4 vs HTML5 Sanitization: Math Style Img Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Shows the sanitization difference for a MathML tag with a style element containing an image payload. HTML4 attempts to preserve it, while HTML5 removes it. ```text 2) Failure: SanitizersTest#test_unsafe_combination_of_math_and_style_with_img_payload [/home/flavorjones/code/oss/rails-html-sanitizer/test/sanitizer_test.rb:609]: --- +++ actual @@ -1 +1 @@ -"" +"" ``` -------------------------------- ### HTML5 DOM for Math Case Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Represents the HTML5 DOM structure after parsing the 'math' case, showing the 'img' tag lifted out. ```text #(Element:0x67c { name = "body", children = [ #(Text "\n"), #(Element:0x690 { name = "math", namespace = #(Namespace:0x6a4 { prefix = "math", href = "http://www.w3.org/1998/Math/MathML" }), children = [ #(Element:0x6b8 { name = "style", namespace = #(Namespace:0x6a4 { prefix = "math", href = "http://www.w3.org/1998/Math/MathML" }) })] }), #(Element:0x6cc { name = "img", attributes = [ #(Attr:0x6e0 { name = "src", value = "x" }), #(Attr:0x6f4 { name = "onerror", value = "alert(1)" })] }), #(Text "\n" + "\n")] ]) ``` -------------------------------- ### Parse HTML5 Document and Fragment Source: https://github.com/flavorjones/loofah/blob/main/README.md Use Loofah.html5_document and Loofah.html5_fragment to parse HTML. These methods return Nokogiri::HTML5::Document and Nokogiri::HTML5::DocumentFragment objects respectively. ```ruby Loofah.html5_document(unsafe_html).is_a?(Nokogiri::HTML5::Document) # => true Loofah.html5_fragment(unsafe_html).is_a?(Nokogiri::HTML5::DocumentFragment) # => true ``` -------------------------------- ### Loofah: Unsanitized Nested Script Tags (Vulnerable) Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Demonstrates the vulnerability in Loofah v2.1.1 where nested script tags are not fully sanitized, allowing malicious scripts to pass through. ```ruby #! /usr/bin/env ruby require "bundler/inline" gemfile do source "https://rubygems.org" gem "loofah", "=2.1.1" end require "loofah" def sanitize(input) Loofah.fragment(input).scrub!(:strip).to_html end input = "
    " sanitize(input) # => "
    " v1.4.2: "" v1.4.3: "" proposed: "" ``` -------------------------------- ### Add target="_blank" to hyperlinks Source: https://context7.com/flavorjones/loofah/llms.txt The :targetblank scrubber adds `target="_blank"` to all hyperlinks, causing them to open in new tabs. It skips anchor links. On modern browsers, `target="_blank"` implicitly provides noopener behavior. ```ruby require 'loofah' # Content with various link types content = '

    External and Anchor

    ' # Add target="_blank" to external links (anchors are skipped) result = Loofah.html5_fragment(content).scrub!(:targetblank).to_s # => '

    External and Anchor

    ' # On modern browsers, target="_blank" implicitly provides noopener behavior ``` -------------------------------- ### Parse HTML5 Documents with Loofah Source: https://context7.com/flavorjones/loofah/llms.txt Use Loofah.html5_document to parse complete HTML5 documents including DOCTYPE, html, head, and body tags. Sanitize the document using scrub! and serialize it back to HTML with to_s. ```ruby require 'loofah' # Parse a complete HTML5 document html = "Test

    Hello

    " doc = Loofah.html5_document(html) # Sanitize the document doc.scrub!(:strip) # Serialize back to HTML doc.to_s # => "Test

    Hello

    " ``` -------------------------------- ### Equivalent HTML5 Document Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md The HTML5 DOM structure is equivalent to this HTML5 document. Browsers will execute the embedded JavaScript. ```html ``` -------------------------------- ### Scrub Specific Nodes with XPath Source: https://context7.com/flavorjones/loofah/llms.txt Apply scrubbers to specific parts of a document or XML by selecting nodes using XPath. Use `doc.xpath(...)` or `doc.at_xpath(...)` before calling `scrub!`. ```ruby require 'loofah' # Scrub only specific nodes, not the whole document xml = <<-XML John50000 Jane60000 Bob70000 XML doc = Loofah.xml_document(xml) # Remove salary info only from employees section remove_salary = Loofah::Scrubber.new do |node| node.remove if node.name == "salary" end # Scrub only nodes matching XPath doc.xpath("//employees/employee").scrub!(remove_salary) # Employees section has no salaries, public-info still has them # Scrub single node doc.at_xpath("//public-info").scrub!(remove_salary) ``` -------------------------------- ### Sanitizer Behavior Comparison for Script Tag Removal Source: https://github.com/flavorjones/loofah/blob/main/docs/2022-10-decision-on-cdata-nodes.md Illustrates how the sanitizer recursively removes `" v1.4.2: "" v1.4.3: "" proposed: "" ```