Skip to content

Fix Proxy get trap being bypassed for properties named "revoke"#2667

Merged
lahma merged 1 commit into
sebastienros:mainfrom
lahma:proxy-revoke-bypass
Jul 13, 2026
Merged

Fix Proxy get trap being bypassed for properties named "revoke"#2667
lahma merged 1 commit into
sebastienros:mainfrom
lahma:proxy-revoke-bypass

Conversation

@lahma

@lahma lahma commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

JsProxy.Get special-cased any property named revoke to skip the get trap entirely:

new Proxy({}, { get: () => 'trapped' }).revoke // Jint: undefined, spec/V8: 'trapped'

The bypass dates back to the original Proxy implementation (#681), where revocation was wired through dynamic property lookups. Today Proxy.revocable captures the proxy instance directly in the revoke closure, so the special case only remains as an observable spec violation (Proxy [[Get]] has no such exception).

test262 has no coverage for a trapped property literally named revoke (verified), which is why this never surfaced. Cross-checked against node 24 / V8: trap is called, and revoked-proxy access errors match.

Tests: get trap fires for revoke; revocable round-trip and revoked-access TypeError still covered.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EsHuKuE4UihKZp5HYapDHE

@lahma
lahma enabled auto-merge (squash) July 13, 2026 12:52
JsProxy.Get contained a special case that skipped the get trap entirely
for any property named "revoke", so
`new Proxy({}, { get: () => 'trapped' }).revoke` returned undefined
instead of 'trapped'. Per the spec (Proxy [[Get]],
https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver)
there is no such exception: the trap must be called for every property key.

The bypass is dead legacy from the original Reflect & Proxy
implementation (f898860, 2019), where revocation was wired through
dynamic property lookups on the proxy itself. Today
ProxyConstructor.Revocable captures the JsProxy instance in a closure
and nulls its target/handler slots directly, so nothing depends on
"revoke" resolving against the target.

Cross-checked with V8 (Node v24.18.0):
`new Proxy({}, {get: () => 'trapped'}).revoke` prints "trapped", and
property access on a revoked proxy still throws
"TypeError: Cannot perform 'get' on a proxy that has been revoked".

Adds tests for the trapped "revoke" property and for the TypeError on
property access after revocation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EsHuKuE4UihKZp5HYapDHE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant