The software world is full of small missteps that lead to big problems. One such issue is CVE-2022-21227, a vulnerability in the popular Node.js package sqlite3 (versions before 5..3). This flaw allowed a Denial of Service (DoS) attack by simply passing a bad object that, when its toString method was called, would throw an error and crash the V8 engine—sending your whole application down, sometimes with just a single request.
Let’s break this down step by step in plain language and see exactly how the bug works, including a live demonstration and safe-guards you should put in place.
CVE ID: CVE-2022-21227
- Affected package: sqlite3
Type: Denial of Service (DoS)
- NVD Link: https://nvd.nist.gov/vuln/detail/CVE-2022-21227
- GitHub Advisory: GHSA-8v3f-7gq8-vh3h
Impact: An attacker can supply an object whose toString method throws an error. If this is passed into certain sqlite3 APIs (for instance, as a query or parameter), sqlite3 will try to call .toString() on it, which in turn crashes the underlying V8 engine. In Node.js, an uncaught error like this can bring down the whole process.
How Does It Work?
When you use sqlite3 and call functions such as db.get, db.run, etc., you provide parameters that typically should be SQL queries or parameters. Internally, sqlite3 calls .toString() on these arguments to ensure they are in string format.
Here’s the snag: If you pass an object whose toString() doesn't return a value but instead throws an error, this uncaught exception will bubble up and crash your app!
Example: The Exploit in Action
Let’s see a code snippet that demonstrates this bug in older versions of sqlite3.
const sqlite3 = require('sqlite3'); // vulnerable version: <5..3
const db = new sqlite3.Database(':memory:');
const evilObject = {
toString() {
throw new Error("Boom! I crashed you.");
}
};
try {
// Here's the dangerous API call: evilObject as the query string
db.all(evilObject, (err, rows) => {
// This callback will never be reached!
console.log("Result:", err, rows);
});
} catch (e) {
console.error("Caught exception:", e);
}
Expected outcome:
Your Node.js application will crash with an uncaught exception saying “Boom! I crashed you.”
Why? Because internally, sqlite3.all() calls query.toString() without protection, and the thrown error is not handled anywhere, bringing down the entire process.
Why Is This A DoS Problem?
Denial of Service means making a service unavailable to legitimate users—often by crashing. Since Node.js applications often run as a single process, one crash can make a website or API unreachable until it restarts. In cloud environments, this can trigger restarts and cascading failures.
Any endpoint that accepts user input and runs it through sqlite3—say, search or filter queries—would open you up to this bug.
How Was It Fixed?
In sqlite3 version 5..3, the maintainers patched the code to wrap the .toString() call in a try/catch block. Any thrown error is now turned into a normal error value, which gets passed to your callback or promise, instead of crashing the process.
Reference to the fix:
- sqlite3#1392: Add check for invalid query inputs
How to Defend Yourself
1. Update sqlite3:
The best and easiest fix is to upgrade to version 5..3 or higher
npm install sqlite3@latest
2. Validate Inputs:
Never trust user data! Ensure that you check types before passing anything to sqlite3 APIs.
Example
function safeSqlQuery(query) {
if (typeof query !== 'string') {
throw new Error('Query must be a string');
}
db.all(query, ...);
}
3. Crash-resilient Servers:
If you’re running Node.js, consider tools that auto-restart crashed processes like PM2 or Docker health checks.
Resources and References
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2022-21227
- SQLite3 GitHub: https://github.com/TryGhost/node-sqlite3
- GitHub Security Advisory: GHSA-8v3f-7gq8-vh3h
- Fix PR: sqlite3#1392
- Node.js Process Crashes: https://nodejs.org/api/process.html#uncaughtException
- Blogpost: https://blog.sesse.net/blog/tech/2022-01-31-22-00_vulnerabilities.html (explains similar JavaScript issues)
Timeline
Published on: 05/01/2022 16:15:00 UTC
Last modified on: 05/11/2022 14:10:00 UTC