diff --git a/lib/liquid/errors.rb b/lib/liquid/errors.rb index 84074114..bb9132db 100644 --- a/lib/liquid/errors.rb +++ b/lib/liquid/errors.rb @@ -54,5 +54,6 @@ module Liquid class StandardError < Error; end class SyntaxError < Error; end class StackLevelError < Error; end + class TaintedError < Error; end class MemoryError < Error; end end diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb index 392a9f9f..20d2a930 100644 --- a/lib/liquid/template.rb +++ b/lib/liquid/template.rb @@ -60,6 +60,12 @@ module Liquid # :strict will enforce correct syntax. attr_writer :error_mode + # Sets how strict the taint checker should be. + # :lax ignores the taint flag completely (like previous liquid versions) + # :warn adds a warning, but does not interrupt the rendering + # :error raises an error when tainted output is used + attr_writer :taint_mode + def file_system @@file_system end @@ -80,6 +86,10 @@ module Liquid @error_mode || :lax end + def taint_mode + @taint_mode || :lax + end + # Pass a module with filter methods which should be available # to all liquid views. Good for registering the standard library def register_filter(mod) diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb index 5b5d446e..63ca1cd4 100644 --- a/lib/liquid/variable.rb +++ b/lib/liquid/variable.rb @@ -94,6 +94,16 @@ module Liquid end filterargs << keyword_args unless keyword_args.empty? output = context.invoke(filter[0], output, *filterargs) + end.tap do |obj| + if obj.tainted? + case Template.taint_mode + when :warn + @warnings ||= [] + @warnings << "variable '#{@name}' is tainted and was not escaped" + when :error + raise TaintedError, "Error - variable '#{@name}' is tainted and was not escaped" + end + end end end end