
A drop-in fix for CVE-2023-29689 - SSTI in PyroCMS, via a custom Twig Sandbox implementation
Drop-in security fix for CVE-2023-29689 - Server-Side Template Injection leading to Remote Code Execution in PyroCMS 3.9.
PyroCMS allows admin users to edit templates stored in the database. Without sandboxing, attackers with admin access can inject malicious Twig code:
{{['id']|map('system')|join}}
This executes arbitrary system commands. The upstream maintainers consider this "working as intended" since admin users are trusted - but in multi-tenant or enterprise environments, "admin" ≠ "trusted with shell access".
This package automatically sandboxes user-editable templates while leaving legitimate theme/addon templates unrestricted. It uses Twig's SourcePolicyInterface (contributed upstream by the author of this package) to selectively apply restrictions.
composer require ysaxon/pyrocms-ssti-fix
Unfortunately, due to PyroCMS disabling autodiscovery you will need to add the serviceProvider yourself.
You can do that with
sed -i "/App\\\Providers\\\AppServiceProvider::class,/a \ YSaxon\\\PyroCmsSstiFix\\\SandboxServiceProvider::class," config/app.php
SourcePolicyInterface support)┌─────────────────────────────────────────────────────────────┐
│ Twig Render Request │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ StorageSourcePolicy │
│ │
│ Is template from storage path (database/user-editable)? │
│ │
│ YES ──────────────────► Enable Sandbox │
│ │ - Block: map, filter, reduce │
│ │ - Block: dangerous tags │
│ │ - Whitelist safe operations │
│ │
│ NO ───────────────────► No Sandbox │
│ (Theme/addon templates work │
│ normally) │
└─────────────────────────────────────────────────────────────┘
Default settings are secure and work for most installations. To customize:
php artisan vendor:publish --tag=pyrocms-ssti-fix-config
This creates config/pyrocms-ssti-fix.php:
return [
// Master switch
'enabled' => env('PYROCMS_SSTI_FIX_ENABLED', true),
// Override auto-detected storage path
'storage_path' => env('PYROCMS_SSTI_FIX_STORAGE_PATH', null),
// Customize allowed tags/filters/functions/methods/properties
'policy' => [
'tags' => [SecurityPolicyDefaults::INCLUDE_DEFAULTS],
'filters' => [SecurityPolicyDefaults::INCLUDE_DEFAULTS],
// ... see config file for full options
],
];
The default security policy blocks these dangerous features in sandboxed templates:
map - {{['cmd']|map('system')}} executes shell commandsfilter - Can call arbitrary PHP functionsreduce - Can call arbitrary PHP functionsinclude, extends, block, macro, import, embed, usesource - Reads arbitrary file contentsinclude - Includes other templatestemplate_from_string - Creates templates from stringsSafe operations remain available in sandboxed templates:
{# Variables #}
{{ entry.title }}
{{ user.name|upper }}
{# Loops and conditionals #}
{% for item in items %}
{% if item.active %}
{{ item.name }}
{% endif %}
{% endfor %}
{# Safe filters #}
{{ text|escape }}
{{ date|date('Y-m-d') }}
{{ items|length }}
{{ name|lower|trim }}
{# Safe functions #}
{{ max(a, b) }}
{{ random(['red', 'blue', 'green']) }}
If your admin templates legitimately need additional features:
// config/pyrocms-ssti-fix.php
'policy' => [
'filters' => [
SecurityPolicyDefaults::INCLUDE_DEFAULTS,
'my_custom_filter', // Add specific filter
],
'methods' => [
SecurityPolicyDefaults::INCLUDE_DEFAULTS,
'App\Models\Post' => ['getTitle', 'getSummary'],
],
],
After installation, verify the exploit is blocked:
{{['id']|map('system')|join}}Before fix: Shows output of id command (or crashes)
After fix: Shows error or [rendering failed: Filter "map" is not allowed.]
The package couldn't find Twig. This usually means:
Enable debug mode to see details:
PYROCMS_SSTI_FIX_DEBUG=true
If admin-editable templates use features that are now blocked:
The package caches all path checks and method/property lookups. In auto mode, only storage-path templates incur sandbox overhead.
SourcePolicyInterface contributor to TwigMIT License - see LICENSE file.