VYPR
Medium severity5.0NVD Advisory· Published Sep 15, 2025· Updated Apr 15, 2026

CVE-2025-59397

CVE-2025-59397

Description

Open Web Analytics (OWA) before 1.8.1 allows owa_db.php v[value] SQL injection.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Open Web Analytics (OWA) before 1.8.1 contains a SQL injection vulnerability in owa_db.php via unsanitized v[value] parameter.

Vulnerability

Overview

Open Web Analytics (OWA) versions prior to 1.8.1 are vulnerable to SQL injection in the owa_db.php file. The flaw resides in the _makeConstraintClause function, specifically in the handling of the v[value] parameter when using the =@ and !@ operators for query constraints. The vulnerable code directly concatenates user-supplied input into SQL statements via sprintf("LOCATE('%s', %s) > 0", $v['value'], ...), without proper sanitization [1][2].

Exploitation

Details

An attacker with a low-privileged account can craft a malicious v[value] parameter, which is not sanitized before being inserted into the SQL query. The vulnerability is exploitable through the query builder functionality that processes these operators. No special network position is required beyond authenticated access to the OWA application [2][3]. The attack surface is the web interface that accepts the vulnerable parameters.

Impact

Successful exploitation allows an attacker to execute arbitrary SQL queries against the underlying database. This could lead to unauthorized read access to sensitive analytics data, including potentially user information. The CVSS v3.1 score is 5.0 (Medium), with vector AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N indicating high confidentiality impact but no integrity or availability impact [1][2].

Mitigation

The vulnerability is fixed in OWA version 1.8.1. The patch (commit 1e5531522acb8f145627c9feb0175cf8a66561ba) adds sanitization for the v[value] parameter by applying the prepare() method to user-controlled values in the affected code paths [4]. Users are strongly advised to upgrade to OWA 1.8.1 or later to mitigate the risk.

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
open-web-analytics/open-web-analyticsPackagist
< 1.8.11.8.1

Affected products

1

Patches

2
8c5943a27496

Updating version string.

