CVE-2021-41260: Cross-Site Request Forgery (CSRF) (CWE-352)
value: Galette is a membership management web application built for non profit organizations and released under GPLv3. Versions prior to 0.9.6 do not check for Cross Site Request Forgery attacks. All users are advised to upgrade to 0.9.6 as soon as possible. There are no known workarounds for this issue.
CWE description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
CVSS v3 base score: 8.8
Published: 2021-12-16T18:15Z
Repository: https://github.com/galette/galette
Language: Other
Files changed: galette/composer.json, galette/composer.lock, galette/includes/dependencies.php, galette/includes/main.inc.php, galette/lib/Galette/Middleware/SmartyCsrf.php, galette/templates/default/admintools.tpl, galette/templates/default/advanced_search.tpl, galette/templates/default/ajouter_contribution.tpl, galette/templates/default/ajouter_transaction.tpl, galette/templates/default/attendance_sheet_details.tpl, galette/templates/default/change_passwd.tpl, galette/templates/default/common_scripts.tpl, galette/templates/default/config_fields.tpl, galette/templates/default/config_lists.tpl, galette/templates/default/confirm_removal.tpl, galette/templates/default/directlink.tpl, galette/templates/default/edit_paymenttype.tpl, galette/templates/default/edit_title.tpl, galette/templates/default/editer_champ.tpl, galette/templates/default/editer_intitule.tpl, galette/templates/default/export.tpl, galette/templates/default/forms_types/csrf.tpl, galette/templates/default/gestion_adherents.tpl, galette/templates/default/gestion_contributions.tpl, galette/templates/default/gestion_intitules.tpl, galette/templates/default/gestion_mailings.tpl, galette/templates/default/gestion_paymentstypes.tpl, galette/templates/default/gestion_pdf_content.tpl, galette/templates/default/gestion_textes.tpl, galette/templates/default/gestion_titres.tpl, galette/templates/default/gestion_transactions.tpl, galette/templates/default/group.tpl, galette/templates/default/history.tpl, galette/templates/default/import.tpl, galette/templates/default/import_model.tpl, galette/templates/default/index.tpl, galette/templates/default/liste_membres.tpl, galette/templates/default/lostpasswd.tpl, galette/templates/default/mailing_adherents.tpl, galette/templates/default/mass_add_contribution.tpl, galette/templates/default/mass_change_members.tpl, galette/templates/default/mass_choose_type.tpl, galette/templates/default/member.tpl, galette/templates/default/plugin_initdb.tpl, galette/templates/default/preferences.tpl, galette/templates/default/reminder.tpl, galette/templates/default/saved_searches.tpl, galette/templates/default/traduire_libelles.tpl, galette/templates/default/trombinoscope.tpl
Commit date: 2021-11-09 22:54:50 +0100
Commit message: Add CSRF Middleware

Add csrf inputs on all forms
Use an exception rather than default blank page
Add CSRF check on ajax post requests
Make CSRF token persistent to ease with ajax calls

Diff: diff --git a/galette/composer.json b/galette/composer.json
index f33d8d005..b9d724476 100644
--- a/galette/composer.json
+++ b/galette/composer.json
@@ -48,11 +48,12 @@
         "psr/container": "^1.0",
         "php-di/slim-bridge": "2.0.0",
         "doctrine/annotations": "^1.8",
         "laminas/laminas-servicemanager": "3.7",
         "symfony/polyfill-php80": "^1.23",
