Skip to content

fix(ses): Permit bogus caller and arguments on TextEncoder and TextDecoder that shipped in some versions of chrome prior to 127 - #3371

Closed
naugtur wants to merge 1 commit into
masterfrom
naugtur/textencoder-sloppy-permit
Closed

naugtur wants to merge 1 commit into
masterfrom
naugtur/textencoder-sloppy-permit

Conversation

@naugtur

@naugtur naugtur commented Oct 5, 2026

Copy link
Copy Markdown
Member

Closes: #3369

Description

Proposed Permits tweak to prevent lockdown from failing in some unfortunate versions of Chrome
see #3369

Security Considerations

Only allows a descriptor that contains a null, so any other value is still not permitted.

One drawback of doing it with a permit instead of a fallback in cauterizeProperty is a configurable field will remain allowed.

Scaling Considerations

Documentation Considerations

Could document where the inconsistency in Chrome is coming from.

…coder that shipped in some versions of chrome prior to 127
@changeset-bot

changeset-bot Bot commented Oct 5, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 69dbcb2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

kriscendobot added a commit to endojs/endo-but-for-bots that referenced this pull request Oct 7, 2026
…nstructors

lockdown() now replaces the host TextEncoder and TextDecoder
constructors, before the intrinsics collector samples the global
object, with SES-owned constructors that delegate construction to the
captured host originals and share the host prototypes. The permitted
codec intrinsics are therefore SES-owned on every engine, and the host
constructor objects -- restricted properties and all -- never enter
the permitted intrinsics graph, so lockdown() completes on the
affected engines (V8 up to and including Chrome 137).

The restricted-property descriptor shape is indistinguishable from the
live caller and arguments slots of a sloppy function, so neither
tolerating it in cauterizeProperty nor permitting it (endojs/endo#3371)
would be safe; encapsulation sidesteps the exposure decision entirely.

Instances are constructed by the host constructors and the prototypes
are the host prototypes, so instanceof, subclassing, encode,
encodeInto, streaming decode, decoder labels and options, and the
encoding, fatal, and ignoreBOM getters all retain host behavior.

Fixes endojs/endo#3369

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kriscendobot added a commit to endojs/endo-but-for-bots that referenced this pull request Oct 7, 2026
…nstructors

lockdown() now replaces the host TextEncoder and TextDecoder
constructors, before the intrinsics collector samples the global
object, with SES-owned constructors that delegate construction to the
captured host originals and share the host prototypes. The permitted
codec intrinsics are therefore SES-owned on every engine, and the host
constructor objects -- restricted properties and all -- never enter
the permitted intrinsics graph, so lockdown() completes on the
affected engines (V8 up to and including Chrome 137).

The restricted-property descriptor shape is indistinguishable from the
live caller and arguments slots of a sloppy function, so neither
tolerating it in cauterizeProperty nor permitting it (endojs/endo#3371)
would be safe; encapsulation sidesteps the exposure decision entirely.

Instances are constructed by the host constructors and the prototypes
are the host prototypes, so instanceof, subclassing, encode,
encodeInto, streaming decode, decoder labels and options, and the
encoding, fatal, and ignoreBOM getters all retain host behavior.

SES-for-XS builds its shim compartment constructor from a global
intrinsics sample taken at module load, before lockdown() runs, so
the taming is idempotent and SES-for-XS also tames at module load;
compartments and the start compartment then agree on the SES-owned
codec identities under xst, which provides both codecs.

Fixes endojs/endo#3369

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kriscendobot added a commit to endojs/endo-but-for-bots that referenced this pull request Oct 27, 2026
…nstructors

lockdown() now replaces the host TextEncoder and TextDecoder
constructors, before the intrinsics collector samples the global
object, with SES-owned constructors that delegate construction to the
captured host originals and share the host prototypes. The permitted
codec intrinsics are therefore SES-owned on every engine, and the host
constructor objects -- restricted properties and all -- never enter
the permitted intrinsics graph, so lockdown() completes on the
affected engines (V8 up to and including Chrome 137).

The restricted-property descriptor shape is indistinguishable from the
live caller and arguments slots of a sloppy function, so neither
tolerating it in cauterizeProperty nor permitting it (endojs/endo#3371)
would be safe; encapsulation sidesteps the exposure decision entirely.

Instances are constructed by the host constructors and the prototypes
are the host prototypes, so instanceof, subclassing, encode,
encodeInto, streaming decode, decoder labels and options, and the
encoding, fatal, and ignoreBOM getters all retain host behavior.

SES-for-XS builds its shim compartment constructor from a global
intrinsics sample taken at module load, before lockdown() runs, so
the taming is idempotent and SES-for-XS also tames at module load;
compartments and the start compartment then agree on the SES-owned
codec identities under xst, which provides both codecs.

Fixes endojs/endo#3369

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kriscendobot added a commit to endojs/endo-but-for-bots that referenced this pull request Oct 28, 2026
…nstructors

lockdown() now replaces the host TextEncoder and TextDecoder
constructors, before the intrinsics collector samples the global
object, with SES-owned constructors that delegate construction to the
captured host originals and share the host prototypes. The permitted
codec intrinsics are therefore SES-owned on every engine, and the host
constructor objects -- restricted properties and all -- never enter
the permitted intrinsics graph, so lockdown() completes on the
affected engines (V8 up to and including Chrome 137).

The restricted-property descriptor shape is indistinguishable from the
live caller and arguments slots of a sloppy function, so neither
tolerating it in cauterizeProperty nor permitting it (endojs/endo#3371)
would be safe; encapsulation sidesteps the exposure decision entirely.

Instances are constructed by the host constructors and the prototypes
are the host prototypes, so instanceof, subclassing, encode,
encodeInto, streaming decode, decoder labels and options, and the
encoding, fatal, and ignoreBOM getters all retain host behavior.

SES-for-XS builds its shim compartment constructor from a global
intrinsics sample taken at module load, before lockdown() runs, so
the taming is idempotent and SES-for-XS also tames at module load;
compartments and the start compartment then agree on the SES-owned
codec identities under xst, which provides both codecs.

Fixes endojs/endo#3369

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kriskowal

Copy link
Copy Markdown
Member

Superseded by #3376

@kriskowal kriskowal closed this Oct 29, 2026
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.

lockdown() fails on undeletable caller/arguments, reachable since TextEncoder was permitted in 2.3.0

2 participants