CVE-2021-41260 (Other, published 2021-12-16T18:15Z)
Description: 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.
Severity: MEDIUM (CVSS v3 base score: 8.8)
Weakness: CWE-352 \u2014 Cross-Site Request Forgery (CSRF)
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.
Repository: https://github.com/galette/galette
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 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


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"}