CVE-2015-10108 (PHP, published 2023-05-31T19:15Z)
Description: value: A vulnerability was found in meitar Inline Google Spreadsheet Viewer Plugin up to 0.9.6 on WordPress and classified as problematic. Affected by this issue is the function displayShortcode of the file inline-gdocs-viewer.php. The manipulation leads to cross-site request forgery. The attack may be launched remotely. Upgrading to version 0.9.6.1 is able to address this issue. The patch is identified as 2a8057df8ca30adc859cecbe5cad21ac28c5b747. It is recommended to upgrade the affected component. VDB-230234 is the identifier assigned to this vulnerability.
Severity: nan (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/wp-plugins/inline-google-spreadsheet-viewer
Files changed:
inline-gdocs-viewer.php
Commit message: Secure the CSV fetching code behind a WordPress nonce to avoid CSRFs.

git-svn-id: https://plugins.svn.wordpress.org/inline-google-spreadsheet-viewer/trunk@1158277 b8457f37-d9ea-0310-8a92-e5e31aec5664


Vulnerable code:
        $url = plugins_url('vistable-proxy.php', __FILE__);
        $url .= '?url=' . rawurlencode($key);
        $tq = $this->sanitizeQuery($query);
        $url .= "&tq=$tq";
        $url .= "&tqx=out:$format";
        return $url;
            throw new Exception('[' . __('Error requesting data from Google:', 'inline-gdocs-viewer') . $resp->get_error_message() . ']');
                $url = $this->getGVizDataSourceUrl($x['key'], $x['query'], $fmt);
<?php
require_once dirname(__FILE__) . '/lib/vistable.php';

$url = isset($_GET['url']) ? rawurldecode($_GET['url']) : '';
$tqx = isset($_GET['tqx']) ? $_GET['tqx'] : '';
$tq = isset($_GET['tq']) ? $_GET['tq'] : '';
$tqrt = isset($_GET['tqrt']) ? $_GET['tqrt'] : '';
$tz = isset($_GET['tz']) ? $_GET['tz'] : 'PDT';
$locale = isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]) ? $_SERVER["HTTP_ACCEPT_LANGUAGE"] : 'en_US';

if (isset($_GET['locale'])) {
    $locale = $_GET['locale'];
}

$extra = array();
if (isset($_GET['debug']) && $_GET['debug']) {
    header('Content-type: text/plain; charset="UTF-8"');
    $extra['debug'] = 1;
}

$vt = new csv_vistable($tqx, $tq, $tqrt,$tz,$locale,$extra);

$data = file_get_contents($url);

$vt->setup_table($data);

$result = $vt->execute();

print $result;

Fixed code:
        add_action('init', array($this, 'maybeFetchGvizDataSource'));
        $base = trailingslashit(get_site_url()) . '?';
        $qs = 'url=';
        $qs .= rawurlencode($key .  '?tq=' . $this->sanitizeQuery($query) . "&tqx=out:$format");
        return $base . $qs;
            throw new Exception('[' . __('Error requesting data:', 'inline-gdocs-viewer') . ' ' . $resp->get_error_message() . ']');
    public function maybeFetchGvizDataSource () {
        if (
            !isset($_GET[$this->prefix . 'get_datasource_nonce'])
            ||
            !$this->isValidNonce($_GET[$this->prefix . 'get_datasource_nonce'], $this->prefix . 'get_datasource_nonce')
        ) { return; }
        require_once dirname(__FILE__) . '/lib/vistable.php';
        $url = rawurldecode($_GET['url']);
        $http_response = $this->fetchData($url, false);

        $p = parse_url($url);
        $qs = array();
        parse_str($p['query'], $qs);
        $tqx  = (isset($qs['tqx']))  ? $qs['tqx'] : '';
        $tq   = (isset($qs['tq']))   ? $qs['tq']  : '';
        $tqrt = (isset($qs['tqrt'])) ? $qs['tqrt']: '';
        $tz   = (isset($qs['tz']))   ? $qs['tz']  : 'PDT'; // TODO: will get_option('timezone_string') work?
        $vt = new csv_vistable($tqx, $tq, $tqrt, $tz, get_locale(), array());
        $vt->setup_table($http_response['body']);
        print $vt->execute();
        exit;
    }

    private function makeNonceUrl ($url) {
        $options = get_option($this->prefix . 'settings');
        $options[$this->prefix . 'get_datasource_nonce'] = wp_create_nonce($this->prefix . 'get_datasource_nonce');
        update_option($this->prefix . 'settings', $options);
        $p = parse_url($url);
        return $p['scheme']
            . '://' . $p['host'] . $p['path']
            . '?' . $p['query'] . '&'
            . $this->prefix . 'get_datasource_nonce=' . $options[$this->prefix . 'get_datasource_nonce'];
    }

    private function isValidNonce ($nonce, $nonce_name) {
        $options = get_option($this->prefix . 'settings');
        $is_valid = ($nonce === $options[$nonce_name]) ? true : false;
        unset($options[$this->prefix . 'get_datasource_nonce']);
        update_option($this->prefix . 'settings', $options);
        return $is_valid;
    }

                $url = $this->makeNonceUrl($this->getGVizDataSourceUrl($x['key'], $x['query'], $fmt));