CVE-2017-15200 (PHP, published 2017-10-11T01:32Z)
Description: value: In Kanboard before 1.0.47, by altering form data, an authenticated user can add a new task to a private project of another user.
Severity: MEDIUM (CVSS v3 base score: 4.3)
Weakness: CWE-639 \u2014 Authorization Bypass Through User-Controlled Key
The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.
Repository: https://github.com/kanboard/kanboard
Files changed:
ChangeLog
app/Controller/ActionController.php
app/Controller/ActionCreationController.php
app/Controller/BaseController.php
app/Controller/CategoryController.php
app/Controller/ColumnController.php
app/Controller/CustomFilterController.php
app/Controller/ProjectEditController.php
app/Controller/ProjectTagController.php
app/Controller/SwimlaneController.php
app/Controller/TaskCreationController.php
app/Template/action_creation/create.php
app/Template/action_creation/event.php
app/Template/action_creation/params.php
app/Template/category/create.php
app/Template/category/edit.php
app/Template/column/create.php
app/Template/column/edit.php
app/Template/custom_filter/create.php
app/Template/custom_filter/edit.php
app/Template/project_edit/show.php
app/Template/project_tag/create.php
app/Template/project_tag/edit.php
app/Template/swimlane/create.php
app/Template/swimlane/edit.php
app/Template/task_creation/show.php
Commit message: Avoid people to alter other projects by changing form data