-        "ezyang/htmlpurifier": "^4.13"
+        "ezyang/htmlpurifier": "^4.13",
+        "slim/csrf": "0.8.3"
     },
     "require-dev": {
         "atoum/atoum": "dev-master",
         "galette/smarty-xgettext": "^1.2",
         "squizlabs/php_codesniffer": "^3.5"
diff --git a/galette/composer.lock b/galette/composer.lock
index 79e9819a4..511eb07ec 100644
--- a/galette/composer.lock
+++ b/galette/composer.lock
@@ -2,11 +2,11 @@
     "_readme": [
         "This file locks the dependencies of your project to a known state",
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "47d56d47701d9038105bd93cf3b44a02",
+    "content-hash": "be12f467246cd29921b64f8f84dc17a8",
     "packages": [
         {
             "name": "akrabat/rka-slim-session-middleware",
             "version": "2.0.0",
             "source": {
@@ -2211,10 +2211,60 @@
                 "issues": "https://github.com/opis/closure/issues",
                 "source": "https://github.com/opis/closure/tree/3.6.2"
             },
             "time": "2021-04-09T13:42:10+00:00"
         },
+        {
+            "name": "paragonie/random_compat",
+            "version": "v9.99.100",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/random_compat.git",
+                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
+                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">= 7"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*|5.*",
+                "vimeo/psalm": "^1"
+            },
+            "suggest": {
+                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+            },
+            "type": "library",
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com"
+                }
+            ],
+            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+            "keywords": [
+                "csprng",
+                "polyfill",
+                "pseudorandom",
+                "random"
+            ],
+            "support": {
+                "email": "info@paragonie.com",
+                "issues": "https://github.com/paragonie/random_compat/issues",
+                "source": "https://github.com/paragonie/random_compat"
+            },
+            "time": "2020-10-15T08:29:30+00:00"
+        },
         {
             "name": "php-di/invoker",
             "version": "2.3.2",
             "source": {
                 "type": "git",
@@ -2806,10 +2856,64 @@
             "support": {
                 "source": "https://github.com/php-fig/simple-cache/tree/master"
             },
             "time": "2017-10-23T01:57:42+00:00"
         },
+        {
+            "name": "slim/csrf",
+            "version": "0.8.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/slimphp/Slim-Csrf.git",
+                "reference": "5f2bcf5d89adf86dc0455a32bea84d912ab466a7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/slimphp/Slim-Csrf/zipball/5f2bcf5d89adf86dc0455a32bea84d912ab466a7",
+                "reference": "5f2bcf5d89adf86dc0455a32bea84d912ab466a7",
+                "shasum": ""
+            },
+            "require": {
+                "paragonie/random_compat": "^1.1|^2.0|^9.99",
+                "php": ">=5.5.0",
+                "psr/http-message": "^1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.0",
+                "slim/slim": "~3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Slim\\Csrf\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Josh Lockhart",
+                    "email": "hello@joshlockhart.com",
+                    "homepage": "http://joshlockhart.com"
+                }
+            ],
+            "description": "Slim Framework 3 CSRF protection middleware",
+            "homepage": "http://slimframework.com",
+            "keywords": [
+                "csrf",
+                "framework",
+                "middleware",
+                "slim"
+            ],
+            "support": {
+                "issues": "https://github.com/slimphp/Slim-Csrf/issues",
+                "source": "https://github.com/slimphp/Slim-Csrf/tree/master"
+            },
+            "time": "2018-08-22T16:12:18+00:00"
+        },
         {
             "name": "slim/flash",
             "version": "0.4.0",
             "source": {
                 "type": "git",
diff --git a/galette/includes/dependencies.php b/galette/includes/dependencies.php
index 8cf6b47d9..c1e86bebb 100644
--- a/galette/includes/dependencies.php
+++ b/galette/includes/dependencies.php
@@ -430,10 +430,35 @@ $container->set(
             'useListenerProvider',
             DI\get('Galette\Events\ContribListener')
         )
 );
 
+$container->set(
+    'csrf',
+    function (ContainerInterface $c) {
+        $storage = null;
+        $guard = new \Slim\Csrf\Guard(
+            'csrf',
+            $storage,
+            null,
+            200,
+            16,
+            true
+        );
+
+        $guard->setFailureCallable(function ($request, $response, $next) {
+            Analog::log(
+                'CSRF check has failed',
+                Analog::CRITICAL
+            );
+            throw new \RuntimeException(_T('Failed CSRF check!'));
+        });
+
+        return $guard;
+    }
+);
+
 //For bad existing globals can be used...
 global $translator, $i18n;
 if (
     !$container->has('galette.mode')
     || $container->get('galette.mode') !== 'INSTALL'
diff --git a/galette/includes/main.inc.php b/galette/includes/main.inc.php
index 7c1f190fc..013bbbc5c 100644
--- a/galette/includes/main.inc.php
+++ b/galette/includes/main.inc.php
@@ -90,10 +90,12 @@ $session = new \RKA\SessionMiddleware([
 $session->start();
 $app->add($session);
 
 // Set up dependencies
 require GALETTE_ROOT . '/includes/dependencies.php';
+$app->add(new \Galette\Middleware\SmartyCsrf($app->getContainer()));
+$app->add($app->getContainer()->get('csrf'));
 
 if ($needs_update) {
     $app->add(
         new \Galette\Middleware\UpdateAndMaintenance(
             $container->get('i18n'),
diff --git a/galette/lib/Galette/Middleware/SmartyCsrf.php b/galette/lib/Galette/Middleware/SmartyCsrf.php
new file mode 100644
index 000000000..2305f5028
--- /dev/null
+++ b/galette/lib/Galette/Middleware/SmartyCsrf.php
@@ -0,0 +1,96 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Galette CSRF middleware
+ *
+ * PHP version 5
+ *
+ * Copyright © 2021 The Galette Team
+ *
+ * This file is part of Galette (http://galette.tuxfamily.org).
+ *
+ * Galette is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Galette is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Galette. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Core
+ * @package   Galette
+ *
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9.6dev - 2021-11-08
+ */
+
+namespace Galette\Middleware;
+
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Message\ResponseInterface as Response;
+use Analog\Analog;
+use DI\Container;
+
+/**
+ * Galette CSRF middleware
+ *
+ * @category  Middleware
+ * @name      SmartyCsrf
+ * @package   Galette
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2020 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9.4dev - 2020-05-06
+ */
+class SmartyCsrf
+{
+    private $smarty;
+    private $csrf;
+
+    /**
+     * Constructor
+     *
+     * @param Container $container Container instance
+     */
+    public function __construct(Container $container)
+    {
+        $view = $container->get('Slim\Views\Smarty');
+        $this->smarty = $view->getSmarty();
+        $this->csrf = $container->get('csrf');
+    }
+
+    /**
+     * Middleware invokable class
+     *
+     * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
+     * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
+     * @param  callable                                 $next     Next middleware
+     *
+     * @return \Psr\Http\Message\ResponseInterface
+     */
+    public function __invoke(Request $request, Response $response, $next): Response
+    {
+        $nameKey = $this->csrf->getTokenNameKey();
+        $valueKey = $this->csrf->getTokenValueKey();
+        $name = $request->getAttribute($nameKey);
+        $value = $request->getAttribute($valueKey);
+
+        $this->smarty->assign('csrf_name_key', $nameKey);
+        $this->smarty->assign('csrf_value_key', $valueKey);
+        $this->smarty->assign('csrf_name', $name);
+        $this->smarty->assign('csrf_value', $value);
+
+        return $next($request, $response);
+    }
+}
diff --git a/galette/templates/default/admintools.tpl b/galette/templates/default/admintools.tpl
index b1a9028d6..e72ac324b 100644
--- a/galette/templates/default/admintools.tpl
+++ b/galette/templates/default/admintools.tpl
@@ -29,12 +29,13 @@
                 <span class="tip">{_T string="Fill all empty login and passwords"}</span>
                 <input type="checkbox" name="emptylogins" id="emptylogins"/>
             </p>
         </fieldset>
         <div class="button-container">
-            <button ype="submit" class="action">
+            <button type="submit" class="action">
                 <i class="fas fa-database" aria-hidden="true"></i>
                 {_T string="Go"}
             </button>
+            {include file="forms_types/csrf.tpl"}
         </div>
     </form>
 {/block}
diff --git a/galette/templates/default/advanced_search.tpl b/galette/templates/default/advanced_search.tpl
index 4c8767959..1aa267893 100644
--- a/galette/templates/default/advanced_search.tpl
+++ b/galette/templates/default/advanced_search.tpl
@@ -310,10 +310,11 @@
             </fieldset>
             <div class="center">
                 <input type="hidden" name="advanced_filtering" value="true" />
                 <input type="submit" class="inline" value="{_T string="Filter"}"/>
                 <input type="submit" name="clear_adv_filter" class="inline" value="{_T string="Clear filter"}"/>
+                {include file="forms_types/csrf.tpl"}
             </div>
         </form>
 {/block}
 
 {block name="javascripts"}
diff --git a/galette/templates/default/ajouter_contribution.tpl b/galette/templates/default/ajouter_contribution.tpl
index 69cb889be..42ee6c91f 100644
--- a/galette/templates/default/ajouter_contribution.tpl
+++ b/galette/templates/default/ajouter_contribution.tpl
@@ -182,10 +182,11 @@
             <input type="hidden" name="id_cotis" value="{$contribution->id}"/>
             <input type="hidden" name="valid" value="1"/>
             <input type="hidden" name="trans_id" value="{if $contribution->transaction neq NULL}{$contribution->transaction->id}{/if}"/>
         </div>
     {/if}
+            {include file="forms_types/csrf.tpl"}
         </form>
 {else} {* No members *}
     <div class="center" id="warningbox">
         <h3>{_T string="No member registered!"}</h3>
         <p>
diff --git a/galette/templates/default/ajouter_transaction.tpl b/galette/templates/default/ajouter_transaction.tpl
index 18a3ddde1..2f34546e4 100644
--- a/galette/templates/default/ajouter_transaction.tpl
+++ b/galette/templates/default/ajouter_transaction.tpl
@@ -44,10 +44,11 @@
             <button type="submit" name="valid" class="action">
                 <i class="fas fa-save fa-fw"></i> {_T string="Save"}
             </button>
             <input type="hidden" name="trans_id" value="{$transaction->id}"/>
             <input type="hidden" name="valid" value="1"/>
+            {include file="forms_types/csrf.tpl"}
         </div>
         <p>{_T string="NB : The mandatory fields are in"} <span class="required">{_T string="red"}</span></p>
         </form>
 
     {if $transaction->id}
diff --git a/galette/templates/default/attendance_sheet_details.tpl b/galette/templates/default/attendance_sheet_details.tpl
index a52d37ffb..bd9c2254e 100644
--- a/galette/templates/default/attendance_sheet_details.tpl
+++ b/galette/templates/default/attendance_sheet_details.tpl
@@ -29,10 +29,11 @@
                 <label for="sheet_photos" class="bline">{_T string="With photos?"}</label>
                 <input type="checkbox" name="sheet_photos" id="sheet_photos" value="1"/>
 {foreach $selection as $member}
                 <input type="hidden" name="selection[]" value="{$member}"/>
 {/foreach}
+                {include file="forms_types/csrf.tpl"}
             </p>
         </fieldset>
 {if not $ajax}
         <div class="button-container">
             <button class="active" type="submit">
diff --git a/galette/templates/default/change_passwd.tpl b/galette/templates/default/change_passwd.tpl
index c793ad2cb..187200b21 100644
--- a/galette/templates/default/change_passwd.tpl
+++ b/galette/templates/default/change_passwd.tpl
@@ -14,7 +14,8 @@
                         <td colspan="2" class="exemple">{_T string="(at least 4 characters)"}</td>
                     </tr>
                 </table>
                 <input type="submit" name="change_passwd" value="{_T string="Change my password"}"/>
                 <input type="hidden" name="hash" value="{$hash}"/>
+                {include file="forms_types/csrf.tpl"}
         </form>
 {/block}
diff --git a/galette/templates/default/common_scripts.tpl b/galette/templates/default/common_scripts.tpl
index f4e1dc719..499a7e809 100644
--- a/galette/templates/default/common_scripts.tpl
+++ b/galette/templates/default/common_scripts.tpl
@@ -1,7 +1,25 @@
         <script type="text/javascript">
+            function csrfSafeMethod(method) {
+                // these HTTP methods do not require CSRF protection
+                return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+            }
+
             $(function(){
+                $.ajaxPrefilter(function(options, originalOptions, jqXHR){
+                    if (options.type.toLowerCase() === "post") {
+                        // initialize `data` to empty string if it does not exist
+                        options.data = options.data || "";
+
+                        // add leading ampersand if `data` is non-empty
+                        options.data += options.data?"&":"";
+
+                        // add csrf
+                        options.data += encodeURIComponent("{$csrf_name_key}") + "=" + encodeURIComponent("{$csrf_name}") + "&" + encodeURIComponent("{$csrf_value_key}") + "=" + encodeURIComponent("{$csrf_value}")
+                    }
+                });
+
                 $.datepicker.setDefaults($.datepicker.regional['{$galette_lang}']);
     {if $galette_lang eq 'en'}
                 $.datepicker.setDefaults({
                     dateFormat: 'yy-mm-dd'
                 });
diff --git a/galette/templates/default/config_fields.tpl b/galette/templates/default/config_fields.tpl
index 12849db7a..dd51a0a38 100644
--- a/galette/templates/default/config_fields.tpl
+++ b/galette/templates/default/config_fields.tpl
@@ -53,10 +53,11 @@
     </div>
         <div class="button-container">
             <button type="submit" class="action">
                 <i class="fas fa-save fa-fw"></i> {_T string="Save"}
             </button>
+            {include file="forms_types/csrf.tpl"}
         </div>
     </form>
 {/block}
 
 {block name="javascripts"}
diff --git a/galette/templates/default/config_lists.tpl b/galette/templates/default/config_lists.tpl
index c36e0716e..0968a6a6b 100644
--- a/galette/templates/default/config_lists.tpl
+++ b/galette/templates/default/config_lists.tpl
@@ -55,10 +55,11 @@
         <div class="button-container">
             <button type="submit" class="action">
                 <i class="fas fa-save fa-fw"></i> {_T string="Save"}
             </button>
         </div>
+        {include file="forms_types/csrf.tpl"}
     </form>
 {/block}
 
 {block name="javascripts"}
     <script type="text/javascript">
diff --git a/galette/templates/default/confirm_removal.tpl b/galette/templates/default/confirm_removal.tpl
index fc2157b3e..1fff7ebe9 100644
--- a/galette/templates/default/confirm_removal.tpl
+++ b/galette/templates/default/confirm_removal.tpl
@@ -28,10 +28,11 @@
                     {/foreach}
                 {else}
                 <input type="hidden" name="{$key}" value="{$value}"/>
                 {/if}
             {/foreach}
+            {include file="forms_types/csrf.tpl"}
         </div>
     </form>
     </div>
 {/block}
 
diff --git a/galette/templates/default/directlink.tpl b/galette/templates/default/directlink.tpl
index de22d55c3..d4efc92bf 100644
--- a/galette/templates/default/directlink.tpl
+++ b/galette/templates/default/directlink.tpl
@@ -7,8 +7,9 @@
                         <input type="email" name="email" id="email" maxlength="50" required="required" />
                     </p>
                     <input type="submit" name="directlink" value="{_T string="Get my document"}" />
                     <input type="hidden" name="valid" value="1"/>
                     <input type="hidden" name="hash" value="{$hash}"/>
+                    {include file="forms_types/csrf.tpl"}
                 </section>
             </form>
 {/block}
diff --git a/galette/templates/default/edit_paymenttype.tpl b/galette/templates/default/edit_paymenttype.tpl
index ec40599ae..bc6dccf2c 100644
--- a/galette/templates/default/edit_paymenttype.tpl
+++ b/galette/templates/default/edit_paymenttype.tpl
@@ -14,8 +14,9 @@
             <button type="submit" class="action">
                 <i class="fas fa-save fa-fw"></i> {_T string="Save"}
             </button>
             <input type="submit" name="cancel" value="{_T string="Cancel"}"/>
             <input type="hidden" name="id" id="id" value="{$ptype->id}"/>
+            {include file="forms_types/csrf.tpl"}
         </div>
      </form>
 {/block}
diff --git a/galette/templates/default/edit_title.tpl b/galette/templates/default/edit_title.tpl
index 157d8a7eb..178b05c06 100644
--- a/galette/templates/default/edit_title.tpl
+++ b/galette/templates/default/edit_title.tpl
@@ -18,8 +18,9 @@
                 <button type="submit" class="action">
                     <i class="fas fa-save fa-fw"></i> {_T string="Save"}
                 </button>
                 <input type="submit" name="cancel" value="{_T string="Cancel"}"/>
                 <input type="hidden" name="id" id="id" value="{$title->id}"/>
+                {include file="forms_types/csrf.tpl"}
             </div>
      </form>
 {/block}
diff --git a/galette/templates/default/editer_champ.tpl b/galette/templates/default/editer_champ.tpl
index 29e7a029f..41fbeb54b 100644
--- a/galette/templates/default/editer_champ.tpl
+++ b/galette/templates/default/editer_champ.tpl
@@ -69,10 +69,11 @@
         </fieldset>
             <div class="button-container">
                 <button type="submit" class="action">
                     <i class="fas fa-save fa-fw"></i> {_T string="Save"}
                 </button>
+                {include file="forms_types/csrf.tpl"}
             </div>
 
      </form>
 {elseif $action == "add"}
     <form action="{path_for name="doAddDynamicField" data=["form_name" => $form_name]}" method="post" enctype="multipart/form-data" title="{_T string="New dynamic field"}">
diff --git a/galette/templates/default/editer_intitule.tpl b/galette/templates/default/editer_intitule.tpl
index 18a4ad1e2..ef23748cf 100644
--- a/galette/templates/default/editer_intitule.tpl
+++ b/galette/templates/default/editer_intitule.tpl
@@ -37,9 +37,10 @@
     <div class="button-container">
         <button type="submit" class="action">
             <i class="fas fa-save"></i>
             {_T string="Save"}
         </button>
+        {include file="forms_types/csrf.tpl"}
     </div>
     </div>
 </form>
 {/block}
diff --git a/galette/templates/default/export.tpl b/galette/templates/default/export.tpl
index 43719b7ae..5d9e14fed 100644
--- a/galette/templates/default/export.tpl
+++ b/galette/templates/default/export.tpl
@@ -122,10 +122,11 @@
                         </tbody>
                     </table>
                 </fieldset>
             <div class="button-container">
                 <input type="submit" name="valid" value="{_T string="Continue"}"/>
+                {include file="forms_types/csrf.tpl"}
             </div>
         </form>
 {/block}
 
 {block name="javascripts"}
diff --git a/galette/templates/default/forms_types/csrf.tpl b/galette/templates/default/forms_types/csrf.tpl
new file mode 100644
index 000000000..c9744bdcd
--- /dev/null
+++ b/galette/templates/default/forms_types/csrf.tpl
@@ -0,0 +1,2 @@
+<input type="hidden" name="{$csrf_name_key}" value="{$csrf_name}"/>
+<input type="hidden" name="{$csrf_value_key}" value="{$csrf_value}"/>
\ No newline at end of file
diff --git a/galette/templates/default/gestion_adherents.tpl b/galette/templates/default/gestion_adherents.tpl
index fc8ae326b..7d67ccc13 100644
--- a/galette/templates/default/gestion_adherents.tpl
+++ b/galette/templates/default/gestion_adherents.tpl
@@ -102,10 +102,11 @@ We have to use a template file, so Smarty will do its work (like replacing varia
                 <br/>
                 <a href="#" id="showhideqry">{_T string="Show/hide query"}</a>
             </p>
             <pre id="sql_qry" class="hidden">{$filters->query}</pre>
 {/if}
+            {include file="forms_types/csrf.tpl"}
         </div>
         <div class="infoline">
             {_T string="%count member" plural="%count members" count=$nb_members pattern="/%count/" replace=$nb_members}
             <div class="fright">
                 <label for="nbshow">{_T string="Records per page:"}</label>
@@ -352,11 +353,11 @@ We have to use a template file, so Smarty will do its work (like replacing varia
             {include file=$action module_id=$plugin_name|replace:'batch_action_':''}
         {/foreach}
     {/if}
         </ul>
 {/if}
-
+            {include file="forms_types/csrf.tpl"}
         </form>
 {if $nb_members != 0}
         <div id="legende" title="{_T string="Legend"}">
             <h1>{_T string="Legend"}</h1>
             <table>
@@ -509,10 +510,11 @@ We have to use a template file, so Smarty will do its work (like replacing varia
                         _attendance_sheet_details();
                         return false;
                     }
 
                     if (this.id == 'masscontributions') {
+                        event.preventDefault();
                         $.ajax({
                             url: '{path_for name="batch-memberslist"}',
                             type: "POST",
                             data: {
                                 ajax: true,
diff --git a/galette/templates/default/gestion_contributions.tpl b/galette/templates/default/gestion_contributions.tpl
index 8e34f2a96..0064f29fb 100644
--- a/galette/templates/default/gestion_contributions.tpl
+++ b/galette/templates/default/gestion_contributions.tpl
@@ -59,10 +59,11 @@
                 <select name="nbshow" id="nbshow">
                     {html_options options=$nbshow_options selected=$numrows}
                 </select>
                 <noscript> <span><input type="submit" value="{_T string="Change"}" /></span></noscript>
             </div>
+            {include file="forms_types/csrf.tpl"}
         </div>
         </form>
         <form action="{path_for name="batch-contributionslist" data=["type" => "contributions"]}" method="post" id="listform">
         <table class="listing">
             <thead>
@@ -305,10 +306,11 @@
             </li>
             <li>
                 <button type="submit" id="csv" name="csv">
                     <i class="fas fa-file-csv fa-fw"></i> {_T string="Export as CSV"}
                 </button>
+                {include file="forms_types/csrf.tpl"}
             </li>
         </ul>
     {/if}
 {/if}
         </form>
diff --git a/galette/templates/default/gestion_intitules.tpl b/galette/templates/default/gestion_intitules.tpl
index 4b99a7885..17be135f7 100644
--- a/galette/templates/default/gestion_intitules.tpl
+++ b/galette/templates/default/gestion_intitules.tpl
@@ -2,10 +2,11 @@
 
 {block name="content"}
 <form action="{path_for name="doAddEntitled" data=["class" => $url_class]}" method="post" class="tabbed">
 <div id="intitules_tabs">
     {include file="gestion_intitule_content.tpl"}
+    {include file="forms_types/csrf.tpl"}
 </div>
 </form>
 {/block}
 
 {block name="javascripts"}
diff --git a/galette/templates/default/gestion_mailings.tpl b/galette/templates/default/gestion_mailings.tpl
index 74ac867ec..0ea381260 100644
--- a/galette/templates/default/gestion_mailings.tpl
+++ b/galette/templates/default/gestion_mailings.tpl
@@ -43,10 +43,11 @@
                     <label for="nbshow">{_T string="Records per page:"}</label>
                     <select name="nbshow" id="nbshow">
                         {html_options options=$nbshow_options selected=$numrows}
                     </select>
                     <noscript> <span><input type="submit" value="{_T string="Change"}" /></span></noscript>
+                    {include file="forms_types/csrf.tpl"}
                 </td>
             </tr>
         </table>
     </form>
 
diff --git a/galette/templates/default/gestion_paymentstypes.tpl b/galette/templates/default/gestion_paymentstypes.tpl
index 3c8821696..cbab043a3 100644
--- a/galette/templates/default/gestion_paymentstypes.tpl
+++ b/galette/templates/default/gestion_paymentstypes.tpl
@@ -75,10 +75,11 @@
                             </td>
                         </tr>
             {/foreach}
                     </tbody>
                 </table>
+            {include file="forms_types/csrf.tpl"}
         </form>
 {/block}
 
 {block name="javascripts"}
         <script type="text/javascript">
diff --git a/galette/templates/default/gestion_pdf_content.tpl b/galette/templates/default/gestion_pdf_content.tpl
index d8956fcc9..f13b6bed7 100644
--- a/galette/templates/default/gestion_pdf_content.tpl
+++ b/galette/templates/default/gestion_pdf_content.tpl
@@ -48,8 +48,9 @@
                 <input type="hidden" name="model_type" value="{$model->type}"/>
 {/if}
                 <button type="submit" class="action">
                     <i class="fas fa-save fa-fw"></i> {_T string="Save"}
                 </button>
+                {include file="forms_types/csrf.tpl"}
             </div>
         </form>
         {include file="replacements_legend.tpl" legends=$model->getLegend() cur_ref=$model->id}
\ No newline at end of file
diff --git a/galette/templates/default/gestion_textes.tpl b/galette/templates/default/gestion_textes.tpl
index 1fdde520c..b1a8ea8d8 100644
--- a/galette/templates/default/gestion_textes.tpl
+++ b/galette/templates/default/gestion_textes.tpl
@@ -16,10 +16,11 @@
                     {foreach item=ref from=$reflist}
                         <option value="{$ref.tref}" {if $cur_ref eq $ref.tref}selected="selected"{/if} >{$ref.tcomment}</option>
                     {/foreach}
                 </select>
                 <noscript> <span><input type="submit" value="{_T string="Change"}" /></span></noscript>
+            {include file="forms_types/csrf.tpl"}
         </form>
         </div>
 
         <form action="{path_for name="texts"}" method="post" enctype="multipart/form-data">
         <div class="bigtable">
@@ -40,10 +41,11 @@
             <input type="hidden" name="cur_ref" value="{$cur_ref}"/>
             <input type="hidden" name="valid" id="valid" value="1"/>
             <button type="submit" class="action">
                 <i class="fas fa-save fa-fw"></i> {_T string="Save"}
             </button>
+            {include file="forms_types/csrf.tpl"}
         </div>
         </form>
         {include file="replacements_legend.tpl" legends=$texts->getLegend() cur_ref=$cur_ref}
 {/block}
 
diff --git a/galette/templates/default/gestion_titres.tpl b/galette/templates/default/gestion_titres.tpl
index 762e32dea..dca09bf6a 100644
--- a/galette/templates/default/gestion_titres.tpl
+++ b/galette/templates/default/gestion_titres.tpl
@@ -72,10 +72,11 @@
                             </td>
                         </tr>
             {/foreach}
                     </tbody>
                 </table>
+            {include file="forms_types/csrf.tpl"}
         </form>
 {/block}
 
 {block name="javascripts"}
         <script type="text/javascript">
diff --git a/galette/templates/default/gestion_transactions.tpl b/galette/templates/default/gestion_transactions.tpl
index 69273777e..f4e046f8c 100644
--- a/galette/templates/default/gestion_transactions.tpl
+++ b/galette/templates/default/gestion_transactions.tpl
@@ -35,10 +35,11 @@
                     <label for="nbshow">{_T string="Records per page:"}</label>
                     <select name="nbshow" id="nbshow">
                         {html_options options=$nbshow_options selected=$numrows}
                     </select>
                     <noscript> <span><input type="submit" value="{_T string="Change"}" /></span></noscript>
+                    {include file="forms_types/csrf.tpl"}
                 </td>
             </tr>
         </table>
         </form>
         <table class="listing">
diff --git a/galette/templates/default/group.tpl b/galette/templates/default/group.tpl
index a918089ca..522692f50 100644
--- a/galette/templates/default/group.tpl
+++ b/galette/templates/default/group.tpl
@@ -84,10 +84,11 @@
             <a href="{path_for name="pdf_groups" data=["id" => $group->getId()]}" class="button tooltip" title="{_T string="Current group (and attached people) as PDF"}">
                 <i class="fas fa-file-pdf" aria-hidden="true"></i>
                 {_T string="Group PDF"}
             </a>
             <input type="hidden" name="id_group" id="id_group" value="{$group->getId()}"/>
+            {include file="forms_types/csrf.tpl"}
         </div>
         <p>{_T string="NB : The mandatory fields are in"} <span class="required">{_T string="red"}</span></p>
         </form>
 <script type="text/javascript">
     $(function() {
diff --git a/galette/templates/default/history.tpl b/galette/templates/default/history.tpl
index f97961dc7..9fcc75c2b 100644
--- a/galette/templates/default/history.tpl
+++ b/galette/templates/default/history.tpl
@@ -48,10 +48,11 @@
                 <label for="nbshow">{_T string="Records per page:"}</label>
                 <select name="nbshow" id="nbshow">
                     {html_options options=$nbshow_options selected=$numrows}
                 </select>
                 <noscript> <span><input type="submit" value="{_T string="Change"}" /></span></noscript>
+                {include file="forms_types/csrf.tpl"}
             </div>
         </div>
     </form>
 
         <table class="listing">
diff --git a/galette/templates/default/import.tpl b/galette/templates/default/import.tpl
index 3f9f3d351..7d473e698 100644
--- a/galette/templates/default/import.tpl
+++ b/galette/templates/default/import.tpl
@@ -59,10 +59,11 @@
                         <input type="checkbox" name="dryrun" id="dryrun" value="1"{if isset($dryrun) and $dryrun eq true} checked="checked"{/if}/>
                         <button type="submit" name="import" id="import">
                             <i class="fas fa-file-import"></i>
                             {_T string="Import"}
                         </button>
+                        {include file="forms_types/csrf.tpl"}
                     </div>
 {else}
                     <p>{_T string="No import file actually exists."}<br/>{_T string="Use upload form below to send a new file on server, or copy it directly in the imports directory."}</p>
 {/if}
                 </div>
@@ -79,10 +80,11 @@
                     <div class="button-container">
                         <button type="submit" name="upload" id="upload">
                             <i class="fas fa-upload" aria-hidd="true"></i>
                             {_T string="Upload file"}
                         </button>
+                        {include file="forms_types/csrf.tpl"}
                     </div>
                 </div>
             </fieldset>
         </form>
 {/block}
diff --git a/galette/templates/default/import_model.tpl b/galette/templates/default/import_model.tpl
index 29313db48..f0b23358d 100644
--- a/galette/templates/default/import_model.tpl
+++ b/galette/templates/default/import_model.tpl
@@ -73,10 +73,11 @@
         <div class="button-container">
             <button type="submit" name="upload" class="action">
                 <i class="fas fa-save" aria-hidden="true"></i>
                 {_T string="Store new model"}
             </button>
+            {include file="forms_types/csrf.tpl"}
         </div>
         </form>
     </div>
 </div>
 <p class="center">
diff --git a/galette/templates/default/index.tpl b/galette/templates/default/index.tpl
index c032dfe89..710a8d986 100644
--- a/galette/templates/default/index.tpl
+++ b/galette/templates/default/index.tpl
@@ -15,8 +15,9 @@
                             <td><input type="password" name="password" id="password"/></td>
                         </tr>
                     </table>
                     <input type="submit" value="{_T string="Login"}" />
                     <input type="hidden" name="ident" value="1" />
+                    {include file="forms_types/csrf.tpl"}
                 </section>
                 </form>
 {/block}
diff --git a/galette/templates/default/liste_membres.tpl b/galette/templates/default/liste_membres.tpl
index e70c4cbdf..d8d9cf4cc 100644
--- a/galette/templates/default/liste_membres.tpl
+++ b/galette/templates/default/liste_membres.tpl
@@ -10,10 +10,11 @@
                     <label for="nbshow">{_T string="Records per page:"}</label>
                     <select name="nbshow" id="nbshow">
                         {html_options options=$nbshow_options selected=$numrows}
                     </select>
                     <noscript> <span><input type="submit" value="{_T string="Change"}" /></span></noscript>
+                    {include file="forms_types/csrf.tpl"}
                 </td>
             </tr>
         </table>
         </form>
         <table class="listing">
diff --git a/galette/templates/default/lostpasswd.tpl b/galette/templates/default/lostpasswd.tpl
index ccb455fb3..e137d23fe 100644
--- a/galette/templates/default/lostpasswd.tpl
+++ b/galette/templates/default/lostpasswd.tpl
@@ -6,8 +6,9 @@
                         <label for="login" class="">{_T string="Username or email:"}</label>
                         <input type="text" name="login" id="login" maxlength="50" />
                     </p>
                     <input type="submit" name="lostpasswd" value="{_T string="Recover password"}" />
                     <input type="hidden" name="valid" value="1"/>
+                    {include file="forms_types/csrf.tpl"}
                 </section>
                 </form>
 {/block}
diff --git a/galette/templates/default/mailing_adherents.tpl b/galette/templates/default/mailing_adherents.tpl
index d787c9a72..e46056649 100644
--- a/galette/templates/default/mailing_adherents.tpl
+++ b/galette/templates/default/mailing_adherents.tpl
@@ -142,11 +142,11 @@
                         <input type="hidden" name="mailing_objet" value="{$mailing->subject}"/>
                         <input type="hidden" name="mailing_corps" value="{if $mailing->message}{$mailing->message|escape}{/if}"/>
                     </p>
                 </div>
         {/if}
-
+            {include file="forms_types/csrf.tpl"}
             </section>
         </div>
         </form>
 {/if}
 {/block}
diff --git a/galette/templates/default/mass_add_contribution.tpl b/galette/templates/default/mass_add_contribution.tpl
index 6e053518b..88c6be471 100644
--- a/galette/templates/default/mass_add_contribution.tpl
+++ b/galette/templates/default/mass_add_contribution.tpl
@@ -16,9 +16,10 @@
                     {/foreach}
                 {else}
                 <input type="hidden" name="{$key}" value="{$value}"/>
                 {/if}
             {/foreach}
+            {include file="forms_types/csrf.tpl"}
         </div>
     </form>
     </div>
 {/block}
diff --git a/galette/templates/default/mass_change_members.tpl b/galette/templates/default/mass_change_members.tpl
index e4edf532f..ebde247bb 100644
--- a/galette/templates/default/mass_change_members.tpl
+++ b/galette/templates/default/mass_change_members.tpl
@@ -57,9 +57,10 @@
                     {/foreach}
                 {else}
                 <input type="hidden" name="{$key}" value="{$value}"/>
                 {/if}
             {/foreach}
+            {include file="forms_types/csrf.tpl"}
         </div>
     </form>
     </div>
 {/block}
diff --git a/galette/templates/default/mass_choose_type.tpl b/galette/templates/default/mass_choose_type.tpl
index 89b131e86..3404103cc 100644
--- a/galette/templates/default/mass_choose_type.tpl
+++ b/galette/templates/default/mass_choose_type.tpl
@@ -25,9 +25,10 @@
                     {/foreach}
                 {else}
                 <input type="hidden" name="{$key}" value="{$value}"/>
                 {/if}
             {/foreach}
+            {include file="forms_types/csrf.tpl"}
         </div>
     </form>
     </div>
 {/block}
diff --git a/galette/templates/default/member.tpl b/galette/templates/default/member.tpl
index ed5e07883..f65ab1499 100644
--- a/galette/templates/default/member.tpl
+++ b/galette/templates/default/member.tpl
@@ -126,11 +126,11 @@
                             value=$value
                         }
                     {/if}
                 {/if}
             {/foreach}
-
+            {include file="forms_types/csrf.tpl"}
             <a href="#" id="back2top">{_T string="Back to top"}</a>
         </div>
         </form>
 {/block}
 
diff --git a/galette/templates/default/plugin_initdb.tpl b/galette/templates/default/plugin_initdb.tpl
index c09d3cd83..f4e980316 100644
--- a/galette/templates/default/plugin_initdb.tpl
+++ b/galette/templates/default/plugin_initdb.tpl
@@ -120,10 +120,11 @@
             <a href="#" class="button" id="btnback">{_T string="Close"}</a>
     {else}
             <a href="{path_for name="plugins"}" class="button" id="btnback"><i class="fas fa-backward"></i> {_T string="Back to plugins managment page"}</a>
     {/if}
 {/if}
+            {include file="forms_types/csrf.tpl"}
         </p>
     </form>
     </div>
     <footer>
         <p>{_T string="Steps:"}</p>
diff --git a/galette/templates/default/preferences.tpl b/galette/templates/default/preferences.tpl
index 2d7da82d5..aea003fd8 100644
--- a/galette/templates/default/preferences.tpl
+++ b/galette/templates/default/preferences.tpl
@@ -587,10 +587,11 @@
             <button type="submit" class="action">
                 <i class="fas fa-save fa-fw"></i> {_T string="Save"}
             </button>
         </div>
         <p>{_T string="NB : The mandatory fields are in"} <span class="required">{_T string="red"}</span></p>
+        {include file="forms_types/csrf.tpl"}
         </form>
 
         {include file="telemetry.tpl" part="dialog"}
         {include file="replacements_legend.tpl" legends=$preferences->getLegend() cur_ref='prefs'}
 {/block}
diff --git a/galette/templates/default/reminder.tpl b/galette/templates/default/reminder.tpl
index 11eeae377..f6237ecaa 100644
--- a/galette/templates/default/reminder.tpl
+++ b/galette/templates/default/reminder.tpl
@@ -30,10 +30,11 @@
             <div class="button-container">
                 <button type="submit" name="valid">
                     <i class="fas fa-rocket" aria-hidden="true"></i>
                     {_T string="Send"}
                 </button>
+                {include file="forms_types/csrf.tpl"}
             </div>
         </form>
 {foreach from=$previews key=key item=preview}
         <div id="{$key}_preview" title="{$preview->tcomment}" class="preview">
             <div>
diff --git a/galette/templates/default/saved_searches.tpl b/galette/templates/default/saved_searches.tpl
index eb0cc32a6..97389f017 100644
--- a/galette/templates/default/saved_searches.tpl
+++ b/galette/templates/default/saved_searches.tpl
@@ -55,10 +55,11 @@
 {foreachelse}
                 <tr><td colspan="5" class="emptylist">{_T string="no search"}</td></tr>
 {/foreach}
                     </tbody>
                 </table>
+            {include file="forms_types/csrf.tpl"}
         </form>
 {/block}
 
 {block name="javascripts"}
         <script type="text/javascript">
diff --git a/galette/templates/default/traduire_libelles.tpl b/galette/templates/default/traduire_libelles.tpl
index 02833973e..ee8e89dfc 100644
--- a/galette/templates/default/traduire_libelles.tpl
+++ b/galette/templates/default/traduire_libelles.tpl
@@ -9,10 +9,11 @@
                         <label for="text_orig">{_T string="Choose label to translate"}</label>
                         <select name="text_orig" id="text_orig">
                             {html_options values=$orig output=$orig selected=$text_orig}
                         </select>
                         <noscript> <span><input type="submit" value="{_T string="Change"}" /></span></noscript>
+                        {include file="forms_types/csrf.tpl"}
                     </p>
                 </form>
     {/if}
 
                 <form action="{path_for name="editDynamicTranslation"}" method="post" enctype="multipart/form-data">
@@ -35,10 +36,11 @@
             </div>
             <div class="button-container">
                 <button type="submit" name="trans" class="action">
                     <i class="fas fa-save fa-fw"></i> {_T string="Save"}
                 </button>
+                {include file="forms_types/csrf.tpl"}
             </div>
         </form>
 {else}
         <p>{_T string="No fields to translate."}</p>
 {/if}
diff --git a/galette/templates/default/trombinoscope.tpl b/galette/templates/default/trombinoscope.tpl
index 1b8043cf7..adac06c5f 100644
--- a/galette/templates/default/trombinoscope.tpl
+++ b/galette/templates/default/trombinoscope.tpl
@@ -10,10 +10,11 @@
                 <label for="nbshow">{_T string="Records per page:"}</label>
                 <select name="nbshow" id="nbshow">
                     {html_options options=$nbshow_options selected=$numrows}
                 </select>
                 <noscript> <span><input type="submit" value="{_T string="Change"}" /></span></noscript>
+                {include file="forms_types/csrf.tpl"}
             </td>
         </tr>
     </table>
 </form>
     {foreach from=$members item=member}

Vulnerable code:         "ezyang/htmlpurifier": "^4.13"
    "content-hash": "47d56d47701d9038105bd93cf3b44a02",
            <button ype="submit" class="action">



Fixed code:         "ezyang/htmlpurifier": "^4.13",
        "slim/csrf": "0.8.3"
    "content-hash": "be12f467246cd29921b64f8f84dc17a8",
        {
            "name": "paragonie/random_compat",
            "version": "v9.99.100",
            "source": {
                "type": "git",
                "url": "https://github.com/paragonie/random_compat.git",
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
                "shasum": ""
            },
            "require": {
                "php": ">= 7"
            },
            "require-dev": {
                "phpunit/phpunit": "4.*|5.*",
                "vimeo/psalm": "^1"
            },
            "suggest": {
                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
            },
            "type": "library",
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Paragon Initiative Enterprises",
                    "email": "security@paragonie.com",
                    "homepage": "https://paragonie.com"
                }
            ],
            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
            "keywords": [
                "csprng",
                "polyfill",
                "pseudorandom",
                "random"
            ],
            "support": {
                "email": "info@paragonie.com",
                "issues": "https://github.com/paragonie/random_compat/issues",
                "source": "https://github.com/paragonie/random_compat"
            },
            "time": "2020-10-15T08:29:30+00:00"
        },
        {
            "name": "slim/csrf",
            "version": "0.8.3",
            "source": {
                "type": "git",
                "url": "https://github.com/slimphp/Slim-Csrf.git",
                "reference": "5f2bcf5d89adf86dc0455a32bea84d912ab466a7"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/slimphp/Slim-Csrf/zipball/5f2bcf5d89adf86dc0455a32bea84d912ab466a7",
                "reference": "5f2bcf5d89adf86dc0455a32bea84d912ab466a7",
                "shasum": ""
            },
            "require": {
                "paragonie/random_compat": "^1.1|^2.0|^9.99",
                "php": ">=5.5.0",
                "psr/http-message": "^1.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^4.0",
                "slim/slim": "~3.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Slim\\Csrf\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Josh Lockhart",
                    "email": "hello@joshlockhart.com",
                    "homepage": "http://joshlockhart.com"
                }
            ],
            "description": "Slim Framework 3 CSRF protection middleware",
            "homepage": "http://slimframework.com",
            "keywords": [
                "csrf",
                "framework",
                "middleware",
                "slim"
            ],
            "support": {
                "issues": "https://github.com/slimphp/Slim-Csrf/issues",
                "source": "https://github.com/slimphp/Slim-Csrf/tree/master"
            },
            "time": "2018-08-22T16:12:18+00:00"
        },
$container->set(
    'csrf',
    function (ContainerInterface $c) {
        $storage = null;
        $guard = new \Slim\Csrf\Guard(
            'csrf',
            $storage,
            null,
            200,
            16,
            true
        );

        $guard->setFailureCallable(function ($request, $response, $next) {
            Analog::log(
                'CSRF check has failed',
                Analog::CRITICAL
            );
            throw new \RuntimeException(_T('Failed CSRF check!'));
        });

        return $guard;
    }
);

$app->add(new \Galette\Middleware\SmartyCsrf($app->getContainer()));
$app->add($app->getContainer()->get('csrf'));
<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * Galette CSRF middleware
 *
 * PHP version 5
 *
 * Copyright © 2021 The Galette Team
 *
 * This file is part of Galette (http://galette.tuxfamily.org).
 *
 * Galette is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Galette is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Core
 * @package   Galette
 *
 * @author    Johan Cwiklinski <johan@x-tnd.be>
 * @copyright 2021 The Galette Team
 * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
 * @link      http://galette.tuxfamily.org
 * @since     Available since 0.9.6dev - 2021-11-08
 */

namespace Galette\Middleware;

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Analog\Analog;
use DI\Container;

/**
 * Galette CSRF middleware
 *
 * @category  Middleware
 * @name      SmartyCsrf
 * @package   Galette
 * @author    Johan Cwiklinski <johan@x-tnd.be>
 * @copyright 2020 The Galette Team
 * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
 * @link      http://galette.tuxfamily.org
 * @since     Available since 0.9.4dev - 2020-05-06
 */
class SmartyCsrf
{
    private $smarty;
    private $csrf;

    /**
     * Constructor
     *
     * @param Container $container Container instance
     */
    public function __construct(Container $container)
    {
        $view = $container->get('Slim\Views\Smarty');
        $this->smarty = $view->getSmarty();
        $this->csrf = $container->get('csrf');
    }

    /**
     * Middleware invokable class
     *
     * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
     * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
     * @param  callable                                 $next     Next middleware
     *
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function __invoke(Request $request, Response $response, $next): Response
    {
        $nameKey = $this->csrf->getTokenNameKey();
        $valueKey = $this->csrf->getTokenValueKey();
        $name = $request->getAttribute($nameKey);
        $value = $request->getAttribute($valueKey);

        $this->smarty->assign('csrf_name_key', $nameKey);
        $this->smarty->assign('csrf_value_key', $valueKey);
        $this->smarty->assign('csrf_name', $name);
        $this->smarty->assign('csrf_value', $value);

        return $next($request, $response);
    }
}
            <button type="submit" class="action">
            {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
            function csrfSafeMethod(method) {
                // these HTTP methods do not require CSRF protection
                return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
            }

                $.ajaxPrefilter(function(options, originalOptions, jqXHR){
                    if (options.type.toLowerCase() === "post") {
                        // initialize `data` to empty string if it does not exist
                        options.data = options.data || "";

                        // add leading ampersand if `data` is non-empty
                        options.data += options.data?"&":"";

                        // add csrf
                        options.data += encodeURIComponent("{$csrf_name_key}") + "=" + encodeURIComponent("{$csrf_name}") + "&" + encodeURIComponent("{$csrf_value_key}") + "=" + encodeURIComponent("{$csrf_value}")
                    }
                });

            {include file="forms_types/csrf.tpl"}
        {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                    {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
        {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
<input type="hidden" name="{$csrf_name_key}" value="{$csrf_name}"/>
<input type="hidden" name="{$csrf_value_key}" value="{$csrf_value}"/>
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                        event.preventDefault();
            {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
    {include file="forms_types/csrf.tpl"}
                    {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                    {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
                        {include file="forms_types/csrf.tpl"}
                        {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                    {include file="forms_types/csrf.tpl"}
                    {include file="forms_types/csrf.tpl"}
                    {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
        {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
            {include file="forms_types/csrf.tpl"}
                        {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}
                {include file="forms_types/csrf.tpl"}