Skip to content

Comments

fix: reject MongoDB operator injection in query filter params#1423

Open
theeggorchicken wants to merge 1 commit intoidurar:devfrom
theeggorchicken:fix/mongodb-query-injection
Open

fix: reject MongoDB operator injection in query filter params#1423
theeggorchicken wants to merge 1 commit intoidurar:devfrom
theeggorchicken:fix/mongodb-query-injection

Conversation

@theeggorchicken
Copy link

Description

The filter and equal query parameters in paginatedList.js (line 22) get interpolated directly into the MongoDB query as [filter]: equal. Express parses bracket notation in query strings into nested objects, so equal[$regex]=.* becomes { $regex: ".*" } by the time it hits Mongoose. That turns the filter into an arbitrary MongoDB operator.

Vulnerable Lines

File: backend/src/controllers/middlewaresControllers/createCRUDController/paginatedList.js#L6-L22

const { sortBy = 'enabled', sortValue = -1, filter, equal } = req.query;
// ...
const resultsPromise = Model.find({
  removed: false,
  [filter]: equal,  // <-- equal can be an object like { $regex: ".*" }
  ...fields,
})

What could happen

I tested this against a running instance. With $regex, you can extract every email address in the database:

curl "http://localhost:8888/api/people/list?filter=email&equal[$regex]=.*"
# Returns all people records regardless of any other filters

With $gt, you can enumerate all records by ID:

curl "http://localhost:8888/api/people/list?filter=_id&equal[$gt]=000000000000000000000000"
# Returns every record in the collection

This works against any model that uses paginatedList -- people, invoices, payments, products.

What this PR does

Checks whether equal is a plain string before including it in the query. If Express parsed it into an object (from bracket notation like equal[$regex]=.*), the request gets a 400 response instead of passing the operator through to MongoDB.

Evidence

Full curl --trace-ascii captures showing both $regex and $gt operator injection: evidence gist

Related Issue

Security fix -- MongoDB operator injection via Express query string parsing.

Steps to Test

  1. Start the backend with npm start or Docker
  2. Try curl "http://localhost:8888/api/people/list?filter=email&equal[$regex]=.*" with auth
  3. Before fix: returns all records. After fix: 400 "Invalid filter value".

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

The filter and equal query parameters are interpolated directly into
MongoDB queries as [filter]: equal, allowing an attacker to pass
object values like equal[$regex]=.* or equal[$gt]= to inject
arbitrary MongoDB operators. This enables enumeration of any field
across any collection that uses paginatedList.

Validates that equal is a plain string before including it in the
query. Object values (which Express parses from bracket notation)
are rejected with a 400 response.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant