Skip to content

Sandbox Mode

semihalev edited this page Mar 11, 2025 · 1 revision

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.

Basic Concept

The sandbox mode in Twig works by:

  1. Defining a security policy that specifies what functions, filters, and tags are allowed
  2. Enabling the sandbox on the engine or within a specific template context
  3. Preventing templates from using any functions, filters, or tags not explicitly allowed by the policy

Setting Up Sandbox Mode

Step 1: Create a Security 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

Step 2: Enable Sandbox Mode on the Engine

// Create a Twig engine
engine := twig.New()

// Enable sandbox mode with the policy
engine.EnableSandbox(policy)

Step 3: Use Sandboxed Templates

Once sandbox mode is enabled, you can use it in two ways:

  1. Global sandbox mode: All templates rendered by the engine will be in sandbox mode
  2. Per-include sandbox mode: Only specific included templates are sandboxed

Sandboxed Includes

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:

  1. The included template runs in a sandbox with the security policy
  2. Any functions or filters not explicitly allowed will cause a security exception
  3. The main template remains unaffected by the sandbox restrictions

The Default Security Policy

The DefaultSecurityPolicy provides sensible defaults for most applications:

Allowed Functions

  • 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

Allowed Filters

  • 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

Allowed Tags

  • 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.

How Sandbox Security Works

When sandbox mode is enabled, the Twig engine performs security checks during expression evaluation:

  1. When a function is called, it checks if that function is in the AllowedFunctions list
  2. When a filter is applied, it checks if that filter is in the AllowedFilters list
  3. 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.

Implementing a Custom Security Policy

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{})

Best Practices for Sandbox Mode

  1. Start restrictive: Begin with a minimal set of allowed functions and filters
  2. Test thoroughly: Verify that your templates work correctly with the restrictions in place
  3. Audit regularly: Review your allowed functions and filters for security vulnerabilities
  4. Include documentation: Document which functions and filters are allowed in sandboxed templates
  5. Use with other security measures: Combine sandbox mode with proper input validation and output escaping

Example: User Comment System

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.

Clone this wiki locally