Mar 10, 2026·8 min read·3 visits
A critical NoSQL injection vulnerability in @feathersjs/mongodb allows remote attackers to bypass database isolation by injecting MongoDB operators through unvalidated WebSocket payloads.
The FeathersJS MongoDB adapter (@feathersjs/mongodb) prior to version 5.0.42 contains a critical NoSQL injection vulnerability. The flaw exists due to insufficient type validation of the 'id' parameter when handling requests via WebSocket transports like Socket.IO. Unauthenticated remote attackers can exploit this by passing native JavaScript objects containing MongoDB query operators in place of scalar ID values, allowing them to bypass record-level isolation and perform unauthorized data retrieval, modification, or deletion.
The FeathersJS framework utilizes modular database adapters to facilitate interaction between service methods and underlying datastores. The @feathersjs/mongodb package acts as the official adapter for MongoDB databases, translating standard Feathers service calls (get, find, patch, update, remove) into native MongoDB queries. This adapter is responsible for handling database abstractions while exposing a unified API to the application layer.
CVE-2026-29793 represents a critical flaw in how this adapter processes the primary key identifier (id) passed to specific service methods. The vulnerability is classified under CWE-943 (Improper Neutralization of Special Elements in Data Query Logic). The adapter fails to explicitly restrict the data type of the id argument before incorporating it into the query filter object, creating a direct pathway for NoSQL operator injection.
The vulnerability is highly dependent on the transport layer used by the client application. RESTful HTTP transports natively coerce URL parameters into strings, effectively neutralizing the injection vector. However, WebSocket-based transports, specifically Socket.IO, parse incoming payloads as native JSON objects. This architectural characteristic allows malicious clients to preserve object structures and pass them directly to the service adapter.
Successful exploitation permits an unauthenticated remote attacker to submit MongoDB operators (such as $ne, $gt, or $regex) as the target id. This manipulates the resulting database query, forcing it to match documents indiscriminately rather than targeting a single, specific record. The resulting impact encompasses unauthorized data access, modification, and deletion across the targeted collection.
The root cause of CVE-2026-29793 lies in the absence of input type enforcement within the data access layer. When a client invokes a method that targets a specific document—such as service('messages').get(id)—the FeathersJS adapter internally constructs a MongoDB query object to locate the record. The adapter assumes the id parameter is a primitive scalar value, typically a string or a number.
The query construction logic within vulnerable versions of @feathersjs/mongodb directly assigns the unvalidated id parameter to the primary key field. The framework utilizes a utility method, this.getObjectId(id), which attempts to convert the input into a MongoDB ObjectId instance. If the input is already an object, the function may return it unmodified or fail to properly sanitize the nested keys.
Because Socket.IO preserves the structural integrity of JSON payloads, an attacker can substitute the expected primitive ID with an object representing a MongoDB query operator. When the adapter processes an input such as { "$ne": null }, it constructs the query { "_id": { "$ne": null } }. MongoDB interprets the $ prefix as an instruction to apply an evaluation operator rather than performing a literal value match.
This behavior fundamentally alters the semantics of the query. Instead of evaluating "find the document where _id equals the specified value," the database evaluates "find the document where _id is not null." Since all valid MongoDB documents possess a non-null _id field, the query matches every document in the collection, returning the first result encountered or applying destructive operations broadly.
An analysis of the source code prior to the fix reveals the exact point of failure within packages/mongodb/src/adapter.ts. The adapter's query building mechanism appended the provided id to the $and array of the MongoDB query object without inspecting the data type of the id variable.
// Vulnerable Implementation (packages/mongodb/src/adapter.ts)
if (id !== null) {
query.$and = (query.$and || []).concat({
[this.id]: this.getObjectId(id)
})
}The patch, implemented in commit 163e664f231a57041034c852b80525fc5c8cf68d, introduces an explicit type validation guard clause. Before appending the identifier to the query object, the adapter now strictly verifies that the id is either a string, a number, or a valid ObjectId instance.
// Patched Implementation (packages/mongodb/src/adapter.ts)
if (id !== null) {
if (typeof id !== 'string' && typeof id !== 'number' && !(id instanceof ObjectId)) {
throw new BadRequest(`Invalid id '${JSON.stringify(id)}'`)
}
query.$and = (query.$and || []).concat({
[this.id]: this.getObjectId(id)
})
}This type validation completely eliminates the attack surface. By rejecting any input that is a generic object, the adapter prevents attackers from passing MongoDB operators to the query builder. The framework correctly returns an HTTP 400 Bad Request equivalent via the WebSocket connection.
To prevent future regressions, the fix also introduces comprehensive test coverage in packages/mongodb/test/index.test.ts. The test suite programmatically asserts that passing an object payload to the get method triggers the newly implemented BadRequest exception, ensuring the defensive logic functions as intended under simulated attack conditions.
// Regression Test (packages/mongodb/test/index.test.ts)
it('rejects object as id in get', async () => {
await assert.rejects(
() => app.service('people').get({ $ne: null } as any),
{ name: 'BadRequest' }
)
})Exploitation of CVE-2026-29793 requires the target application to expose the vulnerable FeathersJS service over a WebSocket transport layer, specifically Socket.IO. The attacker must establish a WebSocket connection to the server and possess network routing capabilities to transmit frames. No prior authentication is necessary unless explicitly enforced by custom application-level hooks prior to the adapter execution.
The attack methodology centers on crafting a malicious Socket.IO message that targets a specific database operation. A standard, benign request to retrieve a message might look like ["messages::get", "12345"]. To exploit the flaw, the attacker replaces the scalar string "12345" with a JSON object containing the desired NoSQL operator, formatting the frame as ["messages::get", {"$ne": null}].
When the server processes this frame, the payload bypasses REST-centric string coercion and enters the @feathersjs/mongodb adapter as a native object. If the targeted method is get, the database returns the first document matching the injected condition, allowing the attacker to exfiltrate data sequentially by modifying the operator logic (e.g., using $gt with previously discovered IDs).
The exploitation technique extends to destructive operations. If the application exposes the remove method and the attacker submits the payload ["messages::remove", {"$ne": null}], the adapter instructs the database to delete the matched record. Depending on application logic and hook configurations, this vector facilitates unauthorized state modification or denial-of-service conditions through continuous record deletion.
The security impact of CVE-2026-29793 is critical, yielding a CVSS v4.0 score of 9.3. The vulnerability directly compromises the confidentiality, integrity, and availability of the underlying MongoDB database. Because the NoSQL injection occurs within the core adapter logic, it affects any FeathersJS service utilizing @feathersjs/mongodb without custom, strict type validation hooks.
The primary consequence is the total bypass of record-level isolation. In multi-tenant applications where access controls rely on specific document IDs, an attacker can retrieve records belonging to other organizations or users. By supplying operators like {"$regex": "^"}, the attacker dictates query conditions, effectively transforming targeted single-document operations into unauthorized bulk data retrieval vectors.
Data integrity is equally compromised. If an attacker leverages the patch or update methods with a malicious payload, they can modify arbitrary documents within the collection. This capability enables privilege escalation if the attacker modifies authentication credentials, role assignments, or security-critical configuration flags stored within the database.
The vulnerability also presents a high risk to availability. An unauthenticated attacker utilizing the remove method combined with an expansive NoSQL operator can permanently delete critical database records. In environments lacking comprehensive backup and recovery mechanisms, such actions result in catastrophic data loss and prolonged system downtime.
The definitive remediation strategy for CVE-2026-29793 is to upgrade the @feathersjs/mongodb package to version 5.0.42 or later. This release incorporates the necessary type validation logic within the adapter layer, ensuring that only primitive strings, numbers, or ObjectId instances are processed during database query construction. Development teams must execute npm update @feathersjs/mongodb and verify the installed version via package lock files.
If immediate patching is technically infeasible, organizations can implement a robust mitigation by deploying a global FeathersJS before hook. This hook intercepts all incoming requests to MongoDB-backed services and explicitly validates the data type of the id property. The hook must reject any request where the id is an object, effectively neutralizing the Socket.IO payload manipulation vector.
app.service('myservice').hooks({
before: {
all: [(context) => {
const { id } = context;
if (id !== null && typeof id === 'object' && !id.constructor.name.includes('ObjectId')) {
throw new errors.BadRequest('Invalid ID type');
}
}]
}
});Secondary hardening measures include strict configuration of the adapter.whitelist property. While the whitelist primarily governs the params.query object rather than the id parameter directly, enforcing a deny-by-default policy for query operators reduces the overall attack surface against NoSQL injection methodologies. Security operations teams should simultaneously monitor WebSocket traffic for JSON objects containing MongoDB operator prefixes ($) targeting primary service methods.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@feathersjs/mongodb FeathersJS | >= 5.0.0, < 5.0.42 | 5.0.42 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-943 |
| Attack Vector | Network (WebSocket / Socket.IO) |
| CVSS v4.0 | 9.3 Critical |
| Impact | Unauthorized Data Access, Modification, and Deletion |
| Exploit Status | Proof of Concept Available |
| Affected Component | @feathersjs/mongodb prior to 5.0.42 |
Improper Neutralization of Special Elements in Data Query Logic