Vulnerability: An issue was discovered in MISP before 2.4.158. In UsersController.php, password confirmation can be bypassed via vectors involving an "Accept: application/json" header.
Vulnerability ID: CVE-2022-29534
CWE: CWE-287
Severity score: 2.9
Project: https://github.com/MISP/MISP
Published: 2022-04-20
File: app/Controller/UsersController.php
Commit message: fix: [security] Password confirmation bypass in user edit

- optional password confirmation can be potentially circumvented
- fooling the user edit via a request that sets accept:application/json whilst posting form content

- as reported by Dawid Czarnecki of Zigrin Security on behalf of the Luxembourg Army
Commit author: iglocska

Vulnerable version (before fix):
 public function edit()                     }                 }             }             if (!$abortPost && !$this->_isRest()) {                 if (Configure::read('Security.require_password_confirmation')) {                     if (!empty($this->request->data['User']['current_password'])) {                         $hashed = $this->User->verifyPassword($this->Auth->user('id'), $this->request->data['User']['current_password']); public function admin_edit($id = null)                 $this->request->data['User'] = $this->request->data;             }             $abortPost = false;             if (!$this->_isRest()) {                 if (Configure::read('Security.require_password_confirmation')) {                     if (!empty($this->request->data['User']['current_password'])) {                         $hashed = $this->User->verifyPassword($this->Auth->user('id'), $this->request->data['User']['current_password']);

Fixed version (after fix):
 public function edit()                     }                 }             }             if (!$abortPost && (!$this->_isRest() || empty($this->request->header('Authorization')))) {                 if (Configure::read('Security.require_password_confirmation')) {                     if (!empty($this->request->data['User']['current_password'])) {                         $hashed = $this->User->verifyPassword($this->Auth->user('id'), $this->request->data['User']['current_password']); public function admin_edit($id = null)                 $this->request->data['User'] = $this->request->data;             }             $abortPost = false;             if (!$this->_isRest() || empty($this->request->header('Authorization'))) {                 if (Configure::read('Security.require_password_confirmation')) {                     if (!empty($this->request->data['User']['current_password'])) {                         $hashed = $this->User->verifyPassword($this->Auth->user('id'), $this->request->data['User']['current_password']);

Patch:
patch: @@ -154,7 +154,7 @@ public function edit()
                     }
                 }
             }
-            if (!$abortPost && !$this->_isRest()) {
+            if (!$abortPost && (!$this->_isRest() || empty($this->request->header('Authorization')))) {
                 if (Configure::read('Security.require_password_confirmation')) {
                     if (!empty($this->request->data['User']['current_password'])) {
                         $hashed = $this->User->verifyPassword($this->Auth->user('id'), $this->request->data['User']['current_password']);
@@ -853,7 +853,7 @@ public function admin_edit($id = null)
                 $this->request->data['User'] = $this->request->data;
             }
             $abortPost = false;
-            if (!$this->_isRest()) {
+            if (!$this->_isRest() || empty($this->request->header('Authorization'))) {
                 if (Configure::read('Security.require_password_confirmation')) {
                     if (!empty($this->request->data['User']['current_password'])) {
                         $hashed = $this->User->verifyPassword($this->Auth->user('id'), $this->request->data['User']['current_password']);
path: app/Controller/UsersController.php