Skip to content

Document the seal lockdown modes and the seal-after-load default - #756

Open
kriszyp wants to merge 6 commits into
mainfrom
docs/lockdown-seal-modes
Open

kriszyp wants to merge 6 commits into
mainfrom
docs/lockdown-seal-modes

Conversation

@kriszyp

@kriszyp kriszyp commented Oct 26, 2026 •

Copy link
Copy Markdown
Member
The author presses wax seals onto a reference book while colleagues shelve sealed books and carry away melting ice

⊙ Problem

Seal JavaScript intrinsics by default instead of freezing them adds applications.lockdown: seal and seal-after-load, and makes seal-after-load the default for new installs. The docs list only the freeze modes and say any runtime change to an intrinsic throws. That is no longer true under the new default.

🤔 Is the requirement warranted?

As specified, yes: #755 names the pages. I also updated the v5 migration guide, which stated the old default. The source PR is merged and its seal implementation is present in v5.4.0-alpha.1; the badges use v5.4.0.

💡 Solution

Describe the six lockdown modes, their limits, and upgrade compatibility. Align the configuration reference, release notes, and migration guide. Look hardest at the overwrite trade-off and downgrade advice, which operators act on.

⚖️ Alternatives

  • Update only the value list and the default — the old lockdown prose and troubleshooting bullet would still say any change throws, and point users to lockdown: none for changes the new default allows.

🔧 Changes

🤔 Retain the documented overwrite trade-off?

The source change deliberately leaves existing intrinsic properties writable. Such overwrites can affect application-specific validation or policy checks; the docs' qualified “mostly” wording does not guarantee authorization safety. Keep that decision visible and recommend freeze-after-load when existing properties must be unchangeable.

🤔 Keep the numerical benchmark comparison?

The source PR's benchmark table reports approximately 3.9-4.0x, supporting “about four times.” Core's DESIGN.md says approximately 3x. Keep the source PR's measured comparison. No new benchmark was run for this update.

🤔 Expand the migration guide and reformat Upgrade Notes?

Keep detailed mutation rules in the linked reference. The migration workaround covers adding, deleting, or reconfiguring properties; sealing already allows writable-value assignments. Object.defineProperty throws in strict and sloppy code. Preserve the existing full-text upgrade paragraph rather than reformat unrelated base content.

🤔 Document that a config without lockdown gets no lockdown?

Harper skips locking when the value is absent, as in a config carried over from v4. The docs now say so. The alternative is a core fix that falls back to the default, after which these lines change. This was traced through code, not run.

✅ Verification

  • Ran the harper PR's security/intrinsicsLockdown.ts (head a9247aed) in fresh Node 26.2 workers for each mode and a misspelled one. Under seal, adding and deleting threw; overwrites and arr.push = fn worked. Under freeze both threw. Only the seal modes sealed Function.prototype, and the misspelled mode froze before load.
  • Upgrade claims checked in harper's code: install writes the whole default config, and no upgrade step touches applications.*. The v5.0.0, v5.0.1, v5.0.2 and v5.1.0 tags give the default history; only v5.0.0 lacks freeze-after-load. No live upgrade was run.
  • Fetched core tags and confirmed the remote/local v5.4.0-alpha.1 tag object matches; that tag contains the seal implementation and default.
  • Ran npm run format:write, format:check, lint, typecheck, test:examples, test:workflows, and build on the rebased tree. All pass; example tests pass 13 with one offline companion comparison skipped. The production build checks links and MDX.
Probe results (after the lock, strict mode unless noted)
seal-after-load / seal freeze-after-load / freeze / misspelled
Object.prototype.x = 1 TypeError TypeError
same, sloppy mode ignored ignored
Object.defineProperty(Array.prototype, 'x', …) TypeError TypeError
Function.prototype.x = 1 TypeError allowed
Array.prototype.map = Array.prototype.map allowed TypeError
arr.push = fn on an instance allowed TypeError
obj.toString = fn on an instance allowed allowed
new Array(1e6) fill 1-8 ms about 70 ms

The misspelled mode locked before load, like freeze.

Closes #755

🤖 Generated by OpenAI Codex (maintenance; original documentation by Anthropic Claude); posted via @kriszyp.

Related PRs: #743 overlaps (merged; both entries now share one Security heading)
Complexity: medium

Origin — the dispatch brief this PR was written from

Document the seal lockdown modes and the seal-after-load default

Document the new applications.lockdown seal modes and default, tracked by #755 (its body lists the pages and the exact content; close it from the docs PR).

Source change: HarperFast/harper#3552 (draft). Summary of the behavior to document:

  • New values seal and seal-after-load; seal-after-load is the new default in static/defaultConfig.yaml. none, freeze, freeze-after-load and ses are unchanged.
  • Sealing blocks adding or deleting properties on the intrinsic constructors and prototypes (Object, Array, Promise, BigInt, String, Number, Boolean, Symbol, RegExp, Date, Map, Set, WeakMap, WeakSet, Math, JSON, Reflect, Atomics, SharedArrayBuffer, WeakRef, FinalizationRegistry, plus Function and Function.prototype). This is what prototype-pollution keys such as __proto__.isAdmin need. Existing properties stay writable: instances can shadow inherited methods, and code can still overwrite an existing prototype method (an accepted denial-of-service-only tradeoff). freeze-after-load remains the opt-in for frozen prototypes.
  • Under the after-load modes a component or dependency may still extend intrinsics while it loads (for example reflect-metadata); after load, adding a property throws a TypeError in strict mode and is ignored in sloppy mode.
  • Why the default changed: freezing makes stores into array holes slow process-wide on V8 (msgpackr decode about 4x slower inside a worker); sealing does not.
  • Upgrades: the installer writes the default into each instance's config, so upgraded instances keep freeze-after-load until an operator changes it. Before downgrading to a release without the seal modes, set freeze-after-load: older releases freeze eagerly on an unknown value, and a dependency that extends an intrinsic at load then fails.

