-
Notifications
You must be signed in to change notification settings - Fork 0
Sandbox Mode
Twig's sandbox mode provides a secure way to run templates with restricted permissions. This is particularly useful when including templates from potentially untrusted sources or when you want to ensure templates cannot access sensitive operations or data.
The sandbox mode in Twig works by:
- Defining a security policy that specifies what functions, filters, and tags are allowed
- Enabling the sandbox on the engine or within a specific template context
- Preventing templates from using any functions, filters, or tags not explicitly allowed by the policy
// Create a security policy with default safe settings
policy := twig.NewDefaultSecurityPolicy()
// Or create a completely custom policy
// policy := &twig.DefaultSecurityPolicy{
// AllowedFunctions: make(map[string]bool),
// AllowedFilters: make(map[string]bool),
// AllowedTags: make(map[string]bool),
// }
// Customize allowed functions
policy.AllowedFunctions["range"] = true
policy.AllowedFunctions["date"] = true
// Customize allowed filters
policy.AllowedFilters["upper"] = true
policy.AllowedFilters["escape"] = true
// Customize allowed tags
policy.AllowedTags["if"] = true
policy.AllowedTags["for"] = true
// Create a Twig engine
engine := twig.New()
// Enable sandbox mode with the policy
engine.EnableSandbox(policy)
Once sandbox mode is enabled, you can use it in two ways:
- Global sandbox mode: All templates rendered by the engine will be in sandbox mode
- Per-include sandbox mode: Only specific included templates are sandboxed
The most common use case for sandbox mode is to include untrusted templates with restricted permissions:
{# Main.twig - This is our trusted template #}
{# Normal, unrestricted content here #}
<h1>Welcome to our site</h1>
{# Include user-generated content with sandbox restrictions #}
{% include 'user_content.twig' sandboxed %}
{# More trusted content #}
<footer>Copyright 2025</footer>
When a template is included with the sandboxed
option:
- The included template runs in a sandbox with the security policy
- Any functions or filters not explicitly allowed will cause a security exception
- The main template remains unaffected by the sandbox restrictions
The DefaultSecurityPolicy
provides sensible defaults for most applications:
-
range
: For generating ranges of numbers -
cycle
: For cycling through values -
date
: For date formatting -
min
: For finding the minimum value -
max
: For finding the maximum value -
random
: For generating random values -
length
: For getting the length of strings/arrays -
merge
: For merging arrays/maps
-
escape
/e
: For HTML escaping -
raw
: For preventing escaping -
length
/count
: For counting elements -
lower
: For lowercase conversion -
upper
: For uppercase conversion -
title
: For title case conversion -
capitalize
: For capitalizing text -
trim
: For removing whitespace -
nl2br
: For converting newlines to HTML breaks -
join
: For joining array elements -
split
: For splitting strings -
default
: For providing default values -
date
: For date formatting -
abs
: For absolute values -
first
: For getting the first element -
last
: For getting the last element -
reverse
: For reversing strings/arrays -
sort
: For sorting arrays -
slice
: For slicing arrays/strings
-
if
: For conditional logic -
else
: For alternative conditional branches -
elseif
: For additional conditional branches -
for
: For loops -
set
: For variable assignment -
verbatim
: For outputting raw Twig syntax
You can add or remove items from these lists to customize the security policy for your application's needs.
When sandbox mode is enabled, the Twig engine performs security checks during expression evaluation:
- When a function is called, it checks if that function is in the
AllowedFunctions
list - When a filter is applied, it checks if that filter is in the
AllowedFilters
list - When a tag is used, it checks if that tag is in the
AllowedTags
list
If a function, filter, or tag is not allowed, a SecurityViolation
error is returned with details about the violation.
You can implement your own security policy by implementing the SecurityPolicy
interface:
type MyCustomPolicy struct {
// Your custom policy data here
}
// IsFunctionAllowed checks if a function is allowed
func (p *MyCustomPolicy) IsFunctionAllowed(function string) bool {
// Your custom logic here
return false // By default, deny all functions
}
// IsFilterAllowed checks if a filter is allowed
func (p *MyCustomPolicy) IsFilterAllowed(filter string) bool {
// Your custom logic here
return false // By default, deny all filters
}
// IsTagAllowed checks if a tag is allowed
func (p *MyCustomPolicy) IsTagAllowed(tag string) bool {
// Your custom logic here
return false // By default, deny all tags
}
// Use your custom policy
engine.EnableSandbox(&MyCustomPolicy{})
- Start restrictive: Begin with a minimal set of allowed functions and filters
- Test thoroughly: Verify that your templates work correctly with the restrictions in place
- Audit regularly: Review your allowed functions and filters for security vulnerabilities
- Include documentation: Document which functions and filters are allowed in sandboxed templates
- Use with other security measures: Combine sandbox mode with proper input validation and output escaping
Here's a practical example of using sandbox mode for a user comment system:
// Set up the engine with a security policy for comments
engine := twig.New()
policy := twig.NewDefaultSecurityPolicy()
// Only allow basic formatting functions
policy.AllowedFunctions = map[string]bool{}
policy.AllowedFilters = map[string]bool{
"escape": true,
"e": true,
"nl2br": true,
"upper": true,
"lower": true,
}
policy.AllowedTags = map[string]bool{
"if": true,
"for": true,
}
engine.EnableSandbox(policy)
// Register templates
engine.RegisterString("comment_template.twig", `
<div class="comment">
<h3>{{ commenter }}</h3>
<div class="content">{{ comment|nl2br }}</div>
{% if tags %}
<div class="tags">
{% for tag in tags %}
<span class="tag">{{ tag|e }}</span>
{% endfor %}
</div>
{% endif %}
</div>
`)
engine.RegisterString("page.twig", `
<div class="comments">
<h2>Comments</h2>
{% for comment in comments %}
{% include "comment_template.twig" with comment sandboxed %}
{% endfor %}
</div>
`)
This ensures that user-provided comment templates can only use the allowed functions, filters, and tags, preventing potentially malicious code execution.