Skip to content

Commit 6fb043e

Browse files
authored
Merge pull request from GHSA-hv79-p62r-wg3p
fix: Auth Remote Code execution
2 parents 2323e9c + 97a075c commit 6fb043e

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

Diff for: app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php

+38-4
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
use CachetHQ\Cachet\Services\Dates\DateFactory;
2424
use Carbon\Carbon;
2525
use Illuminate\Contracts\Auth\Guard;
26+
2627
use Twig\Environment as Twig_Environment;
2728
use Twig\Loader\ArrayLoader as Twig_Loader_Array;
2829

30+
31+
2932
/**
3033
* This is the create incident command handler.
3134
*
@@ -49,6 +52,8 @@ class CreateIncidentCommandHandler
4952
*/
5053
protected $dates;
5154

55+
protected $twigConfig;
56+
5257
/**
5358
* Create a new create incident command handler instance.
5459
*
@@ -61,6 +66,8 @@ public function __construct(Guard $auth, DateFactory $dates)
6166
{
6267
$this->auth = $auth;
6368
$this->dates = $dates;
69+
70+
$this->twigConfig = config("cachet.twig");
6471
}
6572

6673
/**
@@ -131,6 +138,34 @@ public function handle(CreateIncidentCommand $command)
131138
return $incident;
132139
}
133140

141+
protected function sandboxedTwigTemplateData(String $templateData) {
142+
143+
if (!$templateData) {
144+
return "";
145+
}
146+
147+
$policy = new \Twig\Sandbox\SecurityPolicy($this->twigConfig["tags"],
148+
$this->twigConfig["filters"],
149+
$this->twigConfig["methods"],
150+
$this->twigConfig["props"],
151+
$this->twigConfig["functions"]);
152+
153+
$sandbox = new \Twig\Extension\SandboxExtension($policy);
154+
155+
$templateBasicLoader = new Twig_Loader_Array([
156+
'firstStageLoader' => $templateData
157+
]);
158+
159+
$sandBoxBasicLoader = new Twig_Loader_Array([
160+
'secondStageLoader' => '{% sandbox %}{% include "firstStageLoader" %} {% endsandbox %}'
161+
]);
162+
163+
$hardenedLoader = new \Twig\Loader\ChainLoader([$templateBasicLoader, $sandBoxBasicLoader]);
164+
$twig = new Twig_Environment($hardenedLoader);
165+
$twig->addExtension($sandbox);
166+
return $twig;
167+
}
168+
134169
/**
135170
* Compiles an incident template into an incident message.
136171
*
@@ -141,8 +176,7 @@ public function handle(CreateIncidentCommand $command)
141176
*/
142177
protected function parseTemplate(IncidentTemplate $template, CreateIncidentCommand $command)
143178
{
144-
$env = new Twig_Environment(new Twig_Loader_Array([]));
145-
$template = $env->createTemplate($template->template);
179+
$template = $this->sandboxedTwigTemplateData($template->template);
146180

147181
$vars = array_merge($command->template_vars, [
148182
'incident' => [
@@ -157,7 +191,7 @@ protected function parseTemplate(IncidentTemplate $template, CreateIncidentComma
157191
'component_status' => $command->component_status,
158192
],
159193
]);
160-
161-
return $template->render($vars);
194+
195+
return $template->render('secondStageLoader', $vars);
162196
}
163197
}

Diff for: app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php

+32-4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ class UpdateIncidentCommandHandler
4747
*/
4848
protected $dates;
4949

50+
/**
51+
* Twig configuration array.
52+
*/
53+
protected $twigConfig;
54+
5055
/**
5156
* Create a new update incident command handler instance.
5257
*
@@ -59,6 +64,8 @@ public function __construct(Guard $auth, DateFactory $dates)
5964
{
6065
$this->auth = $auth;
6166
$this->dates = $dates;
67+
68+
$this->twigConfig = $twigConfig = config("cachet.twig");
6269
}
6370

6471
/**
@@ -140,6 +147,28 @@ protected function filter(UpdateIncidentCommand $command)
140147
});
141148
}
142149

150+
protected function sandboxedTwigTemplateData(String $templateData) {
151+
$policy = new \Twig\Sandbox\SecurityPolicy($this->twigConfig["tags"],
152+
$this->twigConfig["filters"],
153+
$this->twigConfig["methods"],
154+
$this->twigConfig["props"],
155+
$this->twigConfig["functions"]);
156+
$sandbox = new \Twig\Extension\SandboxExtension($policy);
157+
158+
$templateBasicLoader = new \Twig\Loader\ArrayLoader([
159+
'firstStageLoader' => $templateData
160+
]);
161+
162+
$sandBoxBasicLoader = new \Twig\Loader\ArrayLoader([
163+
'secondStageLoader' => '{% sandbox %}{% include "firstStageLoader" %} {% endsandbox %}'
164+
]);
165+
166+
$hardenedLoader = new \Twig\Loader\ChainLoader([$templateBasicLoader, $sandBoxBasicLoader]);
167+
$twig = new \Twig\Environment($hardenedLoader);
168+
$twig->addExtension($sandbox);
169+
return $twig;
170+
}
171+
143172
/**
144173
* Compiles an incident template into an incident message.
145174
*
@@ -150,8 +179,7 @@ protected function filter(UpdateIncidentCommand $command)
150179
*/
151180
protected function parseTemplate(IncidentTemplate $template, UpdateIncidentCommand $command)
152181
{
153-
$env = new Twig_Environment(new Twig_Loader_Array([]));
154-
$template = $env->createTemplate($template->template);
182+
$template = $this->sandboxedTwigTemplateData($template->template);
155183

156184
$vars = array_merge($command->template_vars, [
157185
'incident' => [
@@ -166,7 +194,7 @@ protected function parseTemplate(IncidentTemplate $template, UpdateIncidentComma
166194
'component_status' => $command->component_status,
167195
],
168196
]);
169-
170-
return $template->render($vars);
197+
198+
return $template->render('secondStageLoader', $vars);
171199
}
172200
}

Diff for: composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"nexmo/client": "^1.5",
5656
"pragmarx/google2fa": "^5.0",
5757
"predis/predis": "^1.1",
58-
"twig/twig": "^2.6"
58+
"twig/twig": "^3.0"
5959
},
6060
"require-dev": {
6161
"ext-sqlite3": "*",

Diff for: config/cachet.php

+18
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,22 @@
4646

4747
'beacon' => env('CACHET_BEACON', true),
4848

49+
50+
/*
51+
|--------------------------------------------------------------------------
52+
| Templates configurations
53+
|--------------------------------------------------------------------------
54+
|
55+
| Security fix: now user can provide information which will be included to the Twig sandbox settings
56+
|
57+
| Default: Described below
58+
|
59+
*/
60+
'twig' => [
61+
'methods' => [],
62+
'functions' => [],
63+
'filters' => ['escape'],
64+
'tags' => ['if'],
65+
'props' => [],
66+
]
4967
];

0 commit comments

Comments
 (0)