Skip to content

fix: avoid Object.prototype collisions in remark headings map to fix …#1676

Open
h30s wants to merge 3 commits intojson-schema-org:mainfrom
h30s:fix-1673-unsafe-heading-access
Open

fix: avoid Object.prototype collisions in remark headings map to fix …#1676
h30s wants to merge 3 commits intojson-schema-org:mainfrom
h30s:fix-1673-unsafe-heading-access

Conversation

@h30s
Copy link
Contributor

@h30s h30s commented Feb 21, 2026

What kind of change does this PR introduce?

Bugfix

Issue & Discussion References

Summary

This PR addresses a build crash caused by heading IDs colliding with Object.prototype built-in properties like constructor.

When an author uses {{constructor}}, the (id in file.data.headings) check natively evaluates to true, causing the plugin to crash because it tries to map a native JS function as a remark AST Node.

The problem is resolved by explicitly using a null-prototype map via Object.create(null) in remark-headings.js and changing presence checks in remark-reference-links.js to strictly use Object.prototype.hasOwnProperty.call. I have also added testing to confirm standard headers and colliding headers (like constructor) map cleanly without triggering ReferenceLinkErrors.

Does this PR introduce a breaking change?

No breaking change.

@h30s
Copy link
Contributor Author

h30s commented Feb 21, 2026

@jdesrosiers PTAL

Copy link
Member

@jdesrosiers jdesrosiers left a comment

Choose a reason for hiding this comment

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

As much as it pains me to say it, you can remove the tests. Adding tests in a repo that isn't setup to run tests are just a waste. They won't get run just become stale.

@h30s
Copy link
Contributor Author

h30s commented Feb 23, 2026

@jdesrosiers I have removed the tests as requested. Please let me know if any further changes are needed.

Comment on lines +78 to +82
file.data.headings = {};
file.data.headings = Object.create(null);

visit(tree, "heading", (headingNode) => {
if (headingNode.data?.id) {
if (headingNode.data.id in file.data.headings) {
if (Object.prototype.hasOwnProperty.call(file.data.headings, headingNode.data.id)) {
Copy link
Member

Choose a reason for hiding this comment

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

You've fixed this in two different ways when it only needs one, I think. If you use Object.create(null), then you shouldn't need hasOwnProperty. But, if you just define it as {}, then hasOwnProperty is necessary. So, pick one solution.

And if you pick the hasOwnProperty approach, use Object.hasOwn instead.

Comment on lines +15 to +17
const headerText = nodeToString(file.data.headings[id]);
const linkText = text(file.data.headings[id].data.section);
const headingNode = file.data.headings[id];
const headerText = nodeToString(headingNode);
const linkText = text(headingNode.data.section);
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't have anything to do with what you're fixing. Please revert it.

@h30s
Copy link
Contributor Author

h30s commented Feb 25, 2026

@jdesrosiers PTAL

findAndReplace(tree, [referenceLink, (value, id) => {
// file.data.headings comes from ./remark-headings.js
if (!(id in file.data.headings)) {
if (!Object.prototype.hasOwnProperty.call(file.data.headings, id)) {
Copy link
Member

Choose a reason for hiding this comment

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

You're still using hasOwnProperty here.

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.

Bug: Build crash due to unsafe object property access in remark plugins

2 participants