Instead of trying to handle external tags/filters inside the sandbox,
yield back to the caller with [:tag, ...] or [:filter, ...] args.
This cleanly separates concerns:
- Sandbox handles compiled template logic
- Caller handles external calls with full Ruby access
API:
compiled.render(assigns) do |call_type, *args|
case call_type
when :tag
tag_var, tag_assigns = args
# Handle with full Liquid context
when :filter
filter_name, input, filter_args = args
# Handle with custom filter handler
end
end
If no block is given, a default handler is used that:
- Renders external tags using Liquid::Context
- Calls filter methods via filter_handler
Also:
- Keep public_send in sandbox (safe, only calls public methods)
- Load date/time libs into sandbox for date filter support
- Preserve Date, DateTime, Time constants after lock
- compiled_template.rb: Use Liquid::Box for secure execution on Ruby 4.0+
- Creates box, loads runtime, locks, then evals template code
- Provides render() method and secure? check
- Falls back to insecure eval with warning on Ruby < 4.0
- ruby_compiler.rb: Remove inline helper generation
- Helpers now provided by pre-loaded LR module
- Generated code is much smaller (just control flow + LR calls)
- compile.rb: Update documentation for new security model
- template.rb: Update compile_to_ruby docs
The LR module provides all helper methods for compiled templates.
It is loaded into the sandbox BEFORE lock!, so helpers are defined
once and shared by all templates.
Helpers include:
- Type conversion: to_s, to_number, to_integer
- Output: output (handles nil, arrays, BigDecimal formatting)
- Lookup: lookup (hash/array access, Drop context support)
- Encoding: escape_html, url_encode/decode, base64_encode/decode
- Filters: truncate, truncatewords, slice, date, default, etc.
Method references to CGI, Base64, BigDecimal are captured at load
time, enabling safe use of these libraries within the sandbox.
Design principle: Maximize work in pre-loaded runtime, minimize
generated template code.
Introduces Liquid::Box which wraps Ruby 4.0's Ruby::Box for secure
template execution. On Ruby < 4.0, provides a polyfill with security
warnings.
Key features:
- Detects Ruby::Box availability at load time
- Loads safe libraries (CGI, Base64, BigDecimal) into sandbox
- Neuters dangerous methods (file IO, process control, eval, etc.)
- Preserves user constants defined before lock!
- Provides setup_gem_load_paths! to enable gem requires in box
Security model: It is safe to expose side-effect-free, non-IO methods
that don't leak objects with dangerous methods. The sandbox blocks
capabilities, not data.