parse-community / parse-community/parse-server
Relation query with a null operand throws an uncaught TypeError (500)
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 21.4k
- Forks
- 4.8k
- Avg merge
- 7h 45m
- Merged PRs (30d)
- 11
Description
New Issue Checklist
- Report security issues confidentially.
- Any contribution is under this license.
- Before posting search existing issues.
Filed publicly rather than through the security policy: this is an unhandled exception on malformed input, not a disclosure or an authentication problem. The stack trace stays in the server log, the client gets a generic 500, and the process survives, so it is a per-request failure rather than a crash.
Issue Description
reduceInRelation reads .objectId off each constraint operand without checking that the operand is an object. A null anywhere in a relation query constraint therefore raises an uncaught TypeError and the request fails with a generic 500.
Four call sites dereference unguarded (src/Controllers/DatabaseController.js, at the 9.10.1-alpha.6 tree):
if (constraintKey === 'objectId') {
relatedIds = [query[key].objectId]; // :1096
} else if (constraintKey == '$in') {
relatedIds = query[key]['$in'].map(r => r.objectId); // :1098
} else if (constraintKey == '$nin') {
isNegation = true;
relatedIds = query[key]['$nin'].map(r => r.objectId); // :1101
} else if (constraintKey == '$ne') {
isNegation = true;
relatedIds = [query[key]['$ne'].objectId]; // :1104
}
A non-object operand that is not null, for example {"$in": [7]}, is harmless: (7).objectId is undefined, which contributes no id. Only null throws, because it cannot be boxed.
This is reachable with the application id alone. No master key, session token or client key is required.
Related: #4742 reported the same shape in the same function ($in given a non-array, so .map is not a function) and was closed in 2018. The operands here are still unvalidated.
Steps to reproduce
- Create a class
Ownerwith aRelationfield namedfriends, and save one object so the field is in the schema. - Send a query whose relation constraint contains a
null:
GET /parse/classes/Owner?where={"friends":{"$in":[null]}}
X-Parse-Application-Id: <appId>
Each of these reproduces it:
| Constraint | Result |
|---|---|
{"friends":{"$in":[null]}} |
500 |
{"friends":{"$nin":[null]}} |
500 |
{"friends":{"$ne":null,"$in":[]}} |
500 |
{"friends":{"$ne":null,"$nin":[]}} |
500 |
{"friends":{"$ne":null}} |
200, empty results |
The last row does not throw because a bare falsy $ne fails the gate at :1084-1090, which requires one of $in, $ne, $nin to be truthy, so the extraction loop never runs. Adding any truthy sibling operator satisfies the gate and the falsy $ne is then dereferenced. An empty array is enough, since [] is truthy.
Actual Outcome
500 {"code":1,"message":"Internal server error."}
Expected Outcome
Either Parse.Error.INVALID_JSON, or the null treated the way every other operand without an objectId is already treated: it yields undefined and contributes no related id, so the constraint resolves to no owners. The second matches the existing behavior for {"$in":[7]} and for {"$in":[{"foo":1}]}, which both return an empty result rather than an error.
Environment
Server
- Parse Server version:
9.10.1-alpha.6(ca75b1fed69921f7843dc20b921d9b02dc352626) - Operating system:
macOS 26.5.2 - Local or remote host:
local
Database
- System (MongoDB or Postgres):
MongoDB - Database version:
7.0.25 - Local or remote host:
local
Client
- SDK (iOS, Android, JavaScript, PHP, Unity, etc):
REST - SDK version:
n/a
The Postgres adapter was not tested.
Logs
TypeError: Cannot read properties of null (reading 'objectId')
at .../lib/Controllers/DatabaseController.js:946:45
at Array.map (<anonymous>)
at .../lib/Controllers/DatabaseController.js:934:43
at Array.map (<anonymous>)
at DatabaseController.reduceInRelation (.../lib/Controllers/DatabaseController.js:923:42)
at .../lib/Controllers/DatabaseController.js:1215:238
at async _UnsafeRestQuery.runFind (.../lib/RestQuery.js:785:19)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at reduceInRelation in src/Controllers/DatabaseController.js and reproduce the REST query using a null operand in $in, $nin, or $ne. Trace the related stack path in lib/Controllers/DatabaseController.js; done means null no longer causes an uncaught TypeError or generic 500, while existing non-object operand behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, mongodb
- Domain
- api, backend, databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100