Pages: reference/components/module-loading.md (config example, defaults table, Intrinsic Lockdown section, troubleshooting bullet), reference/configuration/options.md (applications.lockdown), and the release notes for the release that ships the harper PR (currently milestoned v5.4). Do not merge before the harper PR merges.

Dispatch: task docs-harper-3552 · queued by task:harper-lockdown-seal-default · ran by claude/opus/xhigh · worker kzyp-xps-1

Review-Coverage: authored=codex; ran=gemini,cursor-composer,claude; adjudicated=domain; declined=cursor-grok,muse; rounds=10; full=1 @ 6f65d88

Review-Attention: skim ~2m (decisions: writable-default) @ 6f65d88

@kriszyp kriszyp added this to the v5.4 milestone Oct 26, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the documentation and release notes to reflect the change in the default lockdown mode to seal-after-load in version 5.4.0, which addresses performance issues associated with frozen prototypes on Node.js. The feedback highlights an inaccuracy in the downgrade instructions across several files; the documentation incorrectly suggests setting lockdown: freeze-after-load when downgrading to versions v5.0.1 through v5.3, but since freeze-after-load was only introduced in v5.0.2, the range should be corrected to v5.0.2 through v5.3.

Comment thread reference/components/module-loading.md Outdated
Comment thread reference/configuration/options.md Outdated
Comment thread release-notes/v5-lincoln/5.4.md
@github-actions
github-actions Bot temporarily deployed to pr-756 October 26, 2026 09:01 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-756

This preview will update automatically when you push new commits.

@github-actions
github-actions Bot temporarily deployed to pr-756 October 26, 2026 09:11 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-756

This preview will update automatically when you push new commits.

@kriszyp
kriszyp marked this pull request as ready for review October 26, 2026 13:04
@kriszyp
kriszyp requested a review from a team as a code owner October 26, 2026 13:04
@kriszyp
kriszyp force-pushed the docs/lockdown-seal-modes branch from a8b6b4d to c1fc622 Compare October 26, 2026 13:19
@github-actions
github-actions Bot temporarily deployed to pr-756 October 26, 2026 13:24 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-756

This preview will update automatically when you push new commits.

@kriszyp
kriszyp force-pushed the docs/lockdown-seal-modes branch from c1fc622 to 5e21763 Compare October 27, 2026 19:03
@kriszyp
kriszyp force-pushed the docs/lockdown-seal-modes branch from 5e21763 to 1e44217 Compare October 28, 2026 15:54
@github-actions
github-actions Bot temporarily deployed to pr-756 October 28, 2026 16:05 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-756

This preview will update automatically when you push new commits.

kriszyp and others added 6 commits October 30, 2026 08:39
applications.lockdown gains seal and seal-after-load; seal-after-load is
the new default for new installs. Rewrite the Intrinsic Lockdown section
around what each mode blocks, scope what is locked, and cover the upgrade
(installs keep their written value) and downgrade (older releases freeze
eagerly on a seal mode) consequences in the reference, options, 5.4
release notes and v5 migration guide.

Closes #755

Dispatch-Task: docs-harper-3552
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ranges

Sealing also blocks reconfiguring a property with Object.defineProperty,
and still lets a payload overwrite an existing method. Downgrade advice
applies to 5.0.2 through 5.3 (5.0.0 and 5.0.1 have no after-load mode).
A config with no lockdown value, such as one carried over from v4, gets
no lockdown. The migration guide now says when lockdown applies and that
upgrades keep the configured value.

Dispatch-Task: docs-harper-3552
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v5.0.1 already supports freeze-after-load; only v5.0.0 lacks an
after-load mode. The migration guide no longer says the pre-5.4 default
sealed.

Dispatch-Task: docs-harper-3552
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The defaults table gives v5.0.2 as when freeze-after-load became the
default, which reads as when it appeared; v5.0.1 already supports it.

Dispatch-Task: docs-harper-3552
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Dispatch-Task: pr-maint-75e960e45b99e352ac56d740b08786db
Co-Authored-By: Gemini <noreply@google.com>
- Note that switching to a seal mode in a cluster requires all nodes on v5.4.0+ so replicated set_configuration does not fall back to freeze on 5.3 peers
- Use arr.push = fn as the shadowing contrast with freeze in 5.4 release notes and link to What is locked for the intrinsic list
- Note that seal and freeze modes neutralize Function.prototype.constructor before the first module loads
- Clarify v5-migration YAML comment and sealing behavior

Dispatch-Task: pr-maint-75e960e45b99e352ac56d740b08786db
Co-Authored-By: Gemini <noreply@google.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Dispatch-Task: pr-maint-75e960e45b99e352ac56d740b08786db

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
@kriszyp
kriszyp force-pushed the docs/lockdown-seal-modes branch from 1e44217 to 6f65d88 Compare October 30, 2026 14:56
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-756

This preview will update automatically when you push new commits.

This branch was successfully deployed

1 active deployment
pr-756 — 6f65d887 Deployed Oct 30, 2026 by github-actions[bot]
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.

Document the seal lockdown modes and the seal-after-load default

2 participants