{"id":13463344,"url":"https://github.com/flavorjones/loofah","last_synced_at":"2025-11-12T21:38:32.441Z","repository":{"id":631532,"uuid":"272313","full_name":"flavorjones/loofah","owner":"flavorjones","description":"Ruby library for HTML/XML transformation and sanitization","archived":false,"fork":false,"pushed_at":"2025-07-09T14:08:58.000Z","size":1203,"stargazers_count":965,"open_issues_count":17,"forks_count":142,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-10-26T11:21:04.610Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flavorjones.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"MIT-LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"flavorjones","tidelift":"rubygems/loofah"}},"created_at":"2009-08-08T06:04:37.000Z","updated_at":"2025-10-25T17:06:24.000Z","dependencies_parsed_at":"2024-01-24T18:46:48.416Z","dependency_job_id":"b06975fd-b431-4895-920c-fd450ce08449","html_url":"https://github.com/flavorjones/loofah","commit_stats":{"total_commits":725,"total_committers":63,"mean_commits":"11.507936507936508","dds":0.1724137931034483,"last_synced_commit":"85990602c6fdb40489138e80080ca508200c7137"},"previous_names":[],"tags_count":62,"template":false,"template_full_name":null,"purl":"pkg:github/flavorjones/loofah","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavorjones%2Floofah","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavorjones%2Floofah/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavorjones%2Floofah/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavorjones%2Floofah/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flavorjones","download_url":"https://codeload.github.com/flavorjones/loofah/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavorjones%2Floofah/sbom","scorecard":{"id":402883,"data":{"date":"2025-08-11","repo":{"name":"github.com/flavorjones/loofah","commit":"887c3550459497935dfd9aa9caef5467dd76de0b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5,"checks":[{"name":"Maintained","score":1,"reason":"2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":4,"reason":"Found 6/15 approved changesets -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/flavorjones/loofah/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/flavorjones/loofah/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/flavorjones/loofah/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/flavorjones/loofah/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:60: update your workflow using https://app.stepsecurity.io/secureworkflow/flavorjones/loofah/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:61: update your workflow using https://app.stepsecurity.io/secureworkflow/flavorjones/loofah/ci.yml/main?enable=pin","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: MIT-LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: MIT-LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T20:29:39.023Z","repository_id":631532,"created_at":"2025-08-18T20:29:39.024Z","updated_at":"2025-08-18T20:29:39.024Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281257149,"owners_count":26470100,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-27T02:00:05.855Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T13:00:51.516Z","updated_at":"2025-11-12T21:38:32.422Z","avatar_url":"https://github.com/flavorjones.png","language":"Ruby","funding_links":["https://github.com/sponsors/flavorjones","https://tidelift.com/funding/github/rubygems/loofah","https://tidelift.com/badges/package/rubygems/loofah","https://tidelift.com/subscription/pkg/rubygems-loofah?utm_source=rubygems-loofah\u0026utm_medium=referral\u0026utm_campaign=readme","https://tidelift.com/subscription/pkg/rubygems-loofah?utm_source=undefined\u0026utm_medium=referral\u0026utm_campaign=enterprise"],"categories":["Security","Ruby","HTML/XML/CSS Manipulation"],"sub_categories":["Security Tools"],"readme":"# Loofah\n\n* https://github.com/flavorjones/loofah\n* Docs: http://rubydoc.info/github/flavorjones/loofah/main/frames\n* Mailing list: [loofah-talk@googlegroups.com](https://groups.google.com/forum/#!forum/loofah-talk)\n\n## Status\n\n[![ci](https://github.com/flavorjones/loofah/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/flavorjones/loofah/actions/workflows/ci.yml)\n[![Tidelift dependencies](https://tidelift.com/badges/package/rubygems/loofah)](https://tidelift.com/subscription/pkg/rubygems-loofah?utm_source=rubygems-loofah\u0026utm_medium=referral\u0026utm_campaign=readme)\n\n\n## Description\n\nLoofah is a general library for manipulating and transforming HTML/XML documents and fragments, built on top of Nokogiri.\n\nLoofah also includes some HTML sanitizers based on `html5lib`'s safelist, which are a specific application of the general transformation functionality.\n\nActive Record extensions for HTML sanitization are available in the [`loofah-activerecord` gem](https://github.com/flavorjones/loofah-activerecord).\n\n\n## Features\n\n* Easily write custom transformations for HTML and XML\n* Common HTML sanitizing transformations are built-in:\n  * _Strip_ unsafe tags, leaving behind only the inner text.\n  * _Prune_ unsafe tags and their subtrees, removing all traces that they ever existed.\n  * _Escape_ unsafe tags and their subtrees, leaving behind lots of \u003ctt\u003e\u0026lt;\u003c/tt\u003e and \u003ctt\u003e\u0026gt;\u003c/tt\u003e entities.\n  * _Whitewash_ the markup, removing all attributes and namespaced nodes.\n* Other common HTML transformations are built-in:\n  * Add the _nofollow_ attribute to all hyperlinks.\n  * Add the _target=\\_blank_ attribute to all hyperlinks.\n  * Remove _unprintable_ characters from text nodes.\n* Some specialized HTML transformations are also built-in:\n  * Where `\u003cbr\u003e\u003cbr\u003e` exists inside a `p` tag, close the `p` and open a new one.\n* Format markup as plain text, with (or without) sensible whitespace handling around block elements.\n* Replace Rails's `strip_tags` and `sanitize` view helper methods.\n\n\n## Compare and Contrast\n\nLoofah is both:\n\n- a general framework for transforming XML, XHTML, and HTML documents\n- a specific toolkit for HTML sanitization\n\n### General document transformation\n\nLoofah tries to make it easy to write your own custom scrubbers for whatever document transformation you need. You don't like the built-in scrubbers? Build your own, like a boss.\n\n\n### HTML sanitization\n\nAnother Ruby library that provides HTML sanitization is [`rgrove/sanitize`](https://github.com/rgrove/sanitize), another library built on top of Nokogiri, which provides a bit more flexibility on the tags and attributes being scrubbed.\n\nYou may also want to look at [`rails/rails-html-sanitizer`](https://github.com/rails/rails-html-sanitizer) which is built on top of Loofah and provides some useful extensions and additional flexibility in the HTML sanitization.\n\n\n## The Basics\n\nLoofah wraps [Nokogiri](http://nokogiri.org) in a loving embrace. Nokogiri is a stable, well-maintained parser for XML, HTML4, and HTML5.\n\nLoofah implements the following classes:\n\n* `Loofah::HTML5::Document`\n* `Loofah::HTML5::DocumentFragment`\n* `Loofah::HTML4::Document` (aliased as `Loofah::HTML::Document` for now)\n* `Loofah::HTML4::DocumentFragment` (aliased as `Loofah::HTML::DocumentFragment` for now)\n* `Loofah::XML::Document`\n* `Loofah::XML::DocumentFragment`\n\nThese document and fragment classes are subclasses of the similarly-named Nokogiri classes `Nokogiri::HTML5::Document` et al.\n\nLoofah also implements `Loofah::Scrubber`, which represents the document transformation, either by wrapping\na block,\n\n``` ruby\nspan2div = Loofah::Scrubber.new do |node|\n  node.name = \"div\" if node.name == \"span\"\nend\n```\n\nor by implementing a method.\n\n\n### Side Note: Fragments vs Documents\n\nGenerally speaking, unless you expect to have a DOCTYPE and a single root node, you don't have a *document*, you have a *fragment*. For HTML, another rule of thumb is that *documents* have `html` and `body` tags, and *fragments* usually do not.\n\n**HTML fragments** should be parsed with `Loofah.html5_fragment` or `Loofah.html4_fragment`. The result won't be wrapped in `html` or `body` tags, won't have a DOCTYPE declaration, `head` elements will be silently ignored, and multiple root nodes are allowed.\n\n**HTML documents** should be parsed with `Loofah.html5_document` or `Loofah.html4_document`. The result will have a DOCTYPE declaration, along with `html`, `head` and `body` tags.\n\n**XML fragments** should be parsed with `Loofah.xml_fragment`. The result won't have a DOCTYPE declaration, and multiple root nodes are allowed.\n\n**XML documents** should be parsed with `Loofah.xml_document`. The result will have a DOCTYPE declaration and a single root node.\n\n\n### Side Note: HTML4 vs HTML5\n\n⚠ _HTML5 functionality is not available on JRuby, or with versions of Nokogiri `\u003c 1.14.0`._\n\nCurrently, Loofah's methods `Loofah.document` and `Loofah.fragment` are aliases to `.html4_document` and `.html4_fragment`, which use Nokogiri's HTML4 parser. (Similarly, `Loofah::HTML::Document` and `Loofah::HTML::DocumentFragment` are aliased to `Loofah::HTML4::Document` and `Loofah::HTML4::DocumentFragment`.)\n\n**Please note** that in a future version of Loofah, these methods and classes may switch to using Nokogiri's HTML5 parser and classes on platforms that support it [1].\n\n**We strongly recommend that you explicitly use `.html5_document` or `.html5_fragment`** unless you know of a compelling reason not to. If you are sure that you need to use the HTML4 parser, you should explicitly call `.html4_document` or `.html4_fragment` to avoid breakage in a future version.\n\n  [1]: [[feature request] HTML5 parser for JRuby implementation · Issue #2227 · sparklemotion/nokogiri](https://github.com/sparklemotion/nokogiri/issues/2227)\n\n\n### `Loofah::HTML5::Document` and `Loofah::HTML5::DocumentFragment`\n\nThese classes are subclasses of `Nokogiri::HTML5::Document` and `Nokogiri::HTML5::DocumentFragment`.\n\nThe module methods `Loofah.html5_document` and `Loofah.html5_fragment` will parse either an HTML document and an HTML fragment, respectively.\n\n``` ruby\nLoofah.html5_document(unsafe_html).is_a?(Nokogiri::HTML5::Document)         # =\u003e true\nLoofah.html5_fragment(unsafe_html).is_a?(Nokogiri::HTML5::DocumentFragment) # =\u003e true\n```\n\nLoofah injects a `scrub!` method, which takes either a symbol (for built-in scrubbers) or a `Loofah::Scrubber` object (for custom scrubbers), and modifies the document in-place.\n\nLoofah overrides `to_s` to return HTML:\n\n``` ruby\nunsafe_html = \"ohai! \u003cdiv\u003ediv is safe\u003c/div\u003e \u003cscript\u003ebut script is not\u003c/script\u003e\"\n\ndoc = Loofah.html5_fragment(unsafe_html).scrub!(:prune)\ndoc.to_s    # =\u003e \"ohai! \u003cdiv\u003ediv is safe\u003c/div\u003e \"\n```\n\nand `text` to return plain text:\n\n``` ruby\ndoc.text    # =\u003e \"ohai! div is safe \"\n```\n\nAlso, `to_text` is available, which does the right thing with whitespace around block-level and line break elements.\n\n``` ruby\ndoc = Loofah.html5_fragment(\"\u003ch1\u003eTitle\u003c/h1\u003e\u003cdiv\u003eContent\u003cbr\u003eNext line\u003c/div\u003e\")\ndoc.text    # =\u003e \"TitleContentNext line\"            # probably not what you want\ndoc.to_text # =\u003e \"\\nTitle\\n\\nContent\\nNext line\\n\"  # better\n```\n\n### `Loofah::HTML4::Document` and `Loofah::HTML4::DocumentFragment`\n\nThese classes are subclasses of `Nokogiri::HTML4::Document` and `Nokogiri::HTML4::DocumentFragment`.\n\nThe module methods `Loofah.html4_document` and `Loofah.html4_fragment` will parse either an HTML document and an HTML fragment, respectively.\n\n``` ruby\nLoofah.html4_document(unsafe_html).is_a?(Nokogiri::HTML4::Document)         # =\u003e true\nLoofah.html4_fragment(unsafe_html).is_a?(Nokogiri::HTML4::DocumentFragment) # =\u003e true\n```\n\n### `Loofah::XML::Document` and `Loofah::XML::DocumentFragment`\n\nThese classes are subclasses of `Nokogiri::XML::Document` and `Nokogiri::XML::DocumentFragment`.\n\nThe module methods `Loofah.xml_document` and `Loofah.xml_fragment` will parse an XML document and an XML fragment, respectively.\n\n``` ruby\nLoofah.xml_document(bad_xml).is_a?(Nokogiri::XML::Document)         # =\u003e true\nLoofah.xml_fragment(bad_xml).is_a?(Nokogiri::XML::DocumentFragment) # =\u003e true\n```\n\n### Nodes and Node Sets\n\nNokogiri's `Node` and `NodeSet` classes also get a `scrub!` method, which makes it easy to scrub subtrees.\n\nThe following code will apply the `employee_scrubber` only to the `employee` nodes (and their subtrees) in the document:\n\n``` ruby\nLoofah.xml_document(bad_xml).xpath(\"//employee\").scrub!(employee_scrubber)\n```\n\nAnd this code will only scrub the first `employee` node and its subtree:\n\n``` ruby\nLoofah.xml_document(bad_xml).at_xpath(\"//employee\").scrub!(employee_scrubber)\n```\n\n### `Loofah::Scrubber`\n\nA Scrubber wraps up a block (or method) that is run on a document node:\n\n``` ruby\n# change all \u003cspan\u003e tags to \u003cdiv\u003e tags\nspan2div = Loofah::Scrubber.new do |node|\n  node.name = \"div\" if node.name == \"span\"\nend\n```\n\nThis can then be run on a document:\n\n``` ruby\nLoofah.html5_fragment(\"\u003cspan\u003efoo\u003c/span\u003e\u003cp\u003ebar\u003c/p\u003e\").scrub!(span2div).to_s\n# =\u003e \"\u003cdiv\u003efoo\u003c/div\u003e\u003cp\u003ebar\u003c/p\u003e\"\n```\n\nScrubbers can be run on a document in either a top-down traversal (the default) or bottom-up. Top-down scrubbers can optionally return `Scrubber::STOP` to terminate the traversal of a subtree. Read below and in the `Loofah::Scrubber` class for more detailed usage.\n\nHere's an XML example:\n\n``` ruby\n# remove all \u003cemployee\u003e tags that have a \"deceased\" attribute set to true\nbring_out_your_dead = Loofah::Scrubber.new do |node|\n  if node.name == \"employee\" and node[\"deceased\"] == \"true\"\n    node.remove\n    Loofah::Scrubber::STOP # don't bother with the rest of the subtree\n  end\nend\nLoofah.xml_document(File.read('plague.xml')).scrub!(bring_out_your_dead)\n```\n\n### Built-In HTML Scrubbers\n\nLoofah comes with a set of sanitizing scrubbers that use `html5lib`'s safelist algorithm:\n\n``` ruby\ndoc = Loofah.html5_document(input)\ndoc.scrub!(:strip)       # replaces unknown/unsafe tags with their inner text\ndoc.scrub!(:prune)       #  removes unknown/unsafe tags and their children\ndoc.scrub!(:escape)      #  escapes unknown/unsafe tags, like this: \u0026lt;script\u0026gt;\ndoc.scrub!(:whitewash)   #  removes unknown/unsafe/namespaced tags and their children,\n                         #          and strips all node attributes\n```\n\nLoofah also comes with built-in scrubers for some common transformation tasks:\n\n``` ruby\ndoc.scrub!(:nofollow)          # adds rel=\"nofollow\" attribute to links\ndoc.scrub!(:noopener)          # adds rel=\"noopener\" attribute to links\ndoc.scrub!(:noreferrer)        # adds rel=\"noreferrer\" attribute to links\ndoc.scrub!(:unprintable)       # removes unprintable characters from text nodes\ndoc.scrub!(:targetblank)       # adds target=\"_blank\" attribute to links\ndoc.scrub!(:double_breakpoint) # where `\u003cbr\u003e\u003cbr\u003e` appears in a `p` tag, close the `p` and open a new one\n```\n\nSee `Loofah::Scrubbers` for more details and example usage.\n\n\n### Chaining Scrubbers\n\nYou can chain scrubbers:\n\n``` ruby\nLoofah.html5_fragment(\"\u003cspan\u003ehello\u003c/span\u003e \u003cscript\u003ealert('OHAI')\u003c/script\u003e\") \\\n      .scrub!(:prune) \\\n      .scrub!(span2div).to_s\n# =\u003e \"\u003cdiv\u003ehello\u003c/div\u003e \"\n```\n\n### Shorthand\n\nThe class methods `Loofah.scrub_html5_fragment` and `Loofah.scrub_html5_document` (and the corresponding HTML4 methods) are shorthand.\n\nThese methods:\n\n``` ruby\nLoofah.scrub_html5_fragment(unsafe_html, :prune)\nLoofah.scrub_html5_document(unsafe_html, :prune)\nLoofah.scrub_html4_fragment(unsafe_html, :prune)\nLoofah.scrub_html4_document(unsafe_html, :prune)\nLoofah.scrub_xml_fragment(bad_xml, custom_scrubber)\nLoofah.scrub_xml_document(bad_xml, custom_scrubber)\n```\n\ndo the same thing as (and arguably semantically clearer than):\n\n``` ruby\nLoofah.html5_fragment(unsafe_html).scrub!(:prune)\nLoofah.html5_document(unsafe_html).scrub!(:prune)\nLoofah.html4_fragment(unsafe_html).scrub!(:prune)\nLoofah.html4_document(unsafe_html).scrub!(:prune)\nLoofah.xml_fragment(bad_xml).scrub!(custom_scrubber)\nLoofah.xml_document(bad_xml).scrub!(custom_scrubber)\n```\n\n\n### View Helpers\n\nLoofah has two \"view helpers\": `Loofah::Helpers.sanitize` and `Loofah::Helpers.strip_tags`, both of which are drop-in replacements for the Rails Action View helpers of the same name.\n\nThese are not required automatically. You must require `loofah/helpers` to use them.\n\n\n## Requirements\n\n* Nokogiri \u003e= 1.5.9\n\n\n## Installation\n\nUnsurprisingly:\n\n\u003e gem install loofah\n\nRequirements:\n\n* Ruby \u003e= 2.5\n\n\n## Support\n\nThe bug tracker is available here:\n\n* https://github.com/flavorjones/loofah/issues\n\nAnd the mailing list is on Google Groups:\n\n* Mail: loofah-talk@googlegroups.com\n* Archive: https://groups.google.com/forum/#!forum/loofah-talk\n\nConsider subscribing to [Tidelift][tidelift] which provides license assurances and timely security notifications for your open source dependencies, including Loofah. [Tidelift][tidelift] subscriptions also help the Loofah maintainers fund our [automated testing](https://ci.nokogiri.org) which in turn allows us to ship releases, bugfixes, and security updates more often.\n\n  [tidelift]: https://tidelift.com/subscription/pkg/rubygems-loofah?utm_source=undefined\u0026utm_medium=referral\u0026utm_campaign=enterprise\n\n\n## Security\n\nSee [`SECURITY.md`](SECURITY.md) for vulnerability reporting details.\n\n\n## Related Links\n\n* loofah-activerecord: https://github.com/flavorjones/loofah-activerecord\n* Nokogiri: http://nokogiri.org\n* libxml2: http://xmlsoft.org\n* html5lib: https://github.com/html5lib/\n\n\n## Authors\n\n* [Mike Dalessio](http://mike.daless.io) ([@flavorjones](https://twitter.com/flavorjones))\n* Bryan Helmkamp\n\nFeaturing code contributed by:\n\n* [@flavorjones](https://github.com/flavorjones)\n* [@brynary](https://github.com/brynary)\n* [@olleolleolle](https://github.com/olleolleolle)\n* [@JuanitoFatas](https://github.com/JuanitoFatas)\n* [@kaspth](https://github.com/kaspth)\n* [@tenderlove](https://github.com/tenderlove)\n* [@ktdreyer](https://github.com/ktdreyer)\n* [@orien](https://github.com/orien)\n* [@asok](https://github.com/asok)\n* [@junaruga](https://github.com/junaruga)\n* [@MothOnMars](https://github.com/MothOnMars)\n* [@nick-desteffen](https://github.com/nick-desteffen)\n* [@NikoRoberts](https://github.com/NikoRoberts)\n* [@trans](https://github.com/trans)\n* [@andreynering](https://github.com/andreynering)\n* [@aried3r](https://github.com/aried3r)\n* [@baopham](https://github.com/baopham)\n* [@batter](https://github.com/batter)\n* [@brendon](https://github.com/brendon)\n* [@cjba7](https://github.com/cjba7)\n* [@christiankisssner](https://github.com/christiankisssner)\n* [@dacort](https://github.com/dacort)\n* [@danfstucky](https://github.com/danfstucky)\n* [@david-a-wheeler](https://github.com/david-a-wheeler)\n* [@dharamgollapudi](https://github.com/dharamgollapudi)\n* [@georgeclaghorn](https://github.com/georgeclaghorn)\n* [@gogainda](https://github.com/gogainda)\n* [@jaredbeck](https://github.com/jaredbeck)\n* [@ThatHurleyGuy](https://github.com/ThatHurleyGuy)\n* [@jstorimer](https://github.com/jstorimer)\n* [@jbarnette](https://github.com/jbarnette)\n* [@queso](https://github.com/queso)\n* [@technicalpickles](https://github.com/technicalpickles)\n* [@kyoshidajp](https://github.com/kyoshidajp)\n* [@kristianfreeman](https://github.com/kristianfreeman)\n* [@louim](https://github.com/louim)\n* [@mrpasquini](https://github.com/mrpasquini)\n* [@olivierlacan](https://github.com/olivierlacan)\n* [@pauldix](https://github.com/pauldix)\n* [@sampokuokkanen](https://github.com/sampokuokkanen)\n* [@stefannibrasil](https://github.com/stefannibrasil)\n* [@tastycode](https://github.com/tastycode)\n* [@vipulnsward](https://github.com/vipulnsward)\n* [@joncalhoun](https://github.com/joncalhoun)\n* [@ahorek](https://github.com/ahorek)\n* [@rmacklin](https://github.com/rmacklin)\n* [@y-yagi](https://github.com/y-yagi)\n* [@lazyatom](https://github.com/lazyatom)\n\nAnd a big shout-out to Corey Innis for the name, and feedback on the API.\n\n\n## Thank You\n\nThe following people have generously funded Loofah with financial sponsorship:\n\n* Bill Harding\n* [Sentry](https://sentry.io/) @getsentry\n\n\n## Historical Note\n\nThis library was once named \"Dryopteris\", which was a very bad name that nobody could spell properly.\n\n\n## License\n\nDistributed under the MIT License. See `MIT-LICENSE.txt` for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflavorjones%2Floofah","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflavorjones%2Floofah","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflavorjones%2Floofah/lists"}