fix(markdown-core): use Object.hasOwn instead of in operator in parseFrontmatterBlock#99129
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 4, 2026, 1:34 AM ET / 05:34 UTC. Summary PR surface: Source 0, Tests +22. Total +22 across 2 files. Reproducibility: yes. Source inspection shows current main drops YAML nulls, line-parses the same keys, and then suppresses Object.prototype-named keys via Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Next step before merge
Security Review detailsBest possible solution: Land the narrow Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main drops YAML nulls, line-parses the same keys, and then suppresses Object.prototype-named keys via Is this the best way to solve the issue? Yes. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against b68e2e701ae5. Label changesLabel justifications:
Evidence reviewedPR surface: Source 0, Tests +22. Total +22 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
Added a focused regression test for prototype-named null keys as suggested by the review. The test covers @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
7f17546 to
09508c5
Compare
|
@clawsweeper re-review |
|
maintainer review is complete on exact head validation:
best-fix verdict: |
|
Merged via squash.
|
…FrontmatterBlock (openclaw#99129) * fix(markdown-core): use Object.hasOwn instead of in operator in parseFrontmatterBlock * test(markdown-core): add regression test for prototype-named null frontmatter keys * style(markdown-core): fix unbound-method lint in regression test --------- Co-authored-by: Vincent Koc <[email protected]>
…obIdentityFields Replace "jobId" in raw with Object.hasOwn(raw, "jobId") to prevent prototype chain pollution when migrating legacy cron job identity fields. The in operator traverses the prototype chain, so a polluted Object.prototype.jobId would cause the function to incorrectly detect a legacy jobId key and attempt to delete it from the row. This is the third fix in the series after openclaw#99152 and openclaw#99129.
Summary
Use
Object.hasOwn()instead of theinoperator inparseFrontmatterBlock()to prevent prototype chain pollution when merging line-parsed frontmatter entries.What Problem This Solves
When YAML frontmatter contains a key named after an
Object.prototypeproperty (e.g.,toString,constructor,valueOf,hasOwnProperty) with anullvalue, the key is silently dropped from the output.Root cause:
coerceYamlFrontmatterValue(null)returnsundefined, causing the YAML parser to skip the key. The inline line parser still captures it, but the merge step atfrontmatter.ts:225useskey in merged— which traverses the prototype chain. Since"toString" in {}istrue(it findsObject.prototype.toString), the inline value is also discarded, and the user's data is lost.Code evidence: In
packages/markdown-core/src/frontmatter.ts:225, the code checksif (!(key in merged))— butmerged = {}inherits fromObject.prototype, so prototype keys are falsely detected as "already present".Root Cause
inoperator checks the entire prototype chain, not just own propertiesObject.hasOwn()(ES2022+) correctly checks only the object's own propertiesObject.hasOwnis already used 15+ times across the codebase (src/infra/,src/param-key.ts,packages/agent-core/, etc.) — this was the one remaininginoperator usage on a plain objectWhy This Fix
Object.hasOwnusage pattern in the codebaseObject.hasOwn(obj, key)is the semantically correct check for "does this object own this property"Evidence
toString: nullin YAML frontmatter → output{title: "Hello"}(toString lost)toString: nullin YAML frontmatter → output{title: "Hello", toString: "null"}(toString preserved)Real Behavior Proof
Before (on main)
After (with fix)
Tests and Validation
pnpm check: passed (only pre-existingnpm shrinkwrap guardfailure, unrelated)