CVE-2019-19379: Insufficient Information (NVD-CWE-noinfo)
value: In app/Controller/TagsController.php in MISP 2.4.118, users can bypass intended restrictions on tagging data.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 5.3
Published: 2019-11-28T17:15Z
Repository: https://github.com/MISP/MISP
Language: PHP
Files changed: app/Controller/TagsController.php
Commit date: 2019-11-26 11:36:49 +0100
Commit message: fix: [security] tightened checks for restricting users from tagging data they shouldn't be allowed to tag

As reported by Christophe Vandeplas

Diff: diff --git a/app/Controller/TagsController.php b/app/Controller/TagsController.php
index abdbe6c40c8..4fdcddfc7a2 100644
--- a/app/Controller/TagsController.php
+++ b/app/Controller/TagsController.php
@@ -858,45 +858,52 @@ class TagsController extends AppController
         $this->set('flags', JSON_PRETTY_PRINT);
         $this->response->type('json');
         $this->render('/Servers/json/simple');
     }
 
-    private function __findObjectByUuid($object_uuid, &$type)
+    private function __findObjectByUuid($object_uuid, &$type, $scope = 'modify')
     {
         $this->loadModel('Event');
-        $object = $this->Event->find('first', array(
-            'conditions' => array(
-                'Event.uuid' => $object_uuid,
-            ),
-            'fields' => array('Event.orgc_id', 'Event.id'),
-            'recursive' => -1
+        if (!$this->userRole['perm_tagger']) {
+            throw new MethodNotAllowedException(__('This functionality requires tagging permission.'));
+        }
+        $object = $this->Event->fetchEvent($this->Auth->user(), array(
+            'event_uuid' => $object_uuid,
+            'metadata' => 1
         ));
         $type = 'Event';
         if (!empty($object)) {
+            $object = $object[0];
             if (
+                $scope !== 'view' &&
                 !$this->_isSiteAdmin() &&
-                !$this->userRole['perm_tagger'] &&
-                $object['Event']['orgc_id'] != $this->Auth->user('org_id')
+                !$object['Event']['orgc_id'] != $this->Auth->user('org_id')
             ) {
-                throw new MethodNotAllowedException('Invalid Target.');
+                throw new MethodNotAllowedException(__('Invalid Target.'));
             }
         } else {
             $type = 'Attribute';
-            $object = $this->Event->Attribute->find('first', array(
-                'conditions' => array(
-                    'Attribute.uuid' => $object_uuid,
-                ),
-                'fields' => array('Attribute.id'),
-                'recursive' => -1,
-                'contain' => array('Event.orgc_id')
-            ));
+            $object = $this->Event->Attribute->fetchAttributes(
+                $this->Auth->user(),
+                array(
+                    'conditions' => array(
+                        'Attribute.uuid' => $object_uuid
+                    ),
+                    'flatten' => 1
+                )
+            );
             if (!empty($object)) {
-                if (!$this->_isSiteAdmin() && !$this->userRole['perm_tagger'] && $object['Event']['orgc_id'] != $this->Auth->user('org_id')) {
-                    throw new MethodNotAllowedException('Invalid Target.');
+                $object = $object[0];
+                if (
+                    $scope !== 'view' &&
+                    !$this->_isSiteAdmin() &&
+                    !$object['Event']['orgc_id'] != $this->Auth->user('org_id')
+                ) {
+                    throw new MethodNotAllowedException(__('Invalid Target.'));
                 }
             } else {
-                throw new MethodNotAllowedException('Invalid Target.');
+                throw new MethodNotAllowedException(__('Invalid Target.'));
             }
         }
         return $object;
     }
 
@@ -930,15 +937,15 @@ class TagsController extends AppController
         if (empty($local)) {
             if (!empty($this->request->data['local'])) {
                 $local = $this->request->data['local'];
             }
         }
-        if (!is_bool($local)) {
-            throw new InvalidArgumentException('Invalid local flag');
+        if (!empty($local) && $this->Auth->user('org_id') != Configure::read('MISP.host_org_id')) {
+            throw new MethodNotAllowedException(__('Local tags can only be added by users of the host organisation.'));
         }
         $objectType = '';
-        $object = $this->__findObjectByUuid($uuid, $objectType);
+        $object = $this->__findObjectByUuid($uuid, $objectType, $local ? 'view' : 'modify');
         $existingTag = $this->Tag->find('first', array('conditions' => $conditions, 'recursive' => -1));
         if (empty($existingTag)) {
             if (!is_numeric($tag)) {
                 if (!$this->userRole['perm_tag_editor']) {
                     throw new MethodNotAllowedException('Tag not found and insufficient privileges to create it.');
@@ -1036,13 +1043,13 @@ class TagsController extends AppController
         $existingTag = $this->Tag->find('first', array('conditions' => $conditions, 'recursive' => -1));
         if (empty($existingTag)) {
             throw new MethodNotAllowedException('Invalid Tag.');
         }
         $objectType = '';
-        $object = $this->__findObjectByUuid($uuid, $objectType);
+        $object = $this->__findObjectByUuid($uuid, $objectType, 'view');
         if (empty($object)) {
-            throw new MethodNotAllowedException('Invalid Target.');
+            throw new MethodNotAllowedException(__('Invalid Target.'));
         }
         $connectorObject = $objectType . 'Tag';
         $this->loadModel($objectType);
         $existingAssociation = $this->$objectType->$connectorObject->find('first', array(
             'conditions' => array(
@@ -1050,10 +1057,18 @@ class TagsController extends AppController
                 'tag_id' => $existingTag['Tag']['id']
             )
         ));
         if (empty($existingAssociation)) {
             throw new MethodNotAllowedException('Could not remove tag as it is not attached to the target ' . $objectType);
+        } else {
+            if (empty($existingAssociation[$objectType . 'Tag']['local'])) {
+                $object = $this->__findObjectByUuid($uuid, $objectType);
+            } else {
+                if ($object['Event']['orgc_id'] !== $this->Auth->user('org_id') && $this->Auth->user('org_id') != Configure::read('MISP.host_org_id')) {
+                    throw new MethodNotAllowedException(__('Insufficient privileges to remove local tags from events you do not own.'));
+                }
+            }
         }
         $result = $this->$objectType->$connectorObject->delete($existingAssociation[$connectorObject]['id']);
         if ($result) {
             $message = 'Tag ' . $existingTag['Tag']['name'] . '(' . $existingTag['Tag']['id'] . ') successfully removed from ' . $objectType . '(' . $object[$objectType]['id'] . ').';
             return $this->RestResponse->saveSuccessResponse('Tags', 'removeTagFromObject', false, $this->response->type(), $message);

Vulnerable code:     private function __findObjectByUuid($object_uuid, &$type)
        $object = $this->Event->find('first', array(
            'conditions' => array(
                'Event.uuid' => $object_uuid,
            ),
            'fields' => array('Event.orgc_id', 'Event.id'),
            'recursive' => -1
                !$this->userRole['perm_tagger'] &&
                $object['Event']['orgc_id'] != $this->Auth->user('org_id')
                throw new MethodNotAllowedException('Invalid Target.');
            $object = $this->Event->Attribute->find('first', array(
                'conditions' => array(
                    'Attribute.uuid' => $object_uuid,
                ),
                'fields' => array('Attribute.id'),
                'recursive' => -1,
                'contain' => array('Event.orgc_id')
            ));
                if (!$this->_isSiteAdmin() && !$this->userRole['perm_tagger'] && $object['Event']['orgc_id'] != $this->Auth->user('org_id')) {
                    throw new MethodNotAllowedException('Invalid Target.');
                throw new MethodNotAllowedException('Invalid Target.');
        if (!is_bool($local)) {
            throw new InvalidArgumentException('Invalid local flag');
        $object = $this->__findObjectByUuid($uuid, $objectType);
        $object = $this->__findObjectByUuid($uuid, $objectType);
            throw new MethodNotAllowedException('Invalid Target.');
Fixed code:     private function __findObjectByUuid($object_uuid, &$type, $scope = 'modify')
        if (!$this->userRole['perm_tagger']) {
            throw new MethodNotAllowedException(__('This functionality requires tagging permission.'));
        }
        $object = $this->Event->fetchEvent($this->Auth->user(), array(
            'event_uuid' => $object_uuid,
            'metadata' => 1
            $object = $object[0];
                $scope !== 'view' &&
                !$object['Event']['orgc_id'] != $this->Auth->user('org_id')
                throw new MethodNotAllowedException(__('Invalid Target.'));
            $object = $this->Event->Attribute->fetchAttributes(
                $this->Auth->user(),
                array(
                    'conditions' => array(
                        'Attribute.uuid' => $object_uuid
                    ),
                    'flatten' => 1
                )
            );
                $object = $object[0];
                if (
                    $scope !== 'view' &&
                    !$this->_isSiteAdmin() &&
                    !$object['Event']['orgc_id'] != $this->Auth->user('org_id')
                ) {
                    throw new MethodNotAllowedException(__('Invalid Target.'));
                throw new MethodNotAllowedException(__('Invalid Target.'));
        if (!empty($local) && $this->Auth->user('org_id') != Configure::read('MISP.host_org_id')) {
            throw new MethodNotAllowedException(__('Local tags can only be added by users of the host organisation.'));
        $object = $this->__findObjectByUuid($uuid, $objectType, $local ? 'view' : 'modify');
        $object = $this->__findObjectByUuid($uuid, $objectType, 'view');
            throw new MethodNotAllowedException(__('Invalid Target.'));
        } else {
            if (empty($existingAssociation[$objectType . 'Tag']['local'])) {
                $object = $this->__findObjectByUuid($uuid, $objectType);
            } else {
                if ($object['Event']['orgc_id'] !== $this->Auth->user('org_id') && $this->Auth->user('org_id') != Configure::read('MISP.host_org_id')) {
                    throw new MethodNotAllowedException(__('Insufficient privileges to remove local tags from events you do not own.'));
                }
            }