HTML::Defang(3pm)
π¦ HTML::Defang β the module that eats XSS for breakfast π¦
okay bestie so you found the manpage for HTML::Defang(3pm) β a User Contributed Perl Documentation page β and honestly? it's giving bodyguard energy. this thing scrubs HTML and CSS clean of scripting, embedded objects, applets, all the spooky executable stuff, and it neutralises XSS attacks. no cap. sit down, we're doing this together π
β¨ NAME β¨
HTML::Defang β Cleans HTML as well as CSS of scripting and other executable contents, and neutralises XSS attacks.
πΈ SYNOPSIS πΈ
here's the vibe, literally copy-paste goals:
my $InputHtml = "<html><body></body></html>";
my $Defang = HTML::Defang->new(
context => $Self,
fix_mismatched_tags => 1,
tags_to_callback => [ br embed img ],
tags_callback => \&DefangTagsCallback,
url_callback => \&DefangUrlCallback,
css_callback => \&DefangCssCallback,
attribs_to_callback => [ qw(border src) ],
attribs_callback => \&DefangAttribsCallback,
content_callback => \&ContentCallback,
);
my $SanitizedHtml = $Defang->defang($InputHtml);
# Callback for custom handling specific HTML tags
sub DefangTagsCallback {
my ($Self, $Defang, $OpenAngle, $lcTag, $IsEndTag, $AttributeHash, $CloseAngle, $HtmlR, $OutR) = @_;
# Explicitly defang this tag, eventhough safe
return DEFANG_ALWAYS if $lcTag eq 'br';
# Explicitly whitelist this tag, eventhough unsafe
return DEFANG_NONE if $lcTag eq 'embed';
# I am not sure what to do with this tag, so process as HTML::Defang normally would
return DEFANG_DEFAULT if $lcTag eq 'img';
}
# Callback for custom handling URLs in HTML attributes as well as style tag/attribute declarations
sub DefangUrlCallback {
my ($Self, $Defang, $lcTag, $lcAttrKey, $AttrValR, $AttributeHash, $HtmlR) = @_;
# Explicitly allow this URL in tag attributes or stylesheets
return DEFANG_NONE if $$AttrValR =~ /safesite.com/i;
# Explicitly defang this URL in tag attributes or stylesheets
return DEFANG_ALWAYS if $$AttrValR =~ /evilsite.com/i;
}
# Callback for custom handling style tags/attributes
sub DefangCssCallback {
my ($Self, $Defang, $Selectors, $SelectorRules, $Tag, $IsAttr) = @_;
my $i = 0;
foreach (@$Selectors) {
my $SelectorRule = $$SelectorRules[$i];
foreach my $KeyValueRules (@$SelectorRule) {
foreach my $KeyValueRule (@$KeyValueRules) {
my ($Key, $Value) = @$KeyValueRule;
# Comment out any '!important' directive
$$KeyValueRule[2] = DEFANG_ALWAYS if $Value =~ '!important';
# Comment out any 'position=fixed;' declaration
$$KeyValueRule[2] = DEFANG_ALWAYS if $Key =~ 'position' && $Value =~ 'fixed';
}
}
$i++;
}
}
# Callback for custom handling HTML tag attributes
sub DefangAttribsCallback {
my ($Self, $Defang, $lcTag, $lcAttrKey, $AttrValR, $HtmlR) = @_;
# Change all 'border' attribute values to zero.
$$AttrValR = '0' if $lcAttrKey eq 'border';
# Defang all 'src' attributes
return DEFANG_ALWAYS if $lcAttrKey eq 'src';
return DEFANG_NONE;
}
# Callback for all content between tags (except <style>, <script>, etc)
sub DefangContentCallback {
my ($Self, $Defang, $ContentR) = @_;
$$ContentR =~ s/remove this content//;
}
π DESCRIPTION π
so like. this module takes an input HTML and/or CSS string and removes any executable code β scripting, embedded objects, applets, the whole rogues' gallery β and neutralises any XSS attacks. and how does it decide what stays? a whitelist based approach, bestie. only HTML that's known to be safe gets to walk through the velvet rope. everyone else? blocked. π«β¨
HTML::Defang uses a custom html tag parser. and this parser was designed and tested to work with nasty real world html, and to try and emulate as close as possible what browsers actually do with strange looking constructs. the test suite is built from examples from a range of sources such as http://ha.ckers.org/xss.html and http://imfo.ru/csstest/css_hacks/import.php so that as many as possible XSS attack scenarios have been dealt with. we love a girl who did her homework. ππ
HTML::Defang can make callbacks to client code when it encounters the following:
- When a specified tag is parsed
- When a specified attribute is parsed
- When a URL is parsed as part of an HTML attribute, or CSS property value.
- When style data is parsed, as part of an HTML style attribute, or as part of an HTML
<style>tag.
the callbacks include details about the current tag/attribute that is being parsed, and also gives a scalar reference to the input HTML. querying pos() on the input HTML should indicate where the module is with parsing. this gives the client code flexibility in working with HTML::Defang. π§ β¨
HTML::Defang can defang whole tags, any attribute in a tag, any URL that appear as an attribute or style property, or any CSS declaration in a declaration block in a style rule. this helps to precisely block the most specific unwanted elements in the contents (for example, block just an offending attribute instead of the whole tag), while retaining any safe HTML/CSS. surgical, honestly. main character energy. π₯
π CONSTRUCTOR π
HTML::Defang->new(%Options)
Constructs a new HTML::Defang object. the following options are supported:
Options
tags_to_callbackβ Array reference of tags for which a call back should be made. If a tag in this array is parsed, the subroutinetags_callback()is invoked.attribs_to_callbackβ Array reference of tag attributes for which a call back should be made. If an attribute in this array is parsed, the subroutineattribs_callback()is invoked.tags_callbackβ Subroutine reference to be invoked when a tag listed in@$tags_to_callbackis parsed.attribs_callbackβ Subroutine reference to be invoked when an attribute listed in@$attribs_to_callbackis parsed.url_callbackβ Subroutine reference to be invoked when a URL is detected in an HTML tag attribute or a CSS property.css_callbackβ Subroutine reference to be invoked when CSS data is found either as the contents of a'style'attribute in an HTML tag, or as the contents of a<style>HTML tag.content_callbackβ Subroutine reference to be invoked when standard content between HTML tags in found.fix_mismatched_tagsβ This property, if set, fixes mismatched tags in the HTML input. By default, tags present in the default%mismatched_tags_to_fixhash are fixed. This set of tags can be overridden by passing in an array reference$mismatched_tags_to_fixto the constructor. Any opened tags in the set are automatically closed if no corresponding closing tag is found. If an unbalanced closing tag is found, that is commented out.mismatched_tags_to_fixβ Array reference of tags for which the code would check for matching opening and closing tags. See the property$fix_mismatched_tags.contextβ You can pass an arbitrary scalar as a'context'value that's then passed as the first parameter to all callback functions. Most commonly this is something like'$Self'allow_double_defangβ If this is true, then tag names and attribute names which already begin with the defang string ("defang_"by default) will have an additional copy of the defang string prepended if they are flagged to be defanged by the return value of a callback, or if the tag or attribute name is unknown. The default is to assume that tag names and attribute names beginning with the defang string are already made safe, and need no further modification, even if they are flagged to be defanged by the return value of a callback. Any tag or attribute modifications made directly by a callback are still performed.delete_defang_contentβ Normally defanged tags are turned into comments and prefixed bydefang_, and defanged styles are surrounded by/* ... */. If this is set to true, then defanged content is deleted insteadDebugβ If set, prints debugging output.
HTML::Defang->new_bodyonly(%Options)
Constructs a new HTML::Defang object that has the following implicit options
fix_mismatched_tags = 1
delete_defang_content = 1
tags_to_callback = [ qw(html head link body meta title bgsound) ]
tags_callback = { ... remove all above tags and related content ... }
url_callback = { ... explicity DEFANG_NONE to leave everything alone ... }
Basically this is a easy way to remove all html boiler plate content and return only the html body content.
β¦and that's part 1, bestie β more coming, don't you dare close the tab π
π CALLBACK METHODS π
πΈ COMMON PARAMETERS πΈ
okay so bestie, a whole bunch of these callbacks share the same lil' parameters, so instead of repeating ourselves 500 times we're documenting them right here. but heads up: some variables mean specific things in specific callbacks, so pleaseee check that method's own docs first before you come running back to this section, mkay? π«Ά
β¨ $context
You can pass literally any arbitrary scalar as a 'context' value, and it gets handed to all your callback functions as the very first parameter. most of the time this is something like $Self β that's the vibe. π
β¨ $Defang
the current HTML::Defang instance. your main character. π
β¨ $OpenAngle
the opening angle sign (<) of whatever tag we're on right now.
β¨ $lcTag
lower case version of the HTML tag currently being parsed. so <DIV> gives you div, lowercase, no drama. π¦
β¨ $IsEndTag
has the value / if the current tag is a closing tag. that's it. that's the whole value. no cap. β¨
β¨ $AttributeHash
a reference to a hash holding the attributes of the current tag and their values. important: each value is a scalar reference to the value, not just a plain scalar value. π€
you can do whatever you want in here:
- add attributes (remember, make it a scalar ref, like
$AttributeHash{"newattr"} = \"newval") - delete attributes
- modify attribute values
and literally any change you make gets incorporated into the output HTML stream. slay. π₯
The attribute values will have any entity references decoded before being passed to you, and any unsafe values we be re-encoded back into the HTML stream.
so for instance, this tag:
<div title="<"Hi there <">
will have the attribute hash:
{ title => \q[<"Hi there <] }
and will be turned back into the HTML on output as:
<div title="<"Hi there <">
π see? decoded on the way in, re-encoded on the way out. balance. π
β¨ $CloseAngle
anything after the end of the last attribute, including the closing HTML angle (>). everything in the gap, basically.
β¨ $HtmlR
a scalar reference to the input HTML. the input HTML is parsed using m/\G$SomeRegex/c constructs, so to continue from where HTML:Defang left off, clients can use m/\G$SomeRegex/c for further processing on the input. this will resume parsing from where HTML::Defang left. π
you can also use the pos() function to figure out where HTML::Defang left off. this combined with the add_to_output() method should give you reasonable flexibility to process the input however you like. fr fr. π§
β¨ $OutR
a scalar reference to the processed output HTML so far. the receipts, if you will. π
π tags_callback($context, $Defang, $OpenAngle, $lcTag, $IsEndTag, $AttributeHash, $CloseAngle, $HtmlR, $OutR) π
If $Defang->{tags_callback} exists, and HTML::Defang has parsed a tag preset in $Defang->{tags_to_callback}, the above callback is made to the client code. π£
the return value of this method determines whether the tag is defanged or not. more details below bestie, don't scroll past. π
π Return values
DEFANG_NONEβ the current tag will not be defanged. leave my girl alone. πDEFANG_ALWAYSβ the current tag will be defanged. periodt. πDEFANG_DEFAULTβ the current tag will be processed totally normally byHTML:Defang, as if there was no callback method specified at all. the "never mind, forget I said anything" option. π
π¦ attribs_callback($context, $Defang, $lcTag, $lcAttrKey, $AttrVal, $HtmlR, $OutR) π¦
If $Defang->{attribs_callback} exists, and HTML::Defang has parsed an attribute present in $Defang->{attribs_to_callback}, the above callback is made to the client code. π£
the return value of this method determines whether the attribute is defanged or not. more details below. β¨
π Method parameters
$lcAttrKeyβ lower case version of the HTML attribute that is currently being parsed.$AttrValβ reference to the HTML attribute value that is currently being parsed. see$AttributeHashabove for details of decoding. π
π Return values
DEFANG_NONEβ the current attribute will not be defanged.DEFANG_ALWAYSβ the current attribute will be defanged.DEFANG_DEFAULTβ the current attribute will be processed normally byHTML:Defangas if there was no callback method specified. classic. π
π url_callback($context, $Defang, $lcTag, $lcAttrKey, $AttrVal, $AttributeHash, $HtmlR, $OutR) π
If $Defang->{url_callback} exists, and HTML::Defang has parsed a URL, the above callback is made to the client code. π£
the return value of this method determines whether the attribute containing the URL is defanged or not. and omg β URL callbacks can be made from <style> tags as well as style attributes, in which case the particular style declaration will be commented out. more details below. π€
π Method parameters
$lcAttrKeyβ lower case version of the HTML attribute that is currently being parsed. BUT π if this callback is made as a result of parsing a URL in a style attribute,$lcAttrKeywill be set to the stringstyle, or will be set toundefif this callback is made as a result of parsing a URL inside a style tag.$AttrValβ reference to the URL value that is currently being parsed.$AttributeHashβ a reference to a hash containing the attributes of the current tag and their values. each value is a scalar reference to the value, rather than just a scalar value. you can add attributes (remember to make it a scalar ref, like$AttributeHash{"newattr"} = \"newval"), delete attributes, or modify attribute values in this hash, and any changes you make will be incorporated into the output HTML stream. π
β οΈ this one will be set toundefif the callback is made due to a URL in a<style>tag or attribute. so check before you go poking at it, bestie!!
π Return values
DEFANG_NONEβ the current URL will not be defanged.DEFANG_ALWAYSβ the current URL will be defanged.DEFANG_DEFAULTβ the current URL will be processed normally byHTML:Defangas if there was no callback method specified. π
π
css_callback($context, $Defang, $Selectors, $SelectorRules, $lcTag, $IsAttr, $OutR) π
If $Defang->{css_callback} exists, and HTML::Defang has parsed a <style> tag or style attribtue, the above callback is made to the client code. π£
the return value of this method determines whether a particular declaration in the style rules is defanged or not. more details below. π₯
π Method parameters
$Selectorsβ reference to an array containing the selectors in a style tag or attribute.$SelectorRulesβ reference to an array containing the style declaration blocks of all selectors in a style tag or attribute. consider the below CSS:
a { b:c; d:e}
j { k:l; m:n}
The declaration blocks will get parsed into the following data structure:
[
[
[ "b", "c", DEFANG_DEFAULT ],
[ "d", "e", DEFANG_DEFAULT ]
],
[
[ "k", "l", DEFANG_DEFAULT ],
[ "m", "n", DEFANG_DEFAULT ]
]
]
So, generally each property:value pair in a declaration is parsed into an array of the form
["property", "value", X]
where X can be DEFANG_NONE, DEFANG_ALWAYS or DEFANG_DEFAULT, and DEFANG_DEFAULT is the default value. a client can manipulate this value to instruct HTML::Defang to defang this property:value pair. π«‘
DEFANG_NONEβ Do not defangDEFANG_ALWAYSβ Defang thestyle:propertyvalueDEFANG_DEFAULTβ Process this as if there is no callback specified$IsAttrβ True if the currently processed item is a style attribute. False if the currently processed item is a style tag. boolean moment. β¨
π¦ METHODS π¦
ok so this is where the actual machinery lives, bestie. the constructors and callbacks already did their thing β now we get into the functions that do the scrubbing. grab a snack. π
π PUBLIC METHODS π
These are the ones you, the person writing code, actually call. main character energy only.
defang($InputHtml, \%Opts)
Cleans up $InputHtml of any executable code β scripting, embedded objects, applets, etc. β and defangs any XSS attacks. it's giving bodyguard, honestly. π‘οΈβ¨
Method parameters:
$InputHtmlβ the input HTML string that needs to be sanitized.
Returns the cleaned HTML. And heads up: if fix_mismatched_tags is set, any tags that appear in @$mismatched_tags_to_fix that are unbalanced get automatically commented or closed. it literally just tidies up after itself. π
add_to_output($String)
Appends $String to the output after the current parsed tag ends. This one exists so client code can add HTML text to the processed output from inside callback methods. π
And if that HTML text itself needs defanging? no stress β client code can safely call HTML::Defang->defang() recursively from within the callback. recursive queen behavior fr fr. π«Ά
Method parameters:
$Stringβ the string that is added after the current parsed tag ends.
π§ INTERNAL METHODS π§
ngl these are the backstage crew. you probably never talk to them directly.
Generally these methods never need to be called by users of the class, because they'll be called internally as the appropriate tags are encountered, but they may be useful for some users in some cases. π
defang_script_tag($OutR, $HtmlR, $TagOps, $OpenAngle, $IsEndTag, $Tag, $TagTrail, $Attributes, $CloseAngle)
This method is invoked when a <script> tag is parsed. It defangs the <script> opening tag, and any closing tag. Any scripting content is also commented out, so browsers don't display them. π bye script, you're not doing all that here.
Returns 1 to indicate that the <script> tag must be defanged.
Method parameters:
$OutRβ a reference to the processed output HTML before the tag that is currently being parsed.$HtmlRβ a scalar reference to the input HTML.$TagOpsβ indicates what operation should be done on a tag. Can be undefined, integer or code reference. Undefined indicates an unknown tag toHTML::Defang,1indicates a known safe tag,0indicates a known unsafe tag, and a code reference indicates a subroutine that should be called to parse the current tag. For example,<style>and<script>tags are parsed by dedicated subroutines. π§$OpenAngleβ opening angle(<) sign of the current tag.$IsEndTagβ has the value/if the current tag is a closing tag.$Tagβ the HTML tag that is currently being parsed.$TagTrailβ any space after the tag, but before attributes.$Attributesβ a reference to an array of the attributes and their values, including any surrouding spaces. Each element of the array is added bypushcalls like below.
push @$Attributes, [ $AttributeName, $SpaceBeforeEquals, $EqualsAndSubsequentSpace, $QuoteChar, $AttributeValue, $QuoteChar, $SpaceAfterAtributeValue ];
$CloseAngleβ anything after the end of last attribute including the closing HTML angle(>)
defang_style_text($Content, $lcTag, $IsAttr, $AttributeHash, $HtmlR, $OutR)
Defang some raw css data and return the defanged content. css said "let me in" and this method said "absolutely not". π
Method parameters:
$Contentβ the input style string that is defanged.$IsAttrβ true if$Contentis from an attribute, otherwise from a<style>block.
cleanup_style($StyleString)
Helper function to clean up CSS data. Heads up tho β this function directly operates on the input string without taking a copy. it is not playing about your original string, bestie. π
Method parameters:
$StyleStringβ the input style string that is cleaned.
defang_stylerule($SelectorsIn, $StyleRules, $lcTag, $IsAttr, $AttributeHash, $HtmlR, $OutR)
Defangs style data. that's the whole vibe check. β¨
Method parameters:
$SelectorsInβ an array reference to the selectors in the style tag/attribute contents.$StyleRulesβ an array reference to the declaration blocks in the style tag/attribute contents.$lcTagβ lower case version of the HTML tag that is currently being parsed.$IsAttrβ whether we are currently parsing a style attribute or style tag.$IsAttrwill be true if we are currently parsing a style attribute.$HtmlRβ a scalar reference to the input HTML.$OutRβ a scalar reference to the processed output so far.
defang_attributes($OutR, $HtmlR, $TagOps, $OpenAngle, $IsEndTag, $Tag, $TagTrail, $Attributes, $CloseAngle)
Defangs attributes, defangs tags, and does the tag, attrib, css and url callbacks. multitasking icon. π₯
Method parameters:
- For a description of the method parameters, see documentation of
defang_script_tag()method.
cleanup_attribute($AttributeString)
Helper function to cleanup attributes. cute little finishing touch. π
Method parameters:
$AttributeStringβ the value of the attribute.
π SEE ALSO π
- <http://mailtools.anomy.net/>
- <http://htmlcleaner.sourceforge.net/>
HTML::StripScriptsHTML::DetoxifierHTML::SanitizerHTML::Scrubber
βοΈ AUTHOR βοΈ
Kurian Jose Aerthail <cpan@kurianja.fastmail.fm>. Thanks to Rob Mueller <cpan@robm.fastmail.fm> for initial code, guidance and support and bug fixes. shoutout to the OGs. π«‘π
π COPYRIGHT AND LICENSE π
Copyright (C) 2003-2013 by FastMail Pty Ltd
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
and that's the whole page, bestie, you're officially caught up π this was rendered from perl v5.40.1, dated 2025-11-08, for HTML::Defang(3pm) β go forth and defang responsibly, periodt. β¨ππ¦
π¦ where this page comes from
- ubuntu resolute: libhtml-defang-perl 1.08-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libhtml-defang-perl 1.08-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms