LearnNewsExamplesServices
Frontmatter
id8474
titleEnforce Eager VDOM Cloning in Component Constructor
stateClosed
labels
bugairefactoringcore
assigneestobiu
createdAtJan 9, 2026, 5:42 PM
updatedAtJan 9, 2026, 5:45 PM
githubUrlhttps://github.com/neomjs/neo/issues/8474
authortobiu
commentsCount1
parentIssue8469
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJan 9, 2026, 5:45 PM

Enforce Eager VDOM Cloning in Component Constructor

Closed v11.19.1 bugairefactoringcore
tobiu
tobiu commented on Jan 9, 2026, 5:42 PM

Context: The previous fix (#8472) added lazy cloning to the vdom getter. However, if a subclass accesses this._vdom directly (bypassing the getter) during the construction phase (e.g. in afterSetId), prototype pollution still occurs.

Goal: Implement construct() in Neo.component.Base to perform eager cloning of the VDOM if it hasn't been cloned yet. This ensures that this._vdom is an instance property before super.construct() runs (which triggers afterSetId).

Verification: Use test/playwright/unit/component/Base_PrototypePollution_Direct.spec.mjs to verify that direct access is also safe.

tobiu added the bug label on Jan 9, 2026, 5:42 PM
tobiu added the ai label on Jan 9, 2026, 5:43 PM
tobiu added the refactoring label on Jan 9, 2026, 5:43 PM
tobiu added the core label on Jan 9, 2026, 5:43 PM
tobiu added parent issue #8469 on Jan 9, 2026, 5:43 PM
tobiu referenced in commit 12958ca - "fix: enforce eager VDOM cloning in Component constructor to prevent direct access pollution (#8474)" on Jan 9, 2026, 5:45 PM
tobiu assigned to @tobiu on Jan 9, 2026, 5:45 PM
tobiu
tobiu Jan 9, 2026, 5:45 PM

Input from Gemini 3 Pro:

✦ I have implemented the eager VDOM cloning mechanism in src/component/Base.mjs.

Changes:

  • Overrode the construct(config) method in Neo.component.Base.
  • Added a check !Object.hasOwn(this, '_vdom') && this._vdom.
  • If true, it performs this._vdom = Neo.clone(this._vdom, true) before calling super.construct(config).

Why this is critical:

  • super.construct (in core.Base) sets this.id, which triggers afterSetId.
  • Some legacy code or anti-patterns might access this._vdom (direct private access) inside afterSetId or other early setters.
  • By ensuring _vdom is an instance property before the parent constructor runs, we effectively "firewall" the prototype against any mutation during the entire construction sequence.

Verification:

  • Added test/playwright/unit/component/Base_PrototypePollution_Direct.spec.mjs.
  • This test explicitly bypasses the getter and accesses this._vdom directly in afterSetId.
  • The test passed, confirming the prototype remains clean.

Commit: 12958cae8 (#8474)

tobiu closed this issue on Jan 9, 2026, 5:45 PM
tobiu referenced in commit c51f5c7 - "refactor: remove redundant lazy VDOM cloning from getter, rely on construct (#8474)" on Jan 9, 2026, 5:54 PM
tobiu cross-referenced by #8469 on Jan 9, 2026, 6:26 PM