CVE-2020-36622: Cross-Site Request Forgery (CSRF) (CWE-352)
value: A vulnerability was found in sah-comp bienlein and classified as problematic. This issue affects some unknown processing. The manipulation leads to cross-site request forgery. The attack may be initiated remotely. The name of the patch is d7836a4f2b241e4745ede194f0f6fb47199cab6b. It is recommended to apply a patch to fix this issue. The identifier VDB-216473 was assigned to this vulnerability.
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: 6.5
Published: 2022-12-21T19:15Z
Repository: https://github.com/sah-comp/bienlein
Language: PHP
Files changed: app/res/tpl/account/changepassword.php, app/res/tpl/account/index.php, app/res/tpl/account/login.php, app/res/tpl/account/lostpassword.php, app/res/tpl/admin/index.php, app/res/tpl/scaffold/form.php, src/Controller/Account.php, src/Controller/Login.php, src/Controller/Lostpassword.php, src/Controller/Scaffold.php, src/Model.php, src/Model/Criteria.php
Commit date: 2020-09-28 17:07:51 +0200
Commit message: Added CSRF prevention

Diff: diff --git a/app/res/tpl/account/changepassword.php b/app/res/tpl/account/changepassword.php
index 734dc40..0cd766d 100644
--- a/app/res/tpl/account/changepassword.php
+++ b/app/res/tpl/account/changepassword.php
@@ -19,11 +19,14 @@
     <form
         id="form-<?php echo $record->getMeta('type') ?>"
         class="panel panel-<?php echo $record->getMeta('type') ?> action-changepassword"
         method="POST"
         accept-charset="utf-8"
-        enctype="multipart/form-data">        
+        enctype="multipart/form-data">
+
+        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />
+
         <!-- changepassword form -->
         <fieldset>
             <legend><?php echo I18n::__('account_legend_changepassword') ?></legend>
             <div
                 class="row <?php echo $record->hasError('pw') ? 'error' : '' ?>">
diff --git a/app/res/tpl/account/index.php b/app/res/tpl/account/index.php
index eeb83f9..8cbae71 100644
--- a/app/res/tpl/account/index.php
+++ b/app/res/tpl/account/index.php
@@ -20,18 +20,21 @@
         id="form-<?php echo $record->getMeta('type') ?>"
         class="panel panel-<?php echo $record->getMeta('type') ?> action-profile"
         method="POST"
         accept-charset="utf-8"
         enctype="multipart/form-data">
+
+        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />
+        
         <div>
             <img
         		src="<?php echo Gravatar::src($record->email, 72) ?>"
         		class="gravatar-account circular no-shadow"
         		width="72"
         		height="72"
         		alt="<?php echo htmlspecialchars($record->getName()) ?>" />
-        </div>     
+        </div>
         <!-- account form -->
         <fieldset>
             <legend><?php echo I18n::__('account_legend') ?></legend>
             <div
                 class="row <?php echo $record->hasError('name') ? 'error' : '' ?>">
diff --git a/app/res/tpl/account/login.php b/app/res/tpl/account/login.php
index 35b5ceb..7dbbe6c 100644
--- a/app/res/tpl/account/login.php
+++ b/app/res/tpl/account/login.php
@@ -27,10 +27,13 @@
     <form
         id="form-login"
         class="panel login"
         method="POST"
         accept-charset="utf-8">
+
+        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />
+
         <div>
             <input type="hidden" name="dialog[type]" value="<?php echo $record->getMeta('type') ?>" />
             <input type="hidden" name="dialog[id]" value="<?php echo $record->getId() ?>" />
             <input
                 type="hidden"
diff --git a/app/res/tpl/account/lostpassword.php b/app/res/tpl/account/lostpassword.php
index ded7f59..fd60e25 100644
--- a/app/res/tpl/account/lostpassword.php
+++ b/app/res/tpl/account/lostpassword.php
@@ -27,10 +27,13 @@
     <form
         id="form-lostpassword"
         class="panel lostpassword"
         method="POST"
         accept-charset="utf-8">
+
+        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />
+
         <fieldset>
             <legend><?php echo I18n::__('lostpassword_legend') ?></legend>
             <div
                 class="row">
                 <label
diff --git a/app/res/tpl/admin/index.php b/app/res/tpl/admin/index.php
index 766332c..4898f78 100644
--- a/app/res/tpl/admin/index.php
+++ b/app/res/tpl/admin/index.php
@@ -17,10 +17,13 @@
         id="form-<?php echo $record->getMeta('type') ?>"
         class="panel panel-<?php echo $record->getMeta('type') ?> action-edit"
         method="POST"
         accept-charset="utf-8"
         enctype="multipart/form-data">
