CVE-2023-41886 (published 2023-09-15T21:15Z)

OpenRefine is a powerful free, open source tool for working with messy data. Prior to version 3.7.5, an arbitrary file read vulnerability allows any unauthenticated user to read a file on a server. Version 3.7.5 fixes this issue.

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-89
cwe_name: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/OpenRefine/OpenRefine
commit_details: repo_url: https://github.com/OpenRefine/OpenRefine
author: Antonin Delpeuch
author_date: 2023-09-12 08:34:13+02:00
msg: Merge pull request from GHSA-qqh2-wvmv-h72m
repository: repo_url: https://github.com/OpenRefine/OpenRefine
repo_name: OpenRefine/OpenRefine
description: OpenRefine is a free, open source power tool for working with messy data and improving it
repo_language: Java
owner: OpenRefine
file_changes: filename: DatabaseConfiguration.java
change_type: ModificationType.MODIFY
diff: @@ -29,6 +29,9 @@
 
 package com.google.refine.extension.database;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
 public class DatabaseConfiguration {
 
     private String connectionName;
@@ -123,4 +126,17 @@ public class DatabaseConfiguration {
                 + databaseSchema + ", useSSL=" + useSSL + "]";
     }
 
+    public URI toURI() {
+        try {
+            return new URI(
+                    "jdbc:" + databaseType.toLowerCase(),
+                    databaseHost + ((databasePort == 0) ? "" : (":" + databasePort)),
+                    "/" + databaseName,
+                    useSSL ? "useSSL=true" : null,
+                    null
+            );
+        } catch (URISyntaxException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
 }

programming_language: Java
filename: MariaDBConnectionManager.java
change_type: ModificationType.MODIFY
diff: @@ -134,7 +134,7 @@ public class MariaDBConnectionManager {
 
             Class.forName(type.getClassPath());
             DriverManager.setLoginTimeout(10);
-            String dbURL = getDatabaseUrl(databaseConfiguration);
+            String dbURL = databaseConfiguration.toURI().toString();
             connection = DriverManager.getConnection(dbURL, databaseConfiguration.getDatabaseUser(),
                     databaseConfiguration.getDatabasePassword());
 
@@ -162,14 +162,6 @@ public class MariaDBConnectionManager {
                 logger.warn("Non-Managed connection could not be closed. Whoops!", e);
             }
         }
-
     }
 
-    private static String getDatabaseUrl(DatabaseConfiguration dbConfig) {
-
-        int port = dbConfig.getDatabasePort();
-        return "jdbc:" + dbConfig.getDatabaseType().toLowerCase() + "://" + dbConfig.getDatabaseHost()
-                + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName();
-
-    }
 }

programming_language: Java
filename: MySQLConnectionManager.java
change_type: ModificationType.MODIFY
diff: @@ -129,7 +129,7 @@ public class MySQLConnectionManager {
                     return connection;
                 }
             }
-            String dbURL = getDatabaseUrl(databaseConfiguration);
+            String dbURL = databaseConfiguration.toURI().toString();
             Class.forName(type.getClassPath());
 
             // logger.info("*** type.getClassPath() ::{}, {}**** ", type.getClassPath());
@@ -166,11 +166,4 @@ public class MySQLConnectionManager {
 
     }
 
-    private String getDatabaseUrl(DatabaseConfiguration dbConfig) {
-
-        int port = dbConfig.getDatabasePort();
-        return "jdbc:" + dbConfig.getDatabaseType() + "://" + dbConfig.getDatabaseHost()
-                + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName() + "?useSSL=" + dbConfig.isUseSSL();
-
-    }
 }

programming_language: Java
filename: PgSQLConnectionManager.java
change_type: ModificationType.MODIFY
diff: @@ -136,7 +136,7 @@ public class PgSQLConnectionManager {
 
             Class.forName(type.getClassPath());
             DriverManager.setLoginTimeout(10);
-            String dbURL = getDatabaseUrl(databaseConfiguration);
+            String dbURL = databaseConfiguration.toURI().toString();
             connection = DriverManager.getConnection(dbURL, databaseConfiguration.getDatabaseUser(),
                     databaseConfiguration.getDatabasePassword());
 
@@ -165,11 +165,4 @@ public class PgSQLConnectionManager {
 
     }
 
-    private static String getDatabaseUrl(DatabaseConfiguration dbConfig) {
-
-        int port = dbConfig.getDatabasePort();
-        return "jdbc:" + dbConfig.getDatabaseType().toLowerCase() + "://" + dbConfig.getDatabaseHost()
-                + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName();
-
-    }
 }

programming_language: Java
filename: SQLiteConnectionManager.java
change_type: ModificationType.MODIFY
diff: @@ -35,6 +35,8 @@ import com.google.refine.extension.database.SQLType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
@@ -66,7 +68,12 @@ public class SQLiteConnectionManager {
     }
 
     public static String getDatabaseUrl(DatabaseConfiguration dbConfig) {
-        return "jdbc:" + dbConfig.getDatabaseType().toLowerCase() + ":" + dbConfig.getDatabaseName();
+        try {
+            URI uri = new URI("jdbc:" + dbConfig.getDatabaseType().toLowerCase(), dbConfig.getDatabaseName(), null);
+            return uri.toASCIIString();
+        } catch (URISyntaxException e) {
+            throw new IllegalArgumentException(e);
+        }
     }
 
     /**

programming_language: Java
filename: DatabaseConfigurationTest.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,21 @@
+package com.google.refine.extension.database;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+public class DatabaseConfigurationTest {
+
+    @Test
+    public void testToURI() {
+        DatabaseConfiguration config = new DatabaseConfiguration();
+        config.setDatabaseType("mysql");
+        config.setDatabaseHost("my.host");
+        // maliciously crafted database name which attempts to enable local file reads for an exploit
+        config.setDatabaseName("test?allowLoadLocalInfile=true#");
+
+        String url = config.toURI().toString();
+        // the database name is escaped, preventing the exploit
+        assertEquals(url, "jdbc:mysql://my.host/test%3FallowLoadLocalInfile=true%23");
+    }
+}

programming_language: Java