CVE-2016-4069 (PHP, published 2016-08-25T18:59Z)
Description: value: Cross-site request forgery (CSRF) vulnerability in Roundcube Webmail before 1.1.5 allows remote attackers to hijack the authentication of users for requests that download attachments and cause a denial of service (disk consumption) via unspecified vectors.
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/roundcube/roundcubemail
Files changed:
plugins/enigma/enigma.js
plugins/enigma/lib/enigma_ui.php
plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php
plugins/managesieve/managesieve.js
plugins/zipdownload/zipdownload.js
plugins/zipdownload/zipdownload.php
program/include/rcmail.php
program/include/rcmail_output_html.php
program/js/app.js
program/lib/Roundcube/rcube_message.php
program/lib/Roundcube/rcube_output.php
program/steps/addressbook/export.inc
program/steps/mail/get.inc
program/steps/mail/viewsource.inc
Commit message: Protect download urls against CSRF using unique request tokens (#1490642)
Send X-Frame-Options headers with every HTTP response


Vulnerable code:
    this.goto_url('plugin.enigmakeys', {_a: 'export', _keys: keys});
  location.href = this.env.comm_path+'&_action=plugin.managesieve-action&_act=setget&_set='+urlencode(script);
        rcmail.goto_url('viewsource', rcmail.params_from_uid(uid, {_save: 1}));
            ));
        // send clickjacking protection headers
        if (!headers_sent() && ($xframe = $this->app->config->get('x_frame_options', 'sameorigin'))) {
            header('X-Frame-Options: ' . ($iframe && $xframe == 'deny' ? 'sameorigin' : $xframe));
        this.goto_url('get', qstring+'&_download=1', false);
          location.href = location.href.replace(/_frame=/, '_download=');
          this.goto_url('viewsource', this.params_from_uid(uid, {_save: 1}));
          this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _search: this.env.search_request });
          this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _cid: this.contact_list.get_selection().join(',') });
      url += '&_token=' + this.env.request_token;
  this.goto_url = function(action, query, lock)
    this.redirect(this.url(action, query), lock);
                    'uid'    => $uid))

Fixed code:
    this.goto_url('plugin.enigmakeys', {_a: 'export', _keys: keys}, false, true);
        $this->rc->request_security_check(rcube_utils::INPUT_GET);

                $this->rc->request_security_check(rcube_utils::INPUT_GET);

  this.goto_url('plugin.managesieve-action', {_act: 'setget', _set: script}, false, true);
        rcmail.goto_url('viewsource', rcmail.params_from_uid(uid, {_save: 1}), false, true);
            ), false, false, true);

        // require CSRF protected request
        $rcmail->request_security_check(rcube_utils::INPUT_GET);

        else if ($secure && ($token = $this->get_request_token()))
            $url .= $delm . '_token=' . urlencode($token);
        // allow (legal) iframe content to be loaded
        if (!headers_sent() && $iframe && $this->app->config->get('x_frame_options', 'sameorigin') === 'deny') {
            header('X-Frame-Options: sameorigin', true);
        this.goto_url('get', qstring+'&_download=1', false, true);
          location.href = this.secure_url(location.href.replace(/_frame=/, '_download='));
          this.goto_url('viewsource', this.params_from_uid(uid, {_save: 1}), false, true);
          this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _search: this.env.search_request }, false, true);
          this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _cid: this.contact_list.get_selection().join(',') }, false, true);
      url = this.secure_url(url);
  // append CSRF protection token to the given url
  this.secure_url = function(url)
  {
    return this.add_url(url, '_token', this.env.request_token);
  },

  this.goto_url = function(action, query, lock, secure)
    var url = this.url(action, query)
    if (secure) url = this.secure_url(url);
    this.redirect(url, lock);
                    'uid'    => $uid),
                false, false, true)

        // send CSRF and clickjacking protection headers
        if ($xframe = $this->app->config->get('x_frame_options', 'sameorigin')) {
            header('X-Frame-Options: ' . $xframe);
        }
$RCMAIL->request_security_check(rcube_utils::INPUT_GET);

        // require CSRF protected url for downloads
        if ($plugin['download'])
            $RCMAIL->request_security_check(rcube_utils::INPUT_GET);

if (!empty($_GET['_save'])) {
    $RCMAIL->request_security_check(rcube_utils::INPUT_GET);
}