+
+        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />
+
         <?php echo $form_details ?>
         <div class="buttons">
             <input
                 type="submit"
                 name="submit"
diff --git a/app/res/tpl/scaffold/form.php b/app/res/tpl/scaffold/form.php
index f7d1421..cb77a37 100644
--- a/app/res/tpl/scaffold/form.php
+++ b/app/res/tpl/scaffold/form.php
@@ -20,15 +20,17 @@
         id="form-<?php echo $record->getMeta('type') ?>"
         class="panel panel-<?php echo $record->getMeta('type') ?> action-<?php echo $current_action ?>"
         method="POST"
         accept-charset="utf-8"
         enctype="multipart/form-data">
-        
+
+        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />
+
         <!-- form details -->
         <?php echo $form_details ?>
         <!-- end of form details -->
-        
+
         <!-- Scaffold buttons -->
         <div class="buttons">
             <select name="next_action">
                 <?php foreach ($actions[$current_action] as $action): ?>
                 <option
diff --git a/src/Controller/Account.php b/src/Controller/Account.php
index 22596df..7d7de36 100644
--- a/src/Controller/Account.php
+++ b/src/Controller/Account.php
@@ -33,26 +33,28 @@ class Controller_Account extends Controller
     public function index()
     {
         session_start();
         Auth::check();
         $this->template = 'account/index';
-        
+
         if (Flight::request()->method == 'POST') {
+            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
+                $this->redirect("/logout");
+            }
             Flight::get('user')->import(Flight::request()->data->dialog);
             try {
                 R::store(Flight::get('user'));
                 Flight::get('user')->notify(I18n::__('account_edit_success'), 'success');
                 $this->redirect('/account/');
-            }
-            catch (Exception $e) {
+            } catch (Exception $e) {
                 Flight::get('user')->notify(I18n::__('account_edit_failure'), 'error');
-            }    
+            }
         }
-        
+
         $this->render();
     }
-    
+
     /**
      * Displays a page to change the password.
      *
      * A GET request will simply display the page and a POST request will try to
      * change the password.
@@ -60,50 +62,51 @@ class Controller_Account extends Controller
     public function changepassword()
     {
         session_start();
         Auth::check();
         $this->template = 'account/changepassword';
-        
+
         if (Flight::request()->method == 'POST') {
+            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
+                $this->redirect("/logout");
+            }
             if (Flight::get('user')->changePassword(
                 Flight::request()->data->pw,
                 Flight::request()->data->pw_new,
                 Flight::request()->data->pw_repeated
             )) {
                 try {
                     R::store(Flight::get('user'));
                     Flight::get('user')->notify(I18n::__('account_changepassword_success'), 'success');
                     $this->redirect('/account/');
-                }
-                catch (Exception $e) {
+                } catch (Exception $e) {
                     //Whoops, what nu?
                 }
-            }
-            else {
+            } else {
                 Flight::get('user')->notify(I18n::__('account_changepassword_failure'), 'error');
-            }    
+            }
         }
-        
+
         $this->render();
     }
-    
+
     /**
      * Renders the account page.
      */
     protected function render()
     {
-	    Flight::render('shared/notification', array(), 'notification');
-	    //
+        Flight::render('shared/notification', array(), 'notification');
+        //
         Flight::render('shared/navigation/account', array(), 'navigation_account');
-		Flight::render('shared/navigation/main', array(), 'navigation_main');
+        Flight::render('shared/navigation/main', array(), 'navigation_main');
         Flight::render('shared/navigation', array(), 'navigation');
         Flight::render('account/toolbar', array(), 'toolbar');
-		Flight::render('shared/header', array(), 'header');
-		Flight::render('shared/footer', array(), 'footer');
-		Flight::render($this->template, array(
-		    'record' => Flight::get('user')
-		), 'content');
+        Flight::render('shared/header', array(), 'header');
+        Flight::render('shared/footer', array(), 'footer');
+        Flight::render($this->template, array(
+            'record' => Flight::get('user')
+        ), 'content');
         Flight::render('html5', array(
             'title' => I18n::__("account_head_title"),
             'language' => Flight::get('language')
         ));
     }
