#10639·parse-server

allowCustomObjectId accepts an operation as objectId and creates an unreachable user

Author: AdrianCurtinCreated Aug 19, 2026Updated Aug 19, 2026

New Issue Checklist

Issue Description

With allowCustomObjectId: true, a create whose objectId is an operation envelope such as {"__op":"Delete"} is accepted, and the row that results is unusable in three separate ways.

getType returns nothing for an operation envelope, so validateObject hits if (!expected) { continue; } and never compares the value against the String type of the objectId column. The value then reaches the database layer, where the driver generates its own _id.

The outcome is a _User that:

  • is stored under a Mongo-generated _id such as 6a862fa06e17011e3f5a9c96, which is not a Parse objectId and is not what the client was told,
  • has _rperm and _wperm of ["[object Object]"], because the owner ACL is keyed by stringifying the same operation object, so the row is readable and writable by nobody,
  • and is echoed back to the client with "objectId": {"__op":"Delete"}, along with a working session token for a user that session can never read.

A non-operation value behaves correctly and is refused with 111 INCORRECT_TYPE, so this is specific to values whose type cannot be inferred.

Steps to reproduce

Start a server with allowCustomObjectId: true, then:

bash
curl -s -X POST http://127.0.0.1:1337/parse/users \
  -H 'X-Parse-Application-Id: myAppId' -H 'Content-Type: application/json' \
  -d '{"objectId":{"__op":"Delete"},"username":"probe2","password":"pw"}'

Then look at the stored row, with the master key:

bash
curl -s -G http://127.0.0.1:1337/parse/classes/_User \
  -H 'X-Parse-Application-Id: myAppId' -H 'X-Parse-Master-Key: myMasterKey' \
  --data-urlencode 'where={"username":"probe2"}'

For contrast, "objectId": 123 in the same body is refused as expected.

Actual Outcome

201 {"objectId":{"__op":"Delete"},"createdAt":"...","sessionToken":"r:..."}

and in MongoDB:

_id:     "6a862fa06e17011e3f5a9c96"
_rperm:  ["[object Object]"]
_wperm:  ["[object Object]"]

An anonymous GET /classes/_User does not return the row, and neither does a query by another authenticated user, so the account exists and is unreachable by everyone except the master key.

With "objectId": 123 instead: 400 {"code":111,...} and no row, which is the expected behaviour.

Expected Outcome

An objectId whose type cannot be inferred should be refused rather than skipped. Either the same 111 INCORRECT_TYPE that every other non-string value produces, or an explicit rejection of operation envelopes in that position.

At minimum the response should not report an objectId that differs from the stored _id, since a client cannot address the object it just created.

Environment

Server

  • Parse Server version: 9.10.1-alpha.6 (commit ca75b1fe)
  • 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): none, raw REST over HTTP
  • SDK version: n/a

Logs

No error is logged; the request succeeds.

Found while building a reimplementation and comparing behaviour against a server built at ca75b1fe. The stored _id and permission columns above were read directly out of MongoDB rather than inferred.

Source: parse-community/parse-server