Skip to content

fix: isolate extension names from Object.prototype - #4177

Merged
UziTech merged 1 commit into
markedjs:masterfrom
minjungsung:fix/extension-name-prototype-collisions
Nov 2, 2026
Merged

UziTech merged 1 commit into
markedjs:masterfrom
minjungsung:fix/extension-name-prototype-collisions

Conversation

@minjungsung

Copy link
Copy Markdown
Contributor

Marked version: 18.1.2 / 8babc79

Markdown flavor: n/a (extension API)

Description

Custom extension names such as constructor, toString, and __proto__ collide with inherited properties in the renderer and child-token registries. With walkTokens enabled, parsing an otherwise valid custom token throws this.defaults.extensions.childTokens[genericToken.type].forEach is not a function. A renderer returning false can also call an inherited Object function, producing [object Object] or throwing instead of using registered renderer behavior.

Initialize both registries with Object.create(null), as already done for link definitions. This changes registry initialization only and adds no checks to the parsing or token-walking loops. Existing extension chaining stays intact.

Expectation

This extension should render example and visit its token:

import { Marked } from 'marked';

const marked = new Marked({
  extensions: [{
    name: 'constructor',
    level: 'block',
    tokenizer(src) {
      return { type: 'constructor', raw: src, text: src };
    },
    renderer(token) {
      return token.text;
    },
  }],
  walkTokens() {},
});

console.log(marked.parse('example')); // example

Result

On the current master, this throws during token walking. The online demo filters out extension and walkTokens callbacks, so the runnable JavaScript above reproduces the API issue. Input preview shows the ordinary Markdown input without the custom extension.

Validation

  • New public-API regression tests: 12 fail and 3 controls pass before the fix; all 15 pass after. Covers block/inline extensions, nested token traversal, false-return behavior, ordinary names, and fallback to a previously registered renderer.
  • Full npm test passes on Node 26.12.1: 1,947 spec tests and 228 unit tests, including builds, module checks, type checks, and ESLint.
  • git diff --check passes.
  • Small local before/after parse benchmark, seven alternating rounds of 1,000 parses: medians were 80.57/81.77 ms without extensions and 80.02/78.79 ms with an ordinary renderer extension and token walker. This is a local sample, not a general performance guarantee.

Contributor

  • Test(s) exist to ensure functionality and minimize regression.
  • No tests required for this PR.
  • If submitting a new feature, it has been documented in the appropriate places. (Not applicable: bug fix.)

Committer

  • CI is green (no forced merge required).
  • Squash and Merge PR following conventional commit guidelines.

AI disclosure: Codex (GPT-6) discovered and reproduced the issue, prepared the code, tests, and this description, and ran the checks above. No human review is claimed.

Copilot AI balanced review requested due to automatic review settings November 1, 2026 23:27
@vercel

vercel Bot commented Nov 1, 2026

Copy link
Copy Markdown

@minjungsung is attempting to deploy a commit to the MarkedJS Team on Vercel.

A member of the Team first needs to authorize it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@vercel

vercel Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
marked-website Ready Ready Preview Nov 2, 2026 12:28am UTC

Request Review

@UziTech UziTech left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! 💯

@UziTech
UziTech merged commit 5cb03bd into markedjs:master Nov 2, 2026
8 checks passed
github-actions Bot pushed a commit that referenced this pull request Nov 2, 2026
## [18.1.3](v18.1.2...v18.1.3) (2026-11-02)

### Bug Fixes

* allow trailing tabs after a setext heading underline ([#4152](#4152)) ([1f1b480](1f1b480))
* avoid quadratic scan for unmatched emphasis delimiters ([#4103](#4103)) ([eab1e48](eab1e48)), closes [#4099](#4099)
* await promise arrays from walkTokens extensions ([#4153](#4153)) ([c38704c](c38704c))
* **cli:** honor defaults and config when outputting tokens ([#4146](#4146)) ([9470e8f](9470e8f))
* collapse internal whitespace when normalizing link labels ([#4157](#4157)) ([02c73e8](02c73e8))
* do not allow a blank line inside a link reference definition label ([#4165](#4165)) ([f3d21af](f3d21af))
* don't treat an escaped ) or quote as an inline link or title closer ([#4151](#4151)) ([9cb84e0](9cb84e0))
* end a list item before a lazy line after an html block ([#4159](#4159)) ([7ba42f4](7ba42f4))
* end blockquote before a lazy line after a table ([#4161](#4161)) ([e7dcf52](e7dcf52))
* isolate extension names from Object.prototype ([#4177](#4177)) ([5cb03bd](5cb03bd))
* keep a block quote open after a lazy line in a nested block quote ([#4175](#4175)) ([1d7272f](1d7272f))
* only close a code fence with the opening fence character ([#4164](#4164)) ([1d4d8fe](1d4d8fe))
* preserve zero-valued custom renderer results ([#4162](#4162)) ([e43ceef](e43ceef))
* recognize task list items when a tab follows the checkbox ([#4163](#4163)) ([64a299d](64a299d))
* start a GFM www autolink only at a word boundary ([#4166](#4166)) ([84beefb](84beefb))

### Performance Improvements

* fix backtracking in padantic html ([#4173](#4173)) ([2d4a23c](2d4a23c))

This branch was successfully deployed

1 active deployment
Preview — 5989de69 Deployed Nov 2, 2026 by vercel[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.

4 participants