diff --git a/src/Controller/Login.php b/src/Controller/Login.php
index d03079b..67c2195 100644
--- a/src/Controller/Login.php
+++ b/src/Controller/Login.php
@@ -31,17 +31,20 @@ class Controller_Login extends Controller
      * no URL was provided.
      */
     public function index()
     {
         session_start();
-        if ( ! isset($_SESSION['login_id'])) {
+        if (! isset($_SESSION['login_id'])) {
             $_SESSION['login_id'] = 0;
         }
         $login = R::load('login', $_SESSION['login_id']);
         if (Flight::request()->method == 'POST') {
+            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
+                $this->redirect("/logout");
+            }
             try {
-                $login = R::graph( Flight::request()->data->dialog, TRUE );
+                $login = R::graph(Flight::request()->data->dialog, true);
                 if ($login->trial()) {
                     //you must trial before store because of pw reset in update
                     $_SESSION['user']['id'] = $login->user->getId();
                     $_SESSION['backend']['language'] = Flight::get('language');
                     $login->user->sid = session_id();
@@ -54,11 +57,11 @@ class Controller_Login extends Controller
                 error_log($e);
                 //uups, login could not be saved
             }
         }
         // either no yet submitted or the credentials given failed
-        if ( Flight::request()->query->goto == '' || Flight::request()->query->goto == '/login' ) {
+        if (Flight::request()->query->goto == '' || Flight::request()->query->goto == '/login') {
             $goto = '/cms';
         } else {
             $goto = Flight::request()->query->goto;
         }
         Flight::render('account/login', array(
diff --git a/src/Controller/Lostpassword.php b/src/Controller/Lostpassword.php
index 2844438..ad39e40 100644
--- a/src/Controller/Lostpassword.php
+++ b/src/Controller/Lostpassword.php
@@ -21,16 +21,16 @@ class Controller_Lostpassword extends Controller
      * Holds the template to render.
      *
      * @var string
      */
     public $template = 'account/lostpassword';
-    
+
     /**
      * Holds the username entered by the password seeking party.
      */
     public $uname = '';
-    
+
     /**
      * May hold a message (textile) to the user that want to re-enter a password.
      */
     public $message;
 
@@ -41,32 +41,35 @@ class Controller_Lostpassword extends Controller
      * the user account.
      */
     public function index()
     {
         if (Flight::request()->method == 'POST') {
+            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
+                $this->redirect("/logout");
+            }
             $this->uname = Flight::request()->data->dialog['uname'];
-            if ( ! $user = R::findOne('user', ' email = ? LIMIT 1 ', array($this->uname))) {
+            if (! $user = R::findOne('user', ' email = ? LIMIT 1 ', array($this->uname))) {
                 $this->message = I18n::__('lostpassword_user_unknown');
-            } elseif ( ! $user->requestPassword()) {
+            } elseif (! $user->requestPassword()) {
                 $this->message = I18n::__('lostpassword_email_failed');
             } else {
                 $this->redirect('login');
             }
         }
-        
+
         $this->render();
     }
-    
+
     /**
      * Renders the lostpassword page.
      */
     protected function render()
     {
-		Flight::render($this->template, array(
-		    'uname' => $this->uname,
-		    'message' => $this->message
-		), 'content');
+        Flight::render($this->template, array(
+            'uname' => $this->uname,
+            'message' => $this->message
+        ), 'content');
         Flight::render('html5', array(
             'title' => I18n::__("lostpassword_head_title"),
             'language' => Flight::get('language'),
             'stylesheets' => array('custom', 'default')
         ));
diff --git a/src/Controller/Scaffold.php b/src/Controller/Scaffold.php
index 5c86d75..0da3bbc 100644
--- a/src/Controller/Scaffold.php
+++ b/src/Controller/Scaffold.php
@@ -486,10 +486,13 @@ class Controller_Scaffold extends Controller
         $this->order = $order;
         $this->dir = $dir;
         //$this->template = "model/{$this->type}/{$this->layout}";
         $this->template = "scaffold/{$this->layout}";
         if (Flight::request()->method == 'POST') {
+            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
+                $this->redirect("/logout");
+            }
             //clear filter?
             if (Flight::request()->data->submit == I18n::__('filter_submit_clear')) {
                 R::trash($this->filter);
                 $_SESSION['scaffold'][$this->type]['filter']['id'] = 0;
                 $this->redirect("{$this->base_url}/{$this->type}/{$this->layout}");
@@ -557,10 +560,13 @@ class Controller_Scaffold extends Controller
                 // if there is no special "edit" template, we fallback to "edit"
                 $this->template = "scaffold/edit";
             }
         }
         if (Flight::request()->method == 'POST') {
+            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
+                $this->redirect("/logout");
+            }
             $this->record = R::graph(Flight::request()->data->dialog, true);
             $this->setNextAction(Flight::request()->data->next_action);
             if ($this->doRedbeanAction()) {
                 if ($this->getNextAction() == 'add') {
                     $this->redirect("{$this->base_url}/{$this->type}/add/{$this->layout}/");
@@ -603,10 +609,13 @@ class Controller_Scaffold extends Controller
         if (! Flight::view()->exists($this->template)) {
             // if there is no special "edit" template, we fallback to "scaffold/edit"
             $this->template = "scaffold/edit";
         }
         if (Flight::request()->method == 'POST') {
+            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
+                $this->redirect("/logout");
+            }
             Permission::check(Flight::get('user'), $this->type, 'edit');//check for edit perm now
             $this->record = R::graph(Flight::request()->data->dialog, true);
             $this->setNextAction(Flight::request()->data->next_action);
             if ($this->doRedbeanAction()) {
                 if ($this->getNextAction() == 'edit') {
diff --git a/src/Model.php b/src/Model.php
index b05ea2c..ed6c850 100644
--- a/src/Model.php
+++ b/src/Model.php
@@ -85,10 +85,43 @@ class Model extends RedBean_SimpleModel
      */
     public function __construct()
     {
     }
 
+    /**
+     * Returns a "random" string to prevent CSRF.
+     *
+     * @return string
+     */
+    public static function getCSRFToken()
+    {
+        @session_start();
+        if (empty($_SESSION['csrf_tokens'])) {
+            $_SESSION['csrf_tokens'] = [];
+        }
+        $nonce = md5(uniqid(rand(), true));
+        $_SESSION['csrf_tokens'][$nonce] = true;
+        return $nonce;
+    }
+
+    /**
+     * Returns wether the CSRF token validates or not.
+     *
+     * @param string $token
+     * @return bool
+     */
+    public static function validateCSRFToken($token)
+    {
+        @session_start();
+        if (isset($_SESSION['csrf_tokens'][$token])) {
+            unset($_SESSION['csrf_tokens'][$token]);
+            error_log('Good user');
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Returns an array with attributes for lists.
      *
      * @param string (optional) $layout
      * @return array
diff --git a/src/Model/Criteria.php b/src/Model/Criteria.php
index 545f7f0..91e04cb 100644
--- a/src/Model/Criteria.php
+++ b/src/Model/Criteria.php
@@ -21,23 +21,23 @@ class Model_Criteria extends Model
      * Container for the map of search operators.
      *
      * @var array
      */
     public $map = array(
- 		'like' => '%1$s like ?',
- 		'notlike' => '%1$s not like ?',
- 		'eq' => '%1$s = ?',
- 		'neq' => '%1$s != ?',
- 		'bw' => '%1$s like ?',
- 		'ew' => '%1$s like ?',
- 		'lt' => '%1$s < ?',
- 		'gt' => '%1$s > ?',
- 	    'in' => '%1$s in (%2$s)'
- 		//'between' => __('filter_op_between'),
- 		//'istrue' => __('filter_op_istrue'),
- 		//'isfalse' => __('filter_op_isfalse')
- 	);
+        'like' => '%1$s like ?',
+        'notlike' => '%1$s not like ?',
+        'eq' => '%1$s = ?',
+        'neq' => '%1$s != ?',
+        'bw' => '%1$s like ?',
+        'ew' => '%1$s like ?',
+        'lt' => '%1$s < ?',
+        'gt' => '%1$s > ?',
+        'in' => '%1$s in (%2$s)'
+        //'between' => __('filter_op_between'),
+        //'istrue' => __('filter_op_istrue'),
+        //'isfalse' => __('filter_op_isfalse')
+    );
 
     /**
      * Holds possible search operators depending on the filter tag type.
      *
      * A simple scaffold filter criteria will always use the first operator. E.g. if you
@@ -56,124 +56,135 @@ class Model_Criteria extends Model
         'in' => array('in'),
         'select' => array('eq'),
         'bool' => array('eq')
      );
 
-     /**
-      * Container for characters that have to be escaped for usage with SQL.
-      *
-      * @var array
-      */
-     public $pat = array('%', '_');
-
-     /**
-      * Container for escaped charaters.
-      *
-      * @var array
-      */
-     public $rep = array('\%', '\_');
-     
-     /**
-      * Prepares a value according to its tag and returns it.
-      *
-      * @param string the value to convert
-      * @return mixed
-      */
-     public function convertToText($value)
-     {
-         return $value;
-     }
-     
-     /**
-      * Prepares a value according to its tag and returns it.
-      *
-      * @param string the value to convert
-      * @return mixed
-      */
-     public function convertToNumber($value)
-     {
-         return (float)str_replace(',', '.', $value);
-         //return $value;
-     }
-     
-     /**
-      * Prepares a value according to its tag and returns it.
-      *
-      * @param string the value to convert
-      * @return mixed
-      */
-     public function convertToEmail($value)
-     {
-         return $value;
-     }
-     
-     /**
-      * Prepares a value according to its tag and returns it.
-      *
-      * @param string the value to convert
-      * @return mixed
-      */
-     public function convertToTextarea($value)
-     {
-         return $value;
-     }
-     
-     /**
-      * Prepares a value according to its tag and returns it.
-      *
-      * @param string the value to convert
-      * @return mixed
-      */
-     public function convertToIn($value)
-     {
-         return $value;
-     }
-     
-     /**
-      * Prepares a value according to its tag and returns it.
-      *
-      * @param string the value to convert
-      * @return mixed
-      */
-     public function convertToBool($value)
-     {
-         return $value;
-     }
-     
-     /**
-      * Prepares a value according to its tag and returns it.
-      *
-      * @param string the value to convert
-      * @return mixed
-      */
-     public function convertToSelect($value)
-     {
-         return $value;
-     }
-     
-     /**
-      * Returns a mysql datetime string.
-      *
-      * @param string the value to convert
-      * @return string
-      */
-     public function convertToDatetime($value)
-     {
-         return date('Y-m-d H:i:s', strtotime($value));
-     }
-     
-     /**
-      * Returns a mysql date string.
-      *
-      * @param string the value to convert
-      * @return string
-      */
-     public function convertToDate($value)
-     {
-         return date('Y-m-d', strtotime($value));
-     }
-    
+    /**
+     * Container for characters that have to be escaped for usage with SQL.
+     *
+     * @var array
+     */
+    public $pat = array('%', '_');
+
+    /**
+     * Container for escaped charaters.
+     *
+     * @var array
+     */
+    public $rep = array('\%', '\_');
+
+    /**
+     * Prepares a value according to its tag and returns it.
+     *
+     * @param string the value to convert
+     * @return mixed
+     */
+    public function convertToText($value)
+    {
+        return $value;
+    }
+
+    /**
+     * Prepares a value according to its tag and returns it.
+     *
+     * @param string the value to convert
+     * @return mixed
+     */
+    public function convertToNumber($value)
+    {
+        return (float)str_replace(',', '.', $value);
+        //return $value;
+    }
+
+    /**
+     * Prepares a value according to its tag and returns it.
+     *
+     * @param string the value to convert
+     * @return mixed
+     */
+    public function convertToEmail($value)
+    {
+        return $value;
+    }
+
+    /**
+     * Prepares a value according to its tag and returns it.
+     *
+     * @param string the value to convert
+     * @return mixed
+     */
+    public function convertToTextarea($value)
+    {
+        return $value;
+    }
+
+    /**
+     * Prepares a value according to its tag and returns it.
+     *
+     * @param string the value to convert
+     * @return mixed
+     */
+    public function convertToIn($value)
+    {
+        return $value;
+    }
+
+    /**
+     * Prepares a value according to its tag and returns it.
+     *
+     * @param string the value to convert
+     * @return mixed
+     */
+    public function convertToBool($value)
+    {
+        return $value;
+    }
+
+    /**
+     * Prepares a value according to its tag and returns it.
+     *
+     * @param string the value to convert
+     * @return mixed
+     */
+    public function convertToSelect($value)
+    {
+        return $value;
+    }
+
+    /**
+     * Returns a mysql datetime string.
+     *
+     * @param string the value to convert
+     * @return string
+     */
+    public function convertToDatetime($value)
+    {
+        return date('Y-m-d H:i:s', strtotime($value));
+    }
+
+    /**
+     * Returns a mysql date string.
+     *
+     * @param string the value to convert
+     * @return string
+     */
+    public function convertToDate($value)
+    {
+        return date('Y-m-d', strtotime($value));
+    }
+
+    /**
+     * Returns a mysql time string.
+     *
+     * @param string the value to convert
+     * @return string
+     */
+    public function convertToTime($value)
+    {
+        return date('H:i:s', strtotime($value));
+    }
+
     /**
      * Returns a string to use as part of a SQL query.
      *
      * @throws an exception when criteria operator has no template definded in map
      * @uses $map
@@ -181,66 +192,70 @@ class Model_Criteria extends Model
      * @param Model_Filter $filter
      * @return string
      */
     public function makeWherePart(Model_Filter $filter)
     {
-        if ( ! isset($this->map[$this->bean->op])) throw new Exception('Filter operator has no template');
+        if (! isset($this->map[$this->bean->op])) {
+            throw new Exception('Filter operator has no template');
+        }
         $template = $this->map[$this->bean->op];
         $value = $this->mask_filter_value($filter);
         return sprintf($template, $this->bean->attribute, $value);
     }
-    
+
     /**
      * Masks the criterias value and stacks it into the filter values.
      *
      * @uses Model_Filter::$filter_values where the values of our criterias are stacked up
      * @param Model_Filter $filter
      * @return void
      */
     protected function mask_filter_value(Model_Filter $filter)
     {
         $add_to_filter_values = true;
-    	switch ($this->bean->op) {
-    		case 'like':
-    			$value = '%'.str_replace($this->pat, $this->rep, $this->bean->value).'%';
-    			break;
-    		case 'notlike':
-    			$value = '%'.str_replace($this->pat, $this->rep, $this->bean->value).'%';
-    			break;
-    		case 'bw':
-    			$value = str_replace($this->pat, $this->rep, $this->bean->value).'%';
-    			break;
-    		case 'ew':
-    			$value = '%'.str_replace($this->pat, $this->rep, $this->bean->value);
-    			break;
-    		case 'in':
-    		    $_sharedSubName = 'shared'.ucfirst(strtolower($this->bean->substitute));
-    		    $ids = array_keys($this->bean->{$_sharedSubName});
-    		    $value = implode(', ', $ids);
-    		    $add_to_filter_values = false;
-    		    break;
-    		default:
-    			$value = $this->bean->value;
-    	}
-    	if ($add_to_filter_values) {
-    	    $converter = 'convertTo' . ucfirst(strtolower($this->bean->tag));
-    	    $filter->filter_values[] = $this->$converter($value);
-    	}
-    	return $value;
+        switch ($this->bean->op) {
+            case 'like':
+                $value = '%'.str_replace($this->pat, $this->rep, $this->bean->value).'%';
+                break;
+            case 'notlike':
+                $value = '%'.str_replace($this->pat, $this->rep, $this->bean->value).'%';
+                break;
+            case 'bw':
+                $value = str_replace($this->pat, $this->rep, $this->bean->value).'%';
+                break;
+            case 'ew':
+                $value = '%'.str_replace($this->pat, $this->rep, $this->bean->value);
+                break;
+            case 'in':
+                $_sharedSubName = 'shared'.ucfirst(strtolower($this->bean->substitute));
+                $ids = array_keys($this->bean->{$_sharedSubName});
+                $value = implode(', ', $ids);
+                $add_to_filter_values = false;
+                break;
+            default:
+                $value = $this->bean->value;
+        }
+        if ($add_to_filter_values) {
+            $converter = 'convertTo' . ucfirst(strtolower($this->bean->tag));
+            $filter->filter_values[] = $this->$converter($value);
+        }
+        return $value;
     }
-    
+
     /**
      * Returns array with possible operators for the given tag type.
      *
      * @return array $operators
      */
     public function operators()
     {
-        if (isset($this->operators[$this->bean->tag])) return $this->operators[$this->bean->tag];
+        if (isset($this->operators[$this->bean->tag])) {
+            return $this->operators[$this->bean->tag];
+        }
         return array();
     }
-    
+
     /**
      * Setup validators.
      */
     public function dispense()
     {

Vulnerable code:         enctype="multipart/form-data">        
        </div>     
        
        
        
            }
            catch (Exception $e) {
            }    
        
    
        
                }
                catch (Exception $e) {
            }
            else {
            }    
        
    
	    Flight::render('shared/notification', array(), 'notification');
	    //
		Flight::render('shared/navigation/main', array(), 'navigation_main');
		Flight::render('shared/header', array(), 'header');
		Flight::render('shared/footer', array(), 'footer');
		Flight::render($this->template, array(
		    'record' => Flight::get('user')
		), 'content');
        if ( ! isset($_SESSION['login_id'])) {
                $login = R::graph( Flight::request()->data->dialog, TRUE );
        if ( Flight::request()->query->goto == '' || Flight::request()->query->goto == '/login' ) {
    
    
            if ( ! $user = R::findOne('user', ' email = ? LIMIT 1 ', array($this->uname))) {
            } elseif ( ! $user->requestPassword()) {
        
    
		Flight::render($this->template, array(
		    'uname' => $this->uname,
		    'message' => $this->message
		), 'content');
 		'like' => '%1$s like ?',
 		'notlike' => '%1$s not like ?',
 		'eq' => '%1$s = ?',
 		'neq' => '%1$s != ?',
 		'bw' => '%1$s like ?',
 		'ew' => '%1$s like ?',
 		'lt' => '%1$s < ?',
 		'gt' => '%1$s > ?',
 	    'in' => '%1$s in (%2$s)'
 		//'between' => __('filter_op_between'),
 		//'istrue' => __('filter_op_istrue'),
 		//'isfalse' => __('filter_op_isfalse')
 	);
     /**
      * Container for characters that have to be escaped for usage with SQL.
      *
      * @var array
      */
     public $pat = array('%', '_');

     /**
      * Container for escaped charaters.
      *
      * @var array
      */
     public $rep = array('\%', '\_');
     
     /**
      * Prepares a value according to its tag and returns it.
      *
      * @param string the value to convert
      * @return mixed
      */
     public function convertToText($value)
     {
         return $value;
     }
     
     /**
      * Prepares a value according to its tag and returns it.
      *
      * @param string the value to convert
      * @return mixed
      */
     public function convertToNumber($value)
     {
         return (float)str_replace(',', '.', $value);
         //return $value;
     }
     
     /**
      * Prepares a value according to its tag and returns it.
      *
      * @param string the value to convert
      * @return mixed
      */
     public function convertToEmail($value)
     {
         return $value;
     }
     
     /**
      * Prepares a value according to its tag and returns it.
      *
      * @param string the value to convert
      * @return mixed
      */
     public function convertToTextarea($value)
     {
         return $value;
     }
     
     /**
      * Prepares a value according to its tag and returns it.
      *
      * @param string the value to convert
      * @return mixed
      */
     public function convertToIn($value)
     {
         return $value;
     }
     
     /**
      * Prepares a value according to its tag and returns it.
      *
      * @param string the value to convert
      * @return mixed
      */
     public function convertToBool($value)
     {
         return $value;
     }
     
     /**
      * Prepares a value according to its tag and returns it.
      *
      * @param string the value to convert
      * @return mixed
      */
     public function convertToSelect($value)
     {
         return $value;
     }
     
     /**
      * Returns a mysql datetime string.
      *
      * @param string the value to convert
      * @return string
      */
     public function convertToDatetime($value)
     {
         return date('Y-m-d H:i:s', strtotime($value));
     }
     
     /**
      * Returns a mysql date string.
      *
      * @param string the value to convert
      * @return string
      */
     public function convertToDate($value)
     {
         return date('Y-m-d', strtotime($value));
     }
    
        if ( ! isset($this->map[$this->bean->op])) throw new Exception('Filter operator has no template');
    
    	switch ($this->bean->op) {
    		case 'like':
    			$value = '%'.str_replace($this->pat, $this->rep, $this->bean->value).'%';
    			break;
    		case 'notlike':
    			$value = '%'.str_replace($this->pat, $this->rep, $this->bean->value).'%';
    			break;
    		case 'bw':
    			$value = str_replace($this->pat, $this->rep, $this->bean->value).'%';
    			break;
    		case 'ew':
    			$value = '%'.str_replace($this->pat, $this->rep, $this->bean->value);
    			break;
    		case 'in':
    		    $_sharedSubName = 'shared'.ucfirst(strtolower($this->bean->substitute));
    		    $ids = array_keys($this->bean->{$_sharedSubName});
    		    $value = implode(', ', $ids);
    		    $add_to_filter_values = false;
    		    break;
    		default:
    			$value = $this->bean->value;
    	}
    	if ($add_to_filter_values) {
    	    $converter = 'convertTo' . ucfirst(strtolower($this->bean->tag));
    	    $filter->filter_values[] = $this->$converter($value);
    	}
    	return $value;
    
        if (isset($this->operators[$this->bean->tag])) return $this->operators[$this->bean->tag];
    
Fixed code:         enctype="multipart/form-data">

        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />


        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />
        
        </div>

        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />


        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />


        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />


        <input type="hidden" name="token" value="<?php echo Model::getCSRFToken() ?>" />



            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
                $this->redirect("/logout");
            }
            } catch (Exception $e) {
            }



            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
                $this->redirect("/logout");
            }
                } catch (Exception $e) {
            } else {
            }


        Flight::render('shared/notification', array(), 'notification');
        //
        Flight::render('shared/navigation/main', array(), 'navigation_main');
        Flight::render('shared/header', array(), 'header');
        Flight::render('shared/footer', array(), 'footer');
        Flight::render($this->template, array(
            'record' => Flight::get('user')
        ), 'content');
        if (! isset($_SESSION['login_id'])) {
            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
                $this->redirect("/logout");
            }
                $login = R::graph(Flight::request()->data->dialog, true);
        if (Flight::request()->query->goto == '' || Flight::request()->query->goto == '/login') {


            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
                $this->redirect("/logout");
            }
            if (! $user = R::findOne('user', ' email = ? LIMIT 1 ', array($this->uname))) {
            } elseif (! $user->requestPassword()) {


        Flight::render($this->template, array(
            'uname' => $this->uname,
            'message' => $this->message
        ), 'content');
            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
                $this->redirect("/logout");
            }
            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
                $this->redirect("/logout");
            }
            if (! Model::validateCSRFToken(Flight::request()->data->token)) {
                $this->redirect("/logout");
            }
    /**
     * Returns a "random" string to prevent CSRF.
     *
     * @return string
     */
    public static function getCSRFToken()
    {
        @session_start();
        if (empty($_SESSION['csrf_tokens'])) {
            $_SESSION['csrf_tokens'] = [];
        }
        $nonce = md5(uniqid(rand(), true));
        $_SESSION['csrf_tokens'][$nonce] = true;
        return $nonce;
    }

    /**
     * Returns wether the CSRF token validates or not.
     *
     * @param string $token
     * @return bool
     */
    public static function validateCSRFToken($token)
    {
        @session_start();
        if (isset($_SESSION['csrf_tokens'][$token])) {
            unset($_SESSION['csrf_tokens'][$token]);
            error_log('Good user');
            return true;
        }
        return false;
    }

        'like' => '%1$s like ?',
        'notlike' => '%1$s not like ?',
        'eq' => '%1$s = ?',
        'neq' => '%1$s != ?',
        'bw' => '%1$s like ?',
        'ew' => '%1$s like ?',
        'lt' => '%1$s < ?',
        'gt' => '%1$s > ?',
        'in' => '%1$s in (%2$s)'
        //'between' => __('filter_op_between'),
        //'istrue' => __('filter_op_istrue'),
        //'isfalse' => __('filter_op_isfalse')
    );
    /**
     * Container for characters that have to be escaped for usage with SQL.
     *
     * @var array
     */
    public $pat = array('%', '_');

    /**
     * Container for escaped charaters.
     *
     * @var array
     */
    public $rep = array('\%', '\_');

    /**
     * Prepares a value according to its tag and returns it.
     *
     * @param string the value to convert
     * @return mixed
     */
    public function convertToText($value)
    {
        return $value;
    }

    /**
     * Prepares a value according to its tag and returns it.
     *
     * @param string the value to convert
     * @return mixed
     */
    public function convertToNumber($value)
    {
        return (float)str_replace(',', '.', $value);
        //return $value;
    }

    /**
     * Prepares a value according to its tag and returns it.
     *
     * @param string the value to convert
     * @return mixed
     */
    public function convertToEmail($value)
    {
        return $value;
    }

    /**
     * Prepares a value according to its tag and returns it.
     *
     * @param string the value to convert
     * @return mixed
     */
    public function convertToTextarea($value)
    {
        return $value;
    }

    /**
     * Prepares a value according to its tag and returns it.
     *
     * @param string the value to convert
     * @return mixed
     */
    public function convertToIn($value)
    {
        return $value;
    }

    /**
     * Prepares a value according to its tag and returns it.
     *
     * @param string the value to convert
     * @return mixed
     */
    public function convertToBool($value)
    {
        return $value;
    }

    /**
     * Prepares a value according to its tag and returns it.
     *
     * @param string the value to convert
     * @return mixed
     */
    public function convertToSelect($value)
    {
        return $value;
    }

    /**
     * Returns a mysql datetime string.
     *
     * @param string the value to convert
     * @return string
     */
    public function convertToDatetime($value)
    {
        return date('Y-m-d H:i:s', strtotime($value));
    }

    /**
     * Returns a mysql date string.
     *
     * @param string the value to convert
     * @return string
     */
    public function convertToDate($value)
    {
        return date('Y-m-d', strtotime($value));
    }

    /**
     * Returns a mysql time string.
     *
     * @param string the value to convert
     * @return string
     */
    public function convertToTime($value)
    {
        return date('H:i:s', strtotime($value));
    }

        if (! isset($this->map[$this->bean->op])) {
            throw new Exception('Filter operator has no template');
        }

        switch ($this->bean->op) {
            case 'like':
                $value = '%'.str_replace($this->pat, $this->rep, $this->bean->value).'%';
                break;
            case 'notlike':
                $value = '%'.str_replace($this->pat, $this->rep, $this->bean->value).'%';
                break;
            case 'bw':
                $value = str_replace($this->pat, $this->rep, $this->bean->value).'%';
                break;
            case 'ew':
                $value = '%'.str_replace($this->pat, $this->rep, $this->bean->value);
                break;
            case 'in':
                $_sharedSubName = 'shared'.ucfirst(strtolower($this->bean->substitute));
                $ids = array_keys($this->bean->{$_sharedSubName});
                $value = implode(', ', $ids);
                $add_to_filter_values = false;
                break;
            default:
                $value = $this->bean->value;
        }
        if ($add_to_filter_values) {
            $converter = 'convertTo' . ucfirst(strtolower($this->bean->tag));
            $filter->filter_values[] = $this->$converter($value);
        }
        return $value;

        if (isset($this->operators[$this->bean->tag])) {
            return $this->operators[$this->bean->tag];
        }