VYPR
Critical severityNVD Advisory· Published Oct 11, 2023· Updated Sep 17, 2024

Cachet vulnerable to Authenticated Remote Code Execution

CVE-2023-43661

Description

Cachet, the open-source status page system. Prior to the 2.4 branch, a template functionality which allows users to create templates allows them to execute any code on the server during the bad filtration and old twig version. Commit 6fb043e109d2a262ce3974e863c54e9e5f5e0587 of the 2.4 branch contains a patch for this issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
cachethq/cachetPackagist
< 2.42.4

Affected products

1

Patches

1
6fb043e109d2

Merge pull request from GHSA-hv79-p62r-wg3p

https://github.com/cachethq/cachetJames BrooksOct 11, 2023via ghsa
4 files changed · +89 9
  • app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php+38 4 modified
    @@ -23,9 +23,12 @@
     use CachetHQ\Cachet\Services\Dates\DateFactory;
     use Carbon\Carbon;
     use Illuminate\Contracts\Auth\Guard;
    +
     use Twig\Environment as Twig_Environment;
     use Twig\Loader\ArrayLoader as Twig_Loader_Array;
     
    +
    +
     /**
      * This is the create incident command handler.
      *
    @@ -49,6 +52,8 @@ class CreateIncidentCommandHandler
          */
         protected $dates;
     
    +    protected $twigConfig;
    +
         /**
          * Create a new create incident command handler instance.
          *
    @@ -61,6 +66,8 @@ public function __construct(Guard $auth, DateFactory $dates)
         {
             $this->auth = $auth;
             $this->dates = $dates;
    +
    +        $this->twigConfig = config("cachet.twig");
         }
     
         /**
    @@ -131,6 +138,34 @@ public function handle(CreateIncidentCommand $command)
             return $incident;
         }
     
    +    protected function sandboxedTwigTemplateData(String $templateData) {
    +
    +        if (!$templateData) {
    +            return "";
    +        }
    +
    +        $policy = new \Twig\Sandbox\SecurityPolicy($this->twigConfig["tags"], 
    +        $this->twigConfig["filters"],
    +        $this->twigConfig["methods"],
    +        $this->twigConfig["props"], 
    +        $this->twigConfig["functions"]);
    +
    +        $sandbox = new \Twig\Extension\SandboxExtension($policy);
    +
    +        $templateBasicLoader = new Twig_Loader_Array([
    +            'firstStageLoader' => $templateData
    +        ]);
    +
    +        $sandBoxBasicLoader = new Twig_Loader_Array([
    +            'secondStageLoader' => '{% sandbox %}{% include "firstStageLoader" %} {% endsandbox %}'
    +        ]);
    +
    +        $hardenedLoader = new \Twig\Loader\ChainLoader([$templateBasicLoader, $sandBoxBasicLoader]);
    +        $twig = new Twig_Environment($hardenedLoader);
    +        $twig->addExtension($sandbox);
    +        return $twig;
    +    }
    +
         /**
          * Compiles an incident template into an incident message.
          *
    @@ -141,8 +176,7 @@ public function handle(CreateIncidentCommand $command)
          */
         protected function parseTemplate(IncidentTemplate $template, CreateIncidentCommand $command)
         {
    -        $env = new Twig_Environment(new Twig_Loader_Array([]));
    -        $template = $env->createTemplate($template->template);
    +        $template = $this->sandboxedTwigTemplateData($template->template);
     
             $vars = array_merge($command->template_vars, [
                 'incident' => [
    @@ -157,7 +191,7 @@ protected function parseTemplate(IncidentTemplate $template, CreateIncidentComma
                     'component_status' => $command->component_status,
                 ],
             ]);
    -
    -        return $template->render($vars);
    +        
    +        return $template->render('secondStageLoader', $vars);
         }
     }
    
  • app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php+32 4 modified
    @@ -47,6 +47,11 @@ class UpdateIncidentCommandHandler
          */
         protected $dates;
     
    +    /**
    +     * Twig configuration array.
    +     */
    +    protected $twigConfig;
    +
         /**
          * Create a new update incident command handler instance.
          *
    @@ -59,6 +64,8 @@ public function __construct(Guard $auth, DateFactory $dates)
         {
             $this->auth = $auth;
             $this->dates = $dates;
    +
    +        $this->twigConfig = $twigConfig = config("cachet.twig");
         }
     
         /**
    @@ -140,6 +147,28 @@ protected function filter(UpdateIncidentCommand $command)
             });
         }
     
    +    protected function sandboxedTwigTemplateData(String $templateData) {
    +        $policy = new \Twig\Sandbox\SecurityPolicy($this->twigConfig["tags"], 
    +        $this->twigConfig["filters"],
    +        $this->twigConfig["methods"],
    +        $this->twigConfig["props"], 
    +        $this->twigConfig["functions"]);
    +        $sandbox = new \Twig\Extension\SandboxExtension($policy);
    +
    +        $templateBasicLoader = new \Twig\Loader\ArrayLoader([
    +            'firstStageLoader' => $templateData
    +        ]);
    +
    +        $sandBoxBasicLoader = new \Twig\Loader\ArrayLoader([
    +            'secondStageLoader' => '{% sandbox %}{% include "firstStageLoader" %} {% endsandbox %}'
    +        ]);
    +
    +        $hardenedLoader = new \Twig\Loader\ChainLoader([$templateBasicLoader, $sandBoxBasicLoader]);
    +        $twig = new \Twig\Environment($hardenedLoader);
    +        $twig->addExtension($sandbox);
    +        return $twig;
    +    }
    +
         /**
          * Compiles an incident template into an incident message.
          *
    @@ -150,8 +179,7 @@ protected function filter(UpdateIncidentCommand $command)
          */
         protected function parseTemplate(IncidentTemplate $template, UpdateIncidentCommand $command)
         {
    -        $env = new Twig_Environment(new Twig_Loader_Array([]));
    -        $template = $env->createTemplate($template->template);
    +        $template = $this->sandboxedTwigTemplateData($template->template);
     
             $vars = array_merge($command->template_vars, [
                 'incident' => [
    @@ -166,7 +194,7 @@ protected function parseTemplate(IncidentTemplate $template, UpdateIncidentComma
                     'component_status' => $command->component_status,
                 ],
             ]);
    -
    -        return $template->render($vars);
    +        
    +        return $template->render('secondStageLoader', $vars);
         }
     }
    
  • composer.json+1 1 modified
    @@ -55,7 +55,7 @@
             "nexmo/client": "^1.5",
             "pragmarx/google2fa": "^5.0",
             "predis/predis": "^1.1",
    -        "twig/twig": "^2.6"
    +        "twig/twig": "^3.0"
         },
         "require-dev": {
             "ext-sqlite3": "*",
    
  • config/cachet.php+18 0 modified
    @@ -46,4 +46,22 @@
     
         'beacon' => env('CACHET_BEACON', true),
     
    +
    +    /*
    +    |--------------------------------------------------------------------------
    +    | Templates configurations
    +    |--------------------------------------------------------------------------
    +    |
    +    | Security fix: now user can provide information which will be included to the Twig sandbox settings
    +    |
    +    | Default: Described below
    +    |
    +    */
    +    'twig' => [
    +        'methods' => [], 
    +        'functions' => [],
    +        'filters' => ['escape'],
    +        'tags' => ['if'],
    +        'props' => [],
    +    ]
     ];
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.