Vulnerable code:
            'action' => $this->actionModel->getById($this->request->getIntegerParam('action_id')),
        $action = $this->actionModel->getById($this->request->getIntegerParam('action_id'));
        if (empty($values['action_name']) || empty($values['project_id'])) {
        if (empty($values['action_name']) || empty($values['project_id']) || empty($values['event_name'])) {
    /**
     * Get the category (common method between actions)
     *
     * @access private
     * @return array
     * @throws PageNotFoundException
     */
    private function getCategory()
    {
        $category = $this->categoryModel->getById($this->request->getIntegerParam('category_id'));

        if (empty($category)) {
            throw new PageNotFoundException();
        }

        return $category;
    }


        $category = $this->getCategory();
        $category = $this->getCategory();
        $category = $this->getCategory();
        $column = $this->columnModel->getById($this->request->getIntegerParam('column_id'));
            'column' => $this->columnModel->getById($this->request->getIntegerParam('column_id')),
        $project = $this->getProject();
        $column_id = $this->request->getIntegerParam('column_id');
        if ($this->columnModel->remove($column_id)) {
        $filter = $this->customFilterModel->getById($this->request->getIntegerParam('filter_id'));
        $filter = $this->customFilterModel->getById($this->request->getIntegerParam('filter_id'));
use Kanboard\Core\Controller\AccessForbiddenException;

        if (empty($values)) {
            $values['project_id'] = $project['id'];
        }

        $tag_id = $this->request->getIntegerParam('tag_id');
        $tag = $this->tagModel->getById($tag_id);
        $tag_id = $this->request->getIntegerParam('tag_id');
        $tag = $this->tagModel->getById($tag_id);
        list($valid, $errors) = $this->tagValidator->validateModification($values);
        if ($tag['project_id'] != $project['id']) {
            throw new AccessForbiddenException();
        }
        $tag_id = $this->request->getIntegerParam('tag_id');
        $tag = $this->tagModel->getById($tag_id);
        $tag_id = $this->request->getIntegerParam('tag_id');
        $tag = $this->tagModel->getById($tag_id);

        if ($tag['project_id'] != $project['id']) {
            throw new AccessForbiddenException();
        }
        if ($this->tagModel->remove($tag_id)) {
use Kanboard\Core\Controller\PageNotFoundException;
use Kanboard\Model\SwimlaneModel;
    /**
     * Get the swimlane (common method between actions)
     *
     * @access private
     * @return array
     * @throws PageNotFoundException
     */
    private function getSwimlane()
    {
        $swimlane = $this->swimlaneModel->getById($this->request->getIntegerParam('swimlane_id'));

        if (empty($swimlane)) {
            throw new PageNotFoundException();
        }

        return $swimlane;
    }

        $swimlane = $this->getSwimlane();

        $swimlane = $this->getSwimlane();
        $swimlane_id = $this->request->getIntegerParam('swimlane_id');
        if ($this->swimlaneModel->remove($project['id'], $swimlane_id)) {
        $swimlane_id = $this->request->getIntegerParam('swimlane_id');
        if ($this->swimlaneModel->disable($project['id'], $swimlane_id)) {
        $swimlane_id = $this->request->getIntegerParam('swimlane_id');
        if ($this->swimlaneModel->enable($project['id'], $swimlane_id)) {
    <?= $this->form->hidden('project_id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>
    <?= $this->form->hidden('id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>

    <?= $this->form->hidden('project_id', $values) ?>

    <?= $this->form->hidden('id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>

    <?= $this->form->hidden('project_id', $values) ?>
    <?= $this->form->hidden('id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>
    <?= $this->form->hidden('id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>
    <?= $this->form->hidden('id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>

    <?= $this->form->hidden('project_id', $values) ?>

    <?= $this->form->hidden('id', $values) ?>
    <?= $this->form->hidden('project_id', $values) ?>

    <?= $this->form->hidden('project_id', $values) ?>

Fixed code:
Security Issues:

* Avoid people to alter other project resources by changing form data

        $action = $this->getAction($project);
            'action' => $action,
        $action = $this->getAction($project);
        $values['project_id'] = $project['id'];
        if (empty($values['action_name'])) {
        $values['project_id'] = $project['id'];
        if (empty($values['action_name']) || empty($values['event_name'])) {
        $values['project_id'] = $project['id'];

    protected function getColumn(array $project)
    {
        $column = $this->columnModel->getById($this->request->getIntegerParam('column_id'));

        if (empty($column)) {
            throw new PageNotFoundException();
        }

        if ($column['project_id'] != $project['id']) {
            throw new AccessForbiddenException();
        }

        return $column;
    }

    protected function getSwimlane(array $project)
    {
        $swimlane = $this->swimlaneModel->getById($this->request->getIntegerParam('swimlane_id'));

        if (empty($swimlane)) {
            throw new PageNotFoundException();
        }

        if ($swimlane['project_id'] != $project['id']) {
            throw new AccessForbiddenException();
        }

        return $swimlane;
    }

    protected function getCategory(array $project)
    {
        $category = $this->categoryModel->getById($this->request->getIntegerParam('category_id'));

        if (empty($category)) {
            throw new PageNotFoundException();
        }

        if ($category['project_id'] != $project['id']) {
            throw new AccessForbiddenException();
        }

        return $category;
    }

    protected function getProjectTag(array $project)
    {
        $tag = $this->tagModel->getById($this->request->getIntegerParam('tag_id'));

        if (empty($tag)) {
            throw new PageNotFoundException();
        }

        if ($tag['project_id'] != $project['id']) {
            throw new AccessForbiddenException();
        }

        return $tag;
    }

    protected function getAction(array $project)
    {
        $action = $this->actionModel->getById($this->request->getIntegerParam('action_id'));

        if (empty($action)) {
            throw new PageNotFoundException();
        }

        if ($action['project_id'] != $project['id']) {
            throw new AccessForbiddenException();
        }

        return $action;
    }

    protected function getCustomFilter(array $project)
    {
        $filter = $this->customFilterModel->getById($this->request->getIntegerParam('filter_id'));

        if (empty($filter)) {
            throw new PageNotFoundException();
        }

        if ($filter['project_id'] != $project['id']) {
            throw new AccessForbiddenException();
        }

        return $filter;
    }
        $values['project_id'] = $project['id'];

        $category = $this->getCategory($project);
        $category = $this->getCategory($project);
        $values['project_id'] = $project['id'];
        $values['id'] = $category['id'];

        $category = $this->getCategory($project);
        $category = $this->getCategory($project);
        $values['project_id'] = $project['id'];
        $column = $this->getColumn($project);
        $column = $this->getColumn($project);

        $values['project_id'] = $project['id'];
        $values['id'] = $column['id'];
        $column = $this->getColumn($project);
            'column' => $column,
        $project = $this->getProject();
        $column = $this->getColumn($project);
        if ($this->columnModel->remove($column['id'])) {
        $values['project_id'] = $project['id'];
        $filter = $this->getCustomFilter($project);
        $filter = $this->getCustomFilter($project);
        $values['id'] = $filter['id'];
        $values['project_id'] = $project['id'];
        $values['id'] = $project['id'];

        $values['project_id'] = $project['id'];

        $tag = $this->getProjectTag($project);
        $tag = $this->getProjectTag($project);
        $values['project_id'] = $project['id'];
        $values['id'] = $tag['id'];
        list($valid, $errors) = $this->tagValidator->validateModification($values);
        $tag = $this->getProjectTag($project);
        $tag = $this->getProjectTag($project);
        if ($this->tagModel->remove($tag['id'])) {
        $values['project_id'] = $project['id'];

        $swimlane = $this->getSwimlane($project);
        $swimlane = $this->getSwimlane($project);
        $values['project_id'] = $project['id'];
        $values['id'] = $swimlane['id'];

        $swimlane = $this->getSwimlane($project);
        $swimlane = $this->getSwimlane($project);
        if ($this->swimlaneModel->remove($project['id'], $swimlane['id'])) {
        $swimlane = $this->getSwimlane($project);
        if ($this->swimlaneModel->disable($project['id'], $swimlane['id'])) {
        $swimlane = $this->getSwimlane($project);
        if ($this->swimlaneModel->enable($project['id'], $swimlane['id'])) {
        $values['project_id'] = $project['id'];