2 files changed · +2 2
  • owa_env.php+1 1 modified
    @@ -42,7 +42,7 @@
     define('OWA_PLUGIN_DIR', OWA_DIR.'plugins/');
     define('OWA_CONF_DIR', OWA_DIR.'conf/');
     define('OWA_THEMES_DIR', OWA_DIR.'themes/');
    -define('OWA_VERSION', 'master');
    +define('OWA_VERSION', '1.8.1');
     define('OWA_VENDOR_DIR', OWA_DIR.'vendor/');
     
     if ( file_exists( OWA_VENDOR_DIR . 'autoload.php' ) ) {
    
  • package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "owa",
    -  "version": "1.0.0",
    +  "version": "1.8.1",
       "description": "Open Web Analytics is an open source alternative to commercial web analytics tools such as Google Analytics. This software allows you to stay in control of the data you collect about the user of your websites or applications.",
       "main": "index.js",
       "scripts": {
    
1e5531522acb

adding sanitization

3 files changed · +54 16
  • modules/base/classes/sanitize.php+40 2 modified
    @@ -90,6 +90,43 @@ public static function escapeForDisplay($string, $encoding = 'UTF-8', $quotes =
             }
         }
     
    +    /**
    +     * Strip SQL keywords and punctuation to prevent SQL injection.
    +     *
    +     * @param string $input String to sanitize
    +     * @return string Sanitized string
    +     * @access public
    +     * @static
    +     */
    +    public static function stripSql( $input = '' ) {
    +   
    +        if ( ! $input ) {
    +            return $input;
    +        }
    +    
    +        // Decode any encoded characters to reveal obfuscated SQL keywords.
    +        $decoded = urldecode( $input );
    +        $decoded = html_entity_decode( $decoded, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
    +       
    +        // Remove common SQL command keywords.
    +        $sql_keywords = array(
    +            'select', 'insert', 'update', 'delete', 'drop', 'union', 'create',
    +            'alter', 'truncate', 'replace', 'merge', 'call', 'exec'
    +        );
    +        $pattern = '/\\b(' . implode( '|', $sql_keywords ) . ')\\b/i';
    +        $decoded = preg_replace( $pattern, '', $decoded );
    +        
    +        // Remove commas and parentheses except for our allowed values.
    +        $allowed_values = ['(not set)', '(unknown)'];
    +        if ( ! in_array( $input, $allowed_values ) ) {
    +            $decoded = str_replace( array( ',', '(', ')' ), '', $decoded );              
    +        }
    +        
    +        // Remove any encoded commas or parentheses that may remain.
    +        $decoded = preg_replace( '/%2C|%28|%29|&#40;|&#41;|&#44;/i', '', $decoded );
    +    
    +        return $decoded;
    +    }
     
         /**
          * Strip Whitespace
    @@ -327,8 +364,9 @@ public static function cleanUrl( $url ) {
                     'backslash'     => false
                 )
             );
    -
    -        return trim(str_replace('&amp;', '&', $url));
    +        if ( $url ){
    +            return trim(str_replace('&amp;', '&', $url));
    +        }
         }
     
         public static function cleanUserId ( $user_id ) {
    
  • owa_db.php+13 13 modified
    @@ -17,7 +17,7 @@
     //
     
     require_once(OWA_BASE_DIR.'/owa_base.php');
    -
    +require_once(OWA_BASE_CLASS_DIR.'sanitize.php');
     /**
      * Database Connection Class
      * 
    @@ -443,7 +443,7 @@ function generateSelectQuerySql() {
                 // Add as
                 if (!empty($v['as'])):
     
    -                $cols .= ' as '.$v['as'];
    +                $cols .= ' as '.$this->prepare( $v['as']);
     
                 endif;
     
    @@ -503,7 +503,7 @@ function _updateQuery() {
     
                 endif;
     
    -            $set .= $v['name'] .' = \'' . $this->prepare($v['value']) . '\'';
    +            $set .= $this->prepare( $v['name'] ) .' = \'' . $this->prepare($v['value']) . '\'';
     
                 $i++;
             }
    @@ -574,35 +574,35 @@ function _makeConstraintClause( $type, $params ) {
                 $constraint = $type.' ';
     
                 foreach ($params as $k => $v) {
    -
    +                owa_coreAPI::debug($v);
                     switch (strtolower($v['operator'])) {
    -
    +                
                         case '==':
    -                        $constraint .= sprintf("%s = '%s'",$v['name'], $this->prepare( $v['value'] ) );
    +                        $constraint .= sprintf("%s = '%s'", $this->prepare( $v['name'] ), $this->prepare( $v['value'] ) );
                             break;
     
                         case 'between':
    -                        $constraint .= sprintf("%s BETWEEN '%s' AND '%s'", $v['name'], $this->prepare( $v['value']['start'] ), $this->prepare( $v['value']['end'] ) );
    +                        $constraint .= sprintf("%s BETWEEN '%s' AND '%s'", $this->prepare( $v['name'] ), $this->prepare( $v['value']['start'] ), $this->prepare( $v['value']['end'] ) );
                             break;
     
                         case '=~':
    -                        $constraint .= sprintf("%s %s '%s'",$v['name'], OWA_SQL_REGEXP, $this->prepare( $v['value'] ) );
    +                        $constraint .= sprintf("%s %s '%s'", $this->prepare( $v['name'] ), OWA_SQL_REGEXP, $this->prepare( $v['value'] ) );
                             break;
     
                         case '!~':
    -                        $constraint .= sprintf("%s %s '%s'",$v['name'], OWA_SQL_NOTREGEXP, $this->prepare( $v['value'] ) );
    +                        $constraint .= sprintf("%s %s '%s'",$this->prepare( $v['name'] ), OWA_SQL_NOTREGEXP, $this->prepare( $v['value'] ) );
                             break;
     
                         case '=@':
    -                        $constraint .= sprintf("LOCATE('%s', %s) > 0",$v['value'], $this->prepare( $v['name'] ) );
    +                        $constraint .= sprintf("LOCATE('%s', %s) > 0",$this->prepare( $v['value'] ), $this->prepare( $v['name'] ) );
                             break;
     
                         case '!@':
    -                        $constraint .= sprintf("LOCATE('%s', %s) = 0",$v['value'], $this->prepare( $v['name'] ) );
    +                        $constraint .= sprintf("LOCATE('%s', %s) = 0",$this->prepare( $v['value'] ), $this->prepare( $v['name'] ) );
                             break;
     
                         default:
    -                        $constraint .= sprintf("%s %s '%s'",$v['name'], $v['operator'], $this->prepare( $v['value'] ) );
    +                        $constraint .= sprintf("%s %s '%s'",$this->prepare( $v['name'] ), $v['operator'], $this->prepare( $v['value'] ) );
                             break;
                     }
     
    @@ -641,7 +641,7 @@ function join($type, $table, $as, $foreign_key, $primary_key = '') {
     
         function prepare ( $string ) {
     
    -        return $string;
    +        return owa_sanitize::stripSql( $string );
         }
     
         function _makeJoinClause() {
    
  • plugins/db/owa_db_mysql.php+1 1 modified
    @@ -297,7 +297,7 @@ function prepare( $string ) {
             if(is_null($string)){
                 return $string;
             }
    -
    +        $string = owa_sanitize::stripSql( $string );
             if ($this->connection_status == false) {
                   $this->connect();
               }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.