Skip to content

Commit 64385cc

Browse files
hi-ogawacodex
andcommitted
fix(plugin-rsc): escape __proto__ in bind objects
Co-authored-by: Codex <noreply@openai.com>
1 parent e25a88f commit 64385cc

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
function outer() {
2+
const x = {}
3+
async function action() {
4+
'use server'
5+
return [x.__proto__.y, x.a.__proto__.b]
6+
}
7+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
function outer() {
2+
const x = {}
3+
const action = /* #__PURE__ */ $$register($$hoist_0_action, "<id>", "$$hoist_0_action").bind(null, { ["__proto__"]: { y: x.__proto__.y }, a: { ["__proto__"]: { b: x.a.__proto__.b } } });
4+
}
5+
6+
;export async function $$hoist_0_action(x) {
7+
'use server'
8+
return [x.__proto__.y, x.a.__proto__.b]
9+
};
10+
/* #__PURE__ */ Object.defineProperty($$hoist_0_action, "name", { value: "action" });

packages/plugin-rsc/src/transforms/hoist.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,14 +289,26 @@ function synthesizePartialObject(root: string, bindPaths: BindPath[]): string {
289289
return root + segments.map((segment) => `.${segment}`).join('')
290290
}
291291
const entries = [...node.entries()]
292-
.map(([k, child]) => `${k}: ${serialize(child, [...segments, k])}`)
292+
.map(
293+
([k, child]) =>
294+
`${serializeObjectKey(k)}: ${serialize(child, [...segments, k])}`,
295+
)
293296
.join(', ')
294297
return `{ ${entries} }`
295298
}
296299

297300
return serialize(trie, [])
298301
}
299302

303+
function serializeObjectKey(key: string): string {
304+
// ECMAScript object literals treat `__proto__: value` specially: when the
305+
// property name is non-computed and equals "__proto__", evaluation performs
306+
// [[SetPrototypeOf]] instead of creating a normal own data property. Emit a
307+
// computed key here so synthesized partial objects preserve the original
308+
// member-path shape rather than mutating the new object's prototype.
309+
return key === '__proto__' ? `[${JSON.stringify(key)}]` : key
310+
}
311+
300312
// e.g.
301313
// [x.y, x.y.z, x.w] -> [x.y, x.w]
302314
// [x.y.z, x.y.z.w] -> [x.y.z]

0 commit comments

Comments
 (0)