[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1116986: bookworm-pu: package openrefine/3.6.2-2+deb12u3



Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: openrefine@packages.debian.org, apo@debian.org
Control: affects -1 + src:openrefine


[ Reason ]

Fixing no-dsa CVE in bookworm. I have backported patches to fix six
CVE in bookworm. The patch for CVE-2024-47879 introduced a regression
which is the reason why it is currently not included. I may follow up
later but the issue is not that severe IMO.

[ Impact ]

OpenRefine in bookworm would continue to be vulnerable.

[ Tests ]

I have tested the update manually and run the maven test suite. I
didn't spot any regressions.


[ Risks ]

Nothing I would be aware of. OpenRefine is a standalone application
and CVE fixes should not affect other software on the user's system.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]

Applied six patches to fix open CVE in bookworm. See also the
openrefine.debdiff.

Thank you
diff -Nru openrefine-3.6.2/debian/changelog openrefine-3.6.2/debian/changelog
--- openrefine-3.6.2/debian/changelog	2023-10-04 15:02:45.000000000 +0200
+++ openrefine-3.6.2/debian/changelog	2025-09-28 00:52:50.000000000 +0200
@@ -1,3 +1,13 @@
+openrefine (3.6.2-2+deb12u3) bookworm; urgency=medium
+
+  * Fix CVE-2024-23833, CVE-2024-47878, CVE-2024-47880, CVE-2024-47881,
+    CVE-2024-47882 and CVE-2024-49760.
+    OpenRefine is a free, open source tool for data processing. Users could be
+    tricked into opening malicious websites which then enabled attackers to run
+    arbitrary code on the server due to improper escaping or code restrictions.
+
+ -- Markus Koschany <apo@debian.org>  Sun, 28 Sep 2025 00:52:50 +0200
+
 openrefine (3.6.2-2+deb12u2) bookworm; urgency=medium
 
   * Fix CVE-2023-41887 and CVE-2023-41886:
diff -Nru openrefine-3.6.2/debian/patches/build.patch openrefine-3.6.2/debian/patches/build.patch
--- openrefine-3.6.2/debian/patches/build.patch	2023-10-04 15:02:45.000000000 +0200
+++ openrefine-3.6.2/debian/patches/build.patch	2025-09-28 00:52:50.000000000 +0200
@@ -7,7 +7,7 @@
  1 file changed, 4 insertions(+)
 
 diff --git a/main/pom.xml b/main/pom.xml
-index c0b409c..27f789d 100644
+index 17b8ddc..4b61428 100644
 --- a/main/pom.xml
 +++ b/main/pom.xml
 @@ -337,6 +337,10 @@
diff -Nru openrefine-3.6.2/debian/patches/CVE-2024-23833.patch openrefine-3.6.2/debian/patches/CVE-2024-23833.patch
--- openrefine-3.6.2/debian/patches/CVE-2024-23833.patch	1970-01-01 01:00:00.000000000 +0100
+++ openrefine-3.6.2/debian/patches/CVE-2024-23833.patch	2025-09-28 00:52:50.000000000 +0200
@@ -0,0 +1,56 @@
+From: Markus Koschany <apo@debian.org>
+Date: Sat, 27 Sep 2025 15:13:00 +0200
+Subject: CVE-2024-23833
+
+Origin: https://github.com/OpenRefine/OpenRefine/commit/41ccf574847d856e22488a7c0987ad8efa12a84a
+Debian-Bug: https://bugs.debian.org/1064192
+---
+ .../refine/extension/database/DatabaseConfiguration.java     |  7 +++++++
+ .../refine/extension/database/DatabaseConfigurationTest.java | 12 ++++++++++++
+ 2 files changed, 19 insertions(+)
+
+diff --git a/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java b/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java
+index 3f0dd57..579ee00 100644
+--- a/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java
++++ b/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java
+@@ -68,6 +68,13 @@ public class DatabaseConfiguration {
+     }
+     
+     public void setDatabaseHost(String databaseServer) {
++        // forbid setting settings inside the host parameter:
++        // https://dev.mysql.com/doc/connector-j/en/connector-j-reference-jdbc-url-format.html
++        if (databaseServer == null ||
++                databaseServer.contains("(") ||
++                databaseServer.contains("=")) {
++            throw new IllegalArgumentException("Invalid host supplied");
++        }
+         this.databaseHost = databaseServer;
+     }
+     
+diff --git a/extensions/database/tests/src/com/google/refine/extension/database/DatabaseConfigurationTest.java b/extensions/database/tests/src/com/google/refine/extension/database/DatabaseConfigurationTest.java
+index 5a571e8..928aeac 100644
+--- a/extensions/database/tests/src/com/google/refine/extension/database/DatabaseConfigurationTest.java
++++ b/extensions/database/tests/src/com/google/refine/extension/database/DatabaseConfigurationTest.java
+@@ -1,5 +1,8 @@
+ package com.google.refine.extension.database;
+ 
++import static org.testng.Assert.assertEquals;
++import static org.testng.Assert.assertThrows;
++
+ import org.testng.annotations.Test;
+ 
+ import static org.testng.Assert.assertEquals;
+@@ -18,4 +21,13 @@ public class DatabaseConfigurationTest {
+         // the database name is escaped, preventing the exploit
+         assertEquals(url, "jdbc:mysql://my.host/test%3FallowLoadLocalInfile=true%23");
+     }
++
++    @Test
++    public void testSetMaliciousHost() {
++        DatabaseConfiguration config = new DatabaseConfiguration();
++        config.setDatabaseType("mysql");
++
++        assertThrows(IllegalArgumentException.class,
++                () -> config.setDatabaseHost("127.0.0.1:3306,(allowLoadLocalInfile=true,allowUrlInLocalInfile=true),127.0.0.1"));
++    }
+ }
diff -Nru openrefine-3.6.2/debian/patches/CVE-2024-47878.patch openrefine-3.6.2/debian/patches/CVE-2024-47878.patch
--- openrefine-3.6.2/debian/patches/CVE-2024-47878.patch	1970-01-01 01:00:00.000000000 +0100
+++ openrefine-3.6.2/debian/patches/CVE-2024-47878.patch	2025-09-28 00:52:50.000000000 +0200
@@ -0,0 +1,156 @@
+From: Markus Koschany <apo@debian.org>
+Date: Sat, 27 Sep 2025 15:15:58 +0200
+Subject: CVE-2024-47878
+
+Origin: https://github.com/OpenRefine/OpenRefine/commit/37b375478eca41b8948b104bf6790ebf659a88cb
+Bug-Debian: https://bugs.debian.org/1086041
+---
+ extensions/gdata/module/MOD-INF/controller.js      | 21 +-----
+ extensions/gdata/module/authorized.vt              |  6 +-
+ .../refine/extension/gdata/AuthorizedCommand.java  | 88 ++++++++++++++++++++++
+ 3 files changed, 94 insertions(+), 21 deletions(-)
+ create mode 100644 extensions/gdata/src/com/google/refine/extension/gdata/AuthorizedCommand.java
+
+diff --git a/extensions/gdata/module/MOD-INF/controller.js b/extensions/gdata/module/MOD-INF/controller.js
+index fc6ff96..549c6be 100644
+--- a/extensions/gdata/module/MOD-INF/controller.js
++++ b/extensions/gdata/module/MOD-INF/controller.js
+@@ -101,23 +101,10 @@ function process(path, request, response) {
+     
+     send(request, response, "authorize.vt", context);
+   } else if (path == "authorized") {
+-    var context = {};
+-    context.state = request.getParameter("state");
+-    
+-    (function() {
+-      if (Packages.com.google.refine.extension.gdata.TokenCookie.getToken(request) !== null) {
+-          return;
+-      }
+-      var tokenAndExpiresInSeconds =  Packages.com.google.refine.extension.gdata.GoogleAPIExtension.getTokenFromCode(module,request);
+-      if (tokenAndExpiresInSeconds) {
+-        var tokenInfo = tokenAndExpiresInSeconds.split(",");
+-        Packages.com.google.refine.extension.gdata.TokenCookie.setToken(request, response, tokenInfo[0], tokenInfo[1]);
+-        return;
+-      }
+-      Packages.com.google.refine.extension.gdata.TokenCookie.deleteToken(request, response);
+-    })();
+-    
+-    send(request, response, "authorized.vt", context);
++    // it's a command but we handle it manually here, so as to preserve the URL
++    var command = new Packages.com.google.refine.extension.gdata.AuthorizedCommand(module);
++    command.doGet(request, response);
++    butterfly.responded();
+   } else if (path == "/" || path == "") {
+       var context = {};
+       context.version = version;
+diff --git a/extensions/gdata/module/authorized.vt b/extensions/gdata/module/authorized.vt
+index 67ed3f5..3c16371 100644
+--- a/extensions/gdata/module/authorized.vt
++++ b/extensions/gdata/module/authorized.vt
+@@ -40,10 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+   <span id="gdata-authorized"></span>
+   
+   <script>
+-    var state = JSON.parse(window.atob("$state"));
+-    
+-    var windowName = state.winname;
+-    var callbackName = state.cb;
++    var windowName = "$winname";
++    var callbackName = "$cb";
+     
+     var w = window.open("", windowName);
+     var callback = w[callbackName];
+diff --git a/extensions/gdata/src/com/google/refine/extension/gdata/AuthorizedCommand.java b/extensions/gdata/src/com/google/refine/extension/gdata/AuthorizedCommand.java
+new file mode 100644
+index 0000000..b3dbb4b
+--- /dev/null
++++ b/extensions/gdata/src/com/google/refine/extension/gdata/AuthorizedCommand.java
+@@ -0,0 +1,88 @@
++
++package com.google.refine.extension.gdata;
++
++import java.io.IOException;
++import java.util.Base64;
++import java.util.regex.Pattern;
++
++import javax.servlet.ServletException;
++import javax.servlet.http.HttpServletRequest;
++import javax.servlet.http.HttpServletResponse;
++
++import com.fasterxml.jackson.databind.JsonNode;
++import com.fasterxml.jackson.databind.node.ObjectNode;
++import edu.mit.simile.butterfly.ButterflyModule;
++import org.apache.velocity.VelocityContext;
++
++import com.google.refine.commands.Command;
++import com.google.refine.util.ParsingUtilities;
++
++public class AuthorizedCommand extends Command {
++
++    Pattern callbackPattern = Pattern.compile("^cb[0-9]+$");
++    Pattern winnamePattern = Pattern.compile("^openrefine[0-9]+$");
++
++    ButterflyModule module;
++
++    public AuthorizedCommand(ButterflyModule module) {
++        this.module = module;
++    }
++
++    @Override
++    public void doGet(HttpServletRequest request, HttpServletResponse response)
++            throws ServletException, IOException {
++        VelocityContext velocityContext = new VelocityContext();
++        String state = request.getParameter("state");
++        if (state == null) {
++            respond(response, "error", "No 'state' parameter provided");
++            return;
++        }
++        try {
++            byte[] decoded = Base64.getDecoder().decode(state);
++            JsonNode parsed = ParsingUtilities.mapper.readTree(decoded);
++            if (parsed instanceof ObjectNode && parsed.has("winname") && parsed.has("cb")) {
++                ObjectNode object = (ObjectNode) parsed;
++                String cb = object.get("cb").asText();
++                String winname = object.get("winname").asText();
++                if (!winnamePattern.matcher(winname).find()) {
++                    respond(response, "error", "Invalid winname provided");
++                    return;
++                }
++                if (!callbackPattern.matcher(cb).find()) {
++                    respond(response, "error", "Invalid callback provided");
++                    return;
++                }
++                velocityContext.internalPut("winname", winname);
++                velocityContext.internalPut("cb", cb);
++
++            } else {
++                throw new IllegalArgumentException("expected a JSON object");
++            }
++        } catch (IllegalArgumentException | IOException e) {
++            respond(response, "error", "Invalid 'state' parameter provided");
++            return;
++        }
++
++        updateToken(request, response);
++
++        try {
++            module.sendTextFromTemplate(request, response, velocityContext, "authorized.vt", "UTF-8", "text/html", false);
++        } catch (Exception e) {
++            respondException(response, e);
++        }
++    }
++
++    private void updateToken(HttpServletRequest request, HttpServletResponse response) throws IOException {
++        if (TokenCookie.getToken(request) != null) {
++            return;
++        }
++        var tokenAndExpiresInSeconds = GoogleAPIExtension.getTokenFromCode(module, request);
++        if (tokenAndExpiresInSeconds != null) {
++            var tokenInfo = tokenAndExpiresInSeconds.split(",");
++            TokenCookie.setToken(request, response, tokenInfo[0], tokenInfo[1]);
++            return;
++        }
++        TokenCookie.deleteToken(request, response);
++    }
++
++}
diff -Nru openrefine-3.6.2/debian/patches/CVE-2024-47880.patch openrefine-3.6.2/debian/patches/CVE-2024-47880.patch
--- openrefine-3.6.2/debian/patches/CVE-2024-47880.patch	1970-01-01 01:00:00.000000000 +0100
+++ openrefine-3.6.2/debian/patches/CVE-2024-47880.patch	2025-09-28 00:52:50.000000000 +0200
@@ -0,0 +1,40 @@
+From: Markus Koschany <apo@debian.org>
+Date: Sat, 27 Sep 2025 15:27:12 +0200
+Subject: CVE-2024-47880
+
+Origin: https://github.com/OpenRefine/OpenRefine/commit/fbf94fe3f001d6e2aa02e890930cf1affb0847b0
+Bug-Debian: https://bugs.debian.org/1086041
+---
+ .../google/refine/commands/project/ExportRowsCommand.java    | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/main/src/com/google/refine/commands/project/ExportRowsCommand.java b/main/src/com/google/refine/commands/project/ExportRowsCommand.java
+index 1912078..78d1f13 100644
+--- a/main/src/com/google/refine/commands/project/ExportRowsCommand.java
++++ b/main/src/com/google/refine/commands/project/ExportRowsCommand.java
+@@ -64,7 +64,8 @@ public class ExportRowsCommand extends Command {
+     private  static final Logger logger = LoggerFactory.getLogger("ExportRowsCommand");
+     
+ 	/**
+-	 * This command uses POST but is left CSRF-unprotected as it does not incur a state change.
++	 * This command uses POST but is left CSRF-unprotected as it does not incur a state change. TODO: add CSRF
++	 * protection anyway, as it does not cost much and could still have prevented an XSS vulnerability
+ 	 */
+ 
+     @SuppressWarnings("unchecked")
+@@ -96,11 +97,10 @@ public class ExportRowsCommand extends Command {
+                 exporter = new CsvExporter('\t');
+             }
+             
+-            String contentType = params.getProperty("contentType");
+-            if (contentType == null) {
+-                contentType = exporter.getContentType();
+-            }
+-            response.setHeader("Content-Type", contentType);
++
++            response.setHeader("Content-Type", exporter.getContentType());
++            // in case the content-type is text/html, to avoid XSS attacks
++            response.setHeader("Content-Security-Policy", "script-src 'none'; connect-src 'none'");
+ 
+             String preview = params.getProperty("preview");
+             if (!"true".equals(preview)) {
diff -Nru openrefine-3.6.2/debian/patches/CVE-2024-47881.patch openrefine-3.6.2/debian/patches/CVE-2024-47881.patch
--- openrefine-3.6.2/debian/patches/CVE-2024-47881.patch	1970-01-01 01:00:00.000000000 +0100
+++ openrefine-3.6.2/debian/patches/CVE-2024-47881.patch	2025-09-28 00:52:50.000000000 +0200
@@ -0,0 +1,181 @@
+From: Markus Koschany <apo@debian.org>
+Date: Sat, 27 Sep 2025 15:59:27 +0200
+Subject: CVE-2024-47881
+
+Origin: https://github.com/OpenRefine/OpenRefine/commit/8a5cced755f9d4544cfc9fd1b9dc9274807b5020
+Bug-Debian: https://bugs.debian.org/1086041
+---
+ .../database/sqlite/SQLiteConnectionManager.java   | 16 ++++++++-
+ extensions/database/tests/conf/tests.xml           |  2 +-
+ .../extension/database/DBExtensionTests.java       |  2 +-
+ .../sqlite/SQLiteConnectionManagerTest.java        | 10 ------
+ .../database/sqlite/SQLiteDatabaseServiceTest.java | 42 +++++++++++++++-------
+ 5 files changed, 47 insertions(+), 25 deletions(-)
+
+diff --git a/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManager.java b/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManager.java
+index 7d42e00..0def4d2 100644
+--- a/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManager.java
++++ b/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManager.java
+@@ -35,6 +35,7 @@ import com.google.refine.extension.database.SQLType;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ 
++import java.io.File;
+ import java.net.URI;
+ import java.net.URISyntaxException;
+ import java.sql.Connection;
+@@ -68,8 +69,21 @@ public class SQLiteConnectionManager {
+     }
+ 
+     public static String getDatabaseUrl(DatabaseConfiguration dbConfig) {
++        String dbPath = dbConfig.getDatabaseName();
++        if (dbPath.contains("?")) {
++            throw new IllegalArgumentException("Paths to SQLite databases are not allowed to contain '?'");
++        }
++        if (dbPath.startsWith("//") || dbPath.startsWith("\\\\") || dbPath.startsWith("\\/") || dbPath.startsWith("/\\")) {
++            throw new IllegalArgumentException("File path starts with illegal prefix; only local files are accepted.");
++        }
++        if (!new File(dbPath).isFile()) {
++            throw new IllegalArgumentException("File could not be read: " + dbPath);
++        }
+         try {
+-            URI uri = new URI("jdbc:" + dbConfig.getDatabaseType().toLowerCase(), dbConfig.getDatabaseName(), null);
++            URI uri = new URI(
++                    "jdbc:" + dbConfig.getDatabaseType().toLowerCase(),
++                    dbPath + "?open_mode=1&limit_attached=0", // open_mode=1 means read-only
++                    null);
+             return uri.toASCIIString();
+         } catch (URISyntaxException e) {
+             throw new IllegalArgumentException(e);
+diff --git a/extensions/database/tests/conf/tests.xml b/extensions/database/tests/conf/tests.xml
+index 7885174..a0910c9 100644
+--- a/extensions/database/tests/conf/tests.xml
++++ b/extensions/database/tests/conf/tests.xml
+@@ -29,7 +29,7 @@
+     <parameter name = "mariadbDbPassword" value=""/>
+     <parameter name = "mariadbTestTable" value="test_table"/>
+ 
+-    <parameter name = "sqliteDbName" value="extension_test_db.sqlite"/>
++    <parameter name = "sqliteDbName" value="tests/resources/test_db.sqlite"/>
+     <parameter name = "sqliteDbHost" value=""/>
+     <parameter name = "sqliteDbPort" value=""/>
+     <parameter name = "sqliteDbUser" value=""/>
+diff --git a/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTests.java b/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTests.java
+index bd1d0bc..a98f55a 100644
+--- a/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTests.java
++++ b/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTests.java
+@@ -61,7 +61,7 @@ public class DBExtensionTests {
+     protected final String DEFAULT_MARIADB_NAME = "testdb";
+ 
+     protected final String SQLITE_DB_NAME = "sqlite";
+-    protected final String DEFAULT_SQLITE_DB_NAME = "extension_test_db.sqlite";
++    protected final String DEFAULT_SQLITE_DB_NAME = "tests/resources/test_db.sqlite";
+ 
+     protected final String DEFAULT_TEST_TABLE = "test_data";
+ 
+diff --git a/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManagerTest.java b/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManagerTest.java
+index 2daf059..5afcdcb 100644
+--- a/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManagerTest.java
++++ b/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManagerTest.java
+@@ -37,7 +37,6 @@ import org.mockito.MockitoAnnotations;
+ import org.testng.Assert;
+ import org.testng.annotations.*;
+ 
+-import java.io.File;
+ import java.sql.Connection;
+ import java.sql.SQLException;
+ 
+@@ -61,15 +60,6 @@ public class SQLiteConnectionManagerTest extends DBExtensionTests {
+         DatabaseService.DBType.registerDatabase(SQLiteDatabaseService.DB_NAME, SQLiteDatabaseService.getInstance());
+     }
+ 
+-    @AfterTest
+-    @Parameters({ "sqliteDbName" })
+-    public void afterTest(@Optional(DEFAULT_SQLITE_DB_NAME) String sqliteDbName) {
+-        File f = new File(sqliteDbName);
+-        if (f.exists()) {
+-            f.delete();
+-        }
+-    }
+-
+     @Test
+     public void testTestConnection() throws DatabaseServiceException {
+         boolean isConnected = SQLiteConnectionManager.getInstance().testConnection(testDbConfig);
+diff --git a/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseServiceTest.java b/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseServiceTest.java
+index c29cc82..cd6f244 100644
+--- a/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseServiceTest.java
++++ b/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseServiceTest.java
+@@ -37,7 +37,6 @@ import org.mockito.MockitoAnnotations;
+ import org.testng.Assert;
+ import org.testng.annotations.*;
+ 
+-import java.io.File;
+ import java.sql.Connection;
+ import java.sql.SQLException;
+ import java.util.List;
+@@ -60,20 +59,10 @@ public class SQLiteDatabaseServiceTest extends DBExtensionTests {
+         testDbConfig.setDatabaseType(SQLiteDatabaseService.DB_NAME);
+ 
+         testTable = sqliteTestTable;
+-        DBExtensionTestUtils.initTestData(testDbConfig, sqliteTestTable);
+ 
+         DatabaseService.DBType.registerDatabase(SQLiteDatabaseService.DB_NAME, SQLiteDatabaseService.getInstance());
+     }
+ 
+-    @AfterTest
+-    @Parameters({ "sqliteDbName" })
+-    public void afterTest(@Optional(DEFAULT_SQLITE_DB_NAME) String sqliteDbName) {
+-        File f = new File(sqliteDbName);
+-        if (f.exists()) {
+-            f.delete();
+-        }
+-    }
+-
+     @Test
+     public void testGetDatabaseUrl() {
+         SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService
+@@ -81,7 +70,7 @@ public class SQLiteDatabaseServiceTest extends DBExtensionTests {
+         String dbUrl = sqLiteDatabaseService.getDatabaseUrl(testDbConfig);
+ 
+         Assert.assertNotNull(dbUrl);
+-        Assert.assertEquals(dbUrl, "jdbc:sqlite:extension_test_db.sqlite");
++        Assert.assertEquals(dbUrl, "jdbc:sqlite:tests/resources/test_db.sqlite?open_mode=1&limit_attached=0");
+     }
+ 
+     @Test
+@@ -94,6 +83,35 @@ public class SQLiteDatabaseServiceTest extends DBExtensionTests {
+         Assert.assertNotNull(conn);
+     }
+ 
++    /*
++     * We don't allow loading extensions because that executes arbitrary code
++     */
++    @Test(expectedExceptions = IllegalArgumentException.class)
++    public void testGetConnectionWithExtensions() throws DatabaseServiceException {
++        DatabaseConfiguration testDbConfigWithExtensions = new DatabaseConfiguration();
++        testDbConfigWithExtensions.setDatabaseName("test_db.sqlite?enable_load_extension=true");
++        testDbConfigWithExtensions.setDatabaseType(SQLiteDatabaseService.DB_NAME);
++
++        SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService
++                .get(SQLiteDatabaseService.DB_NAME);
++        sqLiteDatabaseService.getConnection(testDbConfigWithExtensions);
++    }
++
++    /*
++     * We don't allow loading a remote SQLite file to make remote code execution harder
++     */
++    @Test(expectedExceptions = IllegalArgumentException.class)
++    public void testGetConnectionWithRemoteFile() throws DatabaseServiceException {
++        DatabaseConfiguration testDbConfigWithExtensions = new DatabaseConfiguration();
++        testDbConfigWithExtensions
++                .setDatabaseName("https://github.com/xerial/sqlite-jdbc/raw/master/src/test/resources/org/sqlite/sample.db";);
++        testDbConfigWithExtensions.setDatabaseType(SQLiteDatabaseService.DB_NAME);
++
++        SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService
++                .get(SQLiteDatabaseService.DB_NAME);
++        sqLiteDatabaseService.getConnection(testDbConfigWithExtensions);
++    }
++
+     @Test
+     public void testTestConnection() throws DatabaseServiceException {
+         SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService
diff -Nru openrefine-3.6.2/debian/patches/CVE-2024-47882.patch openrefine-3.6.2/debian/patches/CVE-2024-47882.patch
--- openrefine-3.6.2/debian/patches/CVE-2024-47882.patch	1970-01-01 01:00:00.000000000 +0100
+++ openrefine-3.6.2/debian/patches/CVE-2024-47882.patch	2025-09-28 00:52:50.000000000 +0200
@@ -0,0 +1,33 @@
+From: Markus Koschany <apo@debian.org>
+Date: Sat, 27 Sep 2025 16:40:21 +0200
+Subject: CVE-2024-47882
+
+Bug-Debian: https://bugs.debian.org/1086041
+Origin: https://github.com/OpenRefine/OpenRefine/commit/b0d5dd0a6a40369593f4a6b593e3e0ffa213339e
+---
+ main/src/com/google/refine/commands/HttpUtilities.java | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/main/src/com/google/refine/commands/HttpUtilities.java b/main/src/com/google/refine/commands/HttpUtilities.java
+index defea78..faa64cc 100644
+--- a/main/src/com/google/refine/commands/HttpUtilities.java
++++ b/main/src/com/google/refine/commands/HttpUtilities.java
+@@ -41,6 +41,8 @@ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ 
+ import com.fasterxml.jackson.core.JsonGenerator;
++import com.google.common.escape.Escaper;
++import com.google.common.html.HtmlEscapers;
+ import com.google.refine.RefineServlet;
+ import com.google.refine.util.ParsingUtilities;
+ 
+@@ -171,7 +173,8 @@ abstract public class HttpUtilities {
+             
+             e.printStackTrace(new PrintWriter(writer));
+             
+-            context.put("stack", writer.toString());
++            Escaper escaper = HtmlEscapers.htmlEscaper();
++            context.put("stack", escaper.escape(writer.toString()));
+         } else {
+             context.put("stack", "");
+         }
diff -Nru openrefine-3.6.2/debian/patches/CVE-2024-49760.patch openrefine-3.6.2/debian/patches/CVE-2024-49760.patch
--- openrefine-3.6.2/debian/patches/CVE-2024-49760.patch	1970-01-01 01:00:00.000000000 +0100
+++ openrefine-3.6.2/debian/patches/CVE-2024-49760.patch	2025-09-28 00:52:50.000000000 +0200
@@ -0,0 +1,54 @@
+From: Markus Koschany <apo@debian.org>
+Date: Sat, 27 Sep 2025 17:51:56 +0200
+Subject: CVE-2024-49760
+
+Bug-Debian: https://bugs.debian.org/1086041
+Origin: https://github.com/OpenRefine/OpenRefine/commit/478285afffea59c893ac472faa74898ab9e5e95a
+---
+ .../com/google/refine/commands/lang/LoadLanguageCommand.java |  9 ++++++++-
+ .../refine/commands/lang/LoadLanguageCommandTests.java       | 12 ++++++++++++
+ 2 files changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/main/src/com/google/refine/commands/lang/LoadLanguageCommand.java b/main/src/com/google/refine/commands/lang/LoadLanguageCommand.java
+index 002b908..85bf2e0 100644
+--- a/main/src/com/google/refine/commands/lang/LoadLanguageCommand.java
++++ b/main/src/com/google/refine/commands/lang/LoadLanguageCommand.java
+@@ -126,7 +126,14 @@ public class LoadLanguageCommand extends Command {
+     static ObjectNode loadLanguage(RefineServlet servlet, String modname, String lang) throws UnsupportedEncodingException {
+         
+         ButterflyModule module = servlet.getModule(modname);
+-        File langFile = new File(module.getPath(), "langs" + File.separator + "translation-" + lang + ".json");
++        String strLangFile = "translation-" + lang + ".json";
++        File langsDir = new File(module.getPath(), "langs");
++        File langFile = new File(langsDir, strLangFile);
++        if (!langFile.toPath().normalize().toAbsolutePath().startsWith(langsDir.toPath().normalize().toAbsolutePath())) {
++            logger.error("Security: Attempt to escape the langs directory to read another file");
++            return null;
++        }
++
+         try {
+             Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(langFile), "UTF-8"));
+             return ParsingUtilities.mapper.readValue(reader, ObjectNode.class);
+diff --git a/main/tests/server/src/com/google/refine/commands/lang/LoadLanguageCommandTests.java b/main/tests/server/src/com/google/refine/commands/lang/LoadLanguageCommandTests.java
+index ce569b5..0e073d3 100644
+--- a/main/tests/server/src/com/google/refine/commands/lang/LoadLanguageCommandTests.java
++++ b/main/tests/server/src/com/google/refine/commands/lang/LoadLanguageCommandTests.java
+@@ -77,6 +77,18 @@ public class LoadLanguageCommandTests extends CommandTestBase {
+         assertEquals(response.get("lang").asText(), "en");
+     }
+ 
++    @Test
++    public void testLoadLanguageWithDirectorySlip() throws JsonParseException, JsonMappingException, IOException, ServletException {
++        when(request.getParameter("module")).thenReturn("core");
++        when(request.getParameterValues("lang")).thenReturn(new String[] { "../../../secrets" });
++
++        command.doPost(request, response);
++
++        JsonNode response = ParsingUtilities.mapper.readValue(writer.toString(), JsonNode.class);
++        assertTrue(response.has("dictionary"));
++        assertEquals(response.get("lang").asText(), "en");
++    }
++
+     @Test
+     public void testLanguageFallback() throws JsonParseException, JsonMappingException, IOException {
+         String fallbackJson = "{"
diff -Nru openrefine-3.6.2/debian/patches/gdata-extension.patch openrefine-3.6.2/debian/patches/gdata-extension.patch
--- openrefine-3.6.2/debian/patches/gdata-extension.patch	2023-10-04 15:02:45.000000000 +0200
+++ openrefine-3.6.2/debian/patches/gdata-extension.patch	2025-09-28 00:52:50.000000000 +0200
@@ -7,7 +7,7 @@
  1 file changed, 5 insertions(+)
 
 diff --git a/extensions/gdata/pom.xml b/extensions/gdata/pom.xml
-index 4fc64e5..ce9b906 100644
+index ed8b740..e310e8c 100644
 --- a/extensions/gdata/pom.xml
 +++ b/extensions/gdata/pom.xml
 @@ -97,6 +97,11 @@
diff -Nru openrefine-3.6.2/debian/patches/log4j-api.patch openrefine-3.6.2/debian/patches/log4j-api.patch
--- openrefine-3.6.2/debian/patches/log4j-api.patch	2023-10-04 15:02:45.000000000 +0200
+++ openrefine-3.6.2/debian/patches/log4j-api.patch	2025-09-28 00:52:50.000000000 +0200
@@ -7,7 +7,7 @@
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/server/pom.xml b/server/pom.xml
-index 8bb528a..89dd5ab 100644
+index 2408c76..e168085 100644
 --- a/server/pom.xml
 +++ b/server/pom.xml
 @@ -180,7 +180,7 @@
diff -Nru openrefine-3.6.2/debian/patches/no-java-files.patch openrefine-3.6.2/debian/patches/no-java-files.patch
--- openrefine-3.6.2/debian/patches/no-java-files.patch	2023-10-04 15:02:45.000000000 +0200
+++ openrefine-3.6.2/debian/patches/no-java-files.patch	2025-09-28 00:52:50.000000000 +0200
@@ -8,7 +8,7 @@
  2 files changed, 10 deletions(-)
 
 diff --git a/main/pom.xml b/main/pom.xml
-index 27f789d..0ef3eab 100644
+index 4b61428..8ea4ef6 100644
 --- a/main/pom.xml
 +++ b/main/pom.xml
 @@ -27,11 +27,6 @@
@@ -24,7 +24,7 @@
      <testResources>
        <testResource>
 diff --git a/server/pom.xml b/server/pom.xml
-index 89dd5ab..94fda4c 100644
+index e168085..f2955e4 100644
 --- a/server/pom.xml
 +++ b/server/pom.xml
 @@ -28,11 +28,6 @@
diff -Nru openrefine-3.6.2/debian/patches/series openrefine-3.6.2/debian/patches/series
--- openrefine-3.6.2/debian/patches/series	2023-10-04 15:02:45.000000000 +0200
+++ openrefine-3.6.2/debian/patches/series	2025-09-28 00:52:50.000000000 +0200
@@ -6,3 +6,9 @@
 gdata-extension.patch
 CVE-2023-37476.patch
 CVE-2023-41887-and-CVE-2023-41886.patch
+CVE-2024-23833.patch
+CVE-2024-47878.patch
+CVE-2024-47880.patch
+CVE-2024-47881.patch
+CVE-2024-47882.patch
+CVE-2024-49760.patch

Reply to: