fix: ParseServerRESTController passes context by reference causing cross-request mutation#10291
fix: ParseServerRESTController passes context by reference causing cross-request mutation#10291yog27ray wants to merge 3 commits intoparse-community:alphafrom
Conversation
…on leak across requests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
I will reformat the title to use the proper commit message syntax. |
|
🚀 Thanks for opening this pull request! We appreciate your effort in improving the project. Please let us know once your pull request is ready for review. Tip
Note Please respond to review comments from AI agents just like you would to comments from a human reviewer. Let the reviewer resolve their own comments, unless they have reviewed and accepted your commit, or agreed with your explanation for why the feedback was incorrect. Caution Pull requests must be written using an AI agent with human supervision. Pull requests written entirely by a human will likely be rejected, because of lower code quality, higher review effort and the higher risk of introducing bugs. Please note that AI review comments on this pull request alone do not satisfy this requirement. |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
📝 WalkthroughWalkthroughDeep-clone the incoming REST request Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant REST as ParseServerRESTController
participant Router
participant Hook as CloudHook
Client->>REST: POST /... with options.context (sharedObj)
REST->>REST: try structuredClone(sharedObj) -> requestContext
alt clone succeeds
REST->>Router: tryRouteRequest({ ..., context: requestContext })
Router->>Hook: invoke beforeSave(req.context)
Hook-->>Router: returns (may mutate req.context)
Router-->>REST: response
REST-->>Client: 200 OK (original sharedObj unchanged)
else clone fails
REST-->>Client: reject Promise with DataCloneError
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## alpha #10291 +/- ##
=======================================
Coverage 92.53% 92.53%
=======================================
Files 192 192
Lines 16500 16504 +4
Branches 227 227
=======================================
+ Hits 15268 15272 +4
Misses 1212 1212
Partials 20 20 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/ParseServerRESTController.js`:
- Line 123: The structuredClone(options.context || {}) call can throw
synchronously; wrap that call in a try/catch inside the surrounding promise
callback and propagate errors to the outer rejection path instead of allowing a
sync throw to escape. Locate the structuredClone usage (referenced as
structuredClone and options.context) and change it to perform the clone inside a
try { const ctx = structuredClone(options.context || {}); use ctx } catch (err)
{ return reject(err); } (or call the appropriate error callback/next) so any
clone errors are explicitly rejected/handled.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 16bf7b4a-3327-4532-8474-f32a6b334672
📒 Files selected for processing (2)
spec/ParseServerRESTController.spec.jssrc/ParseServerRESTController.js
…t values Moves structuredClone() before the async chain and wraps it in try/catch so non-cloneable values properly reject the promise instead of causing an unhandled rejection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@mtrezza is there any further changes required in this PR? |
Issue
When
directAccessis enabled,ParseServerRESTControllerbypasses the HTTP layer and routes requests internally. Unlike the HTTP path — where request context is serialized to JSON and deserialized on the server side (naturally creating a fresh copy) — the direct access path passesoptions.contextby reference.This means the same context object instance is shared across all requests within the same session. When a
beforeSaveorafterSavehook mutatesreq.context(which is a common and documented pattern for passing data between hooks), those mutations leak back into the caller's original context object and into any subsequent requests that reuse the same context.Reproduction
directAccess: truein Parse Server configconst ctx = { counter: 0 }{ context: ctx }beforeSavehook, mutatereq.context(e.g.,req.context.counter++)ctxobject is mutated; subsequent requests see the mutated stateImpact
directAccessa non-transparent optimizationApproach
Use
structuredClone()to deep copyoptions.contextbefore attaching it to the internal request object inParseServerRESTController. This ensures each request gets its own isolated context — matching the behavior of the HTTP code path where JSON serialization/deserialization naturally creates independent copies.Change
In
src/ParseServerRESTController.js, line 123:Tasks
Summary by CodeRabbit
Bug Fixes
Tests