fix(v0.44): make SPA page-property projection fail closed for dangerous keys (#1214) - #1249
Merged
Merged
Conversation
Deploying openelement with
|
| Latest commit: |
b5872a3
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://138b7e4e.lessjs.pages.dev |
| Branch Preview URL: | https://v044-a10-6-spa-projection-gu.lessjs.pages.dev |
Contributor
|
APIError: Insufficient Balance |
| loader: () => Promise<unknown>, | ||
| ): Promise<{ host: Record<string, unknown>; baseline: object }> { | ||
| const hosts: Record<string, unknown>[] = []; | ||
| let baseline: object = Object.prototype; |
…us keys (#1214) Alpha.10 truth closure (H4): page-level projection paths bypassed the canonical dangerous-key guard — raw host[key] = value in the SPA bootstrap, unfiltered default projector, and an unfiltered copy in the generated server runtime. Amendment authority: ADR-0151 (touches ADR-0122 §1 frozen path packages/app/src/authoring.ts; Alpha.10 truth-closure scope, umbrella #1155). - route the SPA write boundary through the canonical injectPropsSafe (previously dead code), covering default/props/error projector channels - filter projectPageProps with isDangerousKey at construction - serialize canonical DANGEROUS_KEYS into the generated server runtime at build time (derived copy, not re-authored) - export the guard trio from the element root as @experimental (B1.2 will adjudicate the final home); correct stale guard comments - hostile tests: JSON.parse own-__proto__ end-to-end across SPA and generated server paths; legitimate-key parity proven Implemented by fresh kimi-code/k3-256k HIGH session (.agents/v044-kimi-implementer.md), packet A10.6 + orchestrator-reviewed import-channel repair. No publish, no tag.
SisyphusZheng
force-pushed
the
v044/a10.6-spa-projection-guard
branch
from
September 2, 2026 05:05
5cfa45f to
b5872a3
Compare
Contributor
|
APIError: Insufficient Balance |
This was referenced Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Issue #1214 (umbrella #1155, Alpha.10, audit H4). Page-level property projection bypassed the canonical dangerous-key guard:
spa.tsdid rawhost[key] = valueonto the live page host (host['__proto__'] = …re-prototypes the element instance), the default projectorprojectPagePropspassed route params / loader data through unfiltered (own__proto__keys surviveJSON.parse+Object.entries), and the generated server runtime carried its own unfiltered copy. The canonical guarded assignerinjectPropsSafewas dead code with stale comments.Owner
Canonical rule:
packages/element/src/internal/core/security.ts(DANGEROUS_KEYS/isDangerousKey/injectPropsSafe). This PR creates NO second rule: the generated server runtime receives a build-time-serialized copy of the canonical list (derived, not re-authored), same pattern as the admitted-tag list.Before
Three unguarded projection paths; guard existed but was unused on page-projection paths.
After
Every projection channel (default / descriptor props / descriptor error / route params / loader data, SPA + generated server runtime) fails closed on
__proto__/constructor/prototype; legitimate keys keep full parity (proven by parity tests + all pre-existing suites green). Guard trio exported from the element root as@experimental(documented in PACKAGE_SURFACE with a B1.2 move condition) so production code uses the workspace specifier — no unpublishable relative deep imports.Why this is not a second semantic owner
One rule, one home; generated code carries a serialized copy; no new guard logic anywhere.
Evidence
spa-projection-guard.test.ts(5) +entry-render-runtime-security.test.ts(4), usingJSON.parse('{"__proto__":…}')end-to-end — RED at base SHA (app 4 failed; adapter 3 failed), GREEN after.deno task testexit 0; fmt/lint/typecheck/arch/docs:truth green; interface snapshot regenerated (delta = exactly the 3 experimental symbols); pack:dry-run + package-artifacts:check + package-surface:check + graph:check all exit 0 (publishability proven).Scope / non-goals
No behavior change for legitimate keys; no second dangerous-key rule; no control-plane files.
Risk
Element root gains 3
@experimentalsymbols (unfrozen; B1.2 decides final home). Rollback: revert this commit.Amendment authority
This change amends frozen semantics (ADR-0122 §1 loop contract:
packages/app/src/authoring.ts). Amendment reference: ADR-0151 (v0.44 release-train re-topology) — Alpha.10 Truth Closure scope, issue #1214, umbrella #1155.