Add UnescapedHtml linter#656
Open
wilfison wants to merge 1 commit into
Open
Conversation
Flag HAML's unescaped-output markers (`!=`, `!~`, and dynamic plain-text `!`) at script and tag level. These bypass HTML escaping and make it easy to introduce XSS holes when output includes user-controlled data. Detection uses the source marker (anchored so the Ruby `!=` operator is not flagged); only unescaped output of dynamic content is reported. Enabled by default, detection only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #550
Summary
Adds a new
UnescapedHtmllinter that flags HAML's unescaped-output markers, which bypass HTML escaping. As noted in #550, just likeraw,html_safe, andh()in Rails, these markers make it easy to accidentally introduce XSS holes when the output includes user-controlled data — for example:!= "Username: <strong>#{user.name}</strong>"RuboCop's
Rails/OutputSafetycop catchesraw/html_safe/safe_concat, but it never sees these because they are a HAML construct, not Ruby. This linter fills that gap.What is flagged
The linter targets every HAML marker that emits unescaped output of dynamic content:
= value~ value!= value!~ value! text #{value}%tag!= value%tag!~ value! static text%p= a != b!=operator, not an unescape markerThe distinction is intentional: only unescaped output of dynamic content is reported, since static markup carries no injection risk.
Implementation notes
@value[:escape_html]:haml-lint parses with HTML escaping disabled, so both
=and!=reportescape_html: falseand cannot be told apart that way.:scriptnodes the check is anchored at the start of the source(
/\A\s*!/), so it covers!=,!~, and the dynamic plain-text!formwhile never matching a Ruby
!=operator inside an escaped expression.:tagnodes a newTagNode#unescape_html?helper inspects the contentmarker that follows the tag name and attributes. The existing attribute-source
scan was refactored into a single memoized
parsed_attributes_sourcethat nowalso exposes the trailing
inline_marker_source, keeping tag-source parsing inone place.
!=to=would change behavior and could escapeHTML the author intentionally left raw, so this is detection only.
Enabled by default
The linter ships enabled in
config/default.yml.Testing