Broken Object Property Level Authorization

Broken Object Property Level Authorization Node.js Express [CVE-2026-33163]

[Fixed month year] Updated CVE-2026-33163

Overview

CVE-2026-33163 describes a real-world vulnerability in Parse Server's LiveQuery feature where protected fields and authData could be leaked to subscribers of a class when a Cloud afterLiveQueryEvent trigger is registered. In earlier releases (prior to 9.6.0-alpha.35 and 8.6.50), LiveQuery payloads could include data protected by Class-Level Permissions, exposing sensitive personal information and OAuth tokens to users who should not have access. The root cause was a reference detachment bug: the LiveQuery server would convert the event object to a Parse.Object for the trigger, then create a separate unfiltered JSON copy via toJSONwithObjects() and send that unfiltered copy to clients while filters were applied to the in-memory object. This mismatch allowed protected fields to be included in the data delivered to subscribers with sufficient CLP, enabling data exfiltration across tenants or users. The vulnerability falls under CWE-200 (Information Exposure).

Affected Versions

Parse Server versions prior to 9.6.0-alpha.35 and 8.6.50

Code Fix Example

Node.js (Express) API Security Remediation
Vulnerable pattern (before fix):
// cloud/main.js
Parse.Cloud.afterLiveQueryEvent('MyClass', (req) => {
  // Build JSON payload before filtering
  const payload = req.object.toJSONwithObjects();

  // Apply filter to the object reference (ineffective for payload)
  filterSensitiveFields(req.object);

  // Payload sent to clients remains unfiltered
  req.payload = payload;
});

// Fixed pattern (after upgrade):
Parse.Cloud.afterLiveQueryEvent('MyClass', (req) => {
  // Apply filter to the object first
  filterSensitiveFields(req.object);

  // Then serialize the now-filtered object for the payload
  req.payload = req.object.toJSONwithObjects();
});

// Helper (illustrative):
function filterSensitiveFields(obj) {
  const protectedFields = ['password', 'authData', 'oauthTokens'];
  protectedFields.forEach((field) => {
    // If using Parse.Object, unset/remove the field from the in-memory object
    try {
      if (typeof obj.unset === 'function') {
        obj.unset(field);
      }
    } catch (e) {
      // No-op if the field cannot be unset on this object
    }
  });
}

CVE References

Choose which optional cookies to allow. You can change this any time.