Skip to content

Conversation

@MoshiMoshiMochi
Copy link
Contributor

@MoshiMoshiMochi MoshiMoshiMochi commented Jan 19, 2026

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Resolves #2749

Overview of changes:
Fixed the unsafe token access & unskipped the testcases made in #2747

  • Also added additional check to cover the "empty radio button text" edge test case 😃
  • Added additional test cases such that it handles for cases when there is an empty radio button text with lowercase & uppercase, (x) & (X) respectively

Anything you'd like to highlight/discuss:
As @gerteck mentioned in the issue,

The plugin attempts to access tokens[i-5].content and tokens[i-4].content without checking if those tokens exist (lines 24-26 in markdown-it-radio-button.js)

Hence, I fixed it by adding bounds checks before accessing tokens[i-5] & tokens[i-4] which prevents the crash when those tokens don't exist.

Additionally, the previous logic only handled the radio button cases if there was a space after the parentheses, i,.e. '( ) '. However, will not be the case dealing with empty radio buttons. Hence, I added the cases to explicitly when the radio button is the entire content of the line (i.e. empty radio button)

  • Kindly seeking clarification as for why the .indexOf checks were initially for '( ) ' & not '( )' to begin with (,because from my testing, using the latter fixes this issue for the most part, but I might be missing the bigger picture here.)
  • Hence, for now, I have decided to add the additional checks for the entire content so that I can preserve this logic in case I'm missing something.

Aside from that, kindly let me know if my changes are suffice and if there is anything else that I missed/could improve. 🤓

PS: Potential code quality improvement?

I was thinking of repurposing function startsWithTodoMarkdown() since it is only used by function isTodoItem(token, index) and its logic is somewhat repeated in function makeRadioButton(token, TokenConstructor, radioId).

But at the same time, I'm not sure if doing so will be worth it if it decreases the clarity / makes makeRadioButton dependent on startsWithTodoMarkdown too. 🫤

Interested to hear your thoughts on this matter too! 😀

See resolved example

e.g. when serving this markdown file

<frontmatter>
  layout: default.md
  title: Hello World
  pageNav: 1
  pageNavTitle: "Chapters of This Page"
</frontmatter>

- ( ) Item 1
- ( ) Item 2
- (x)
- ( )

Hello world

Example of whats generated:
image

Testing instructions:

Proposed commit message: (wrap lines at 72 characters)
Fix markdown-it radio button unsafe token access

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

@codecov
Copy link

codecov bot commented Jan 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.70%. Comparing base (a12f57a) to head (c046805).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2790      +/-   ##
==========================================
+ Coverage   71.67%   71.70%   +0.03%     
==========================================
  Files         134      134              
  Lines        7286     7294       +8     
  Branches     1609     1587      -22     
==========================================
+ Hits         5222     5230       +8     
- Misses       1937     2018      +81     
+ Partials      127       46      -81     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@MoshiMoshiMochi MoshiMoshiMochi changed the title Bug radio button unsafe token access Fix radio button unsafe token access bug Jan 19, 2026
@gerteck gerteck requested a review from Copilot January 19, 2026 14:40

This comment was marked as outdated.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@gerteck
Copy link
Member

gerteck commented Jan 19, 2026

Additionally, the previous logic only handled the radio button cases if there was a space after the parentheses, i,.e. '( ) '. However, will not be the case dealing with empty radio buttons. Hence, I added the cases to explicitly when the radio button is the entire content of the line (i.e. empty radio button)

Kindly seeking clarification as for why the .indexOf checks were initially for '( ) ' & not '( )' to begin with (,because from my testing, using the latter fixes this issue for the most part, but I might be missing the bigger picture here.)
Hence, for now, I have decided to add the additional checks for the entire content so that I can preserve this logic in case I'm missing something.

If I understand it correctly, your change parses empty (checked or unchecked) radios

- ( )
- (x)

to be recognized and rendered, while the previous implementation does not do so.

I think we should stick to the old implementation for the following reasons:

  1. the change creates divergence between checkbox - [ ] and radio button - ( ) behavior. (- [ ] does not create an empty checkbox in markbind or github comments)
  2. Why not update checkbox behavior as well? Since MarkBind docs states it provides GitHub-Flavored Markdown, let's stick to how GitHub supports it (i.e. no checkboxes without text -> no radio without text, also probably no use case for checkboxes and radios w/o text anyway)
  3. Technically, it causes a breaking change, which we try to avoid as we break existing user's code, unless there is strong justification to do so.

See:

- [ ] hello
- [ ] 
  • hello
  • [ ]

Edit:
Apologies, it was possibly the testcase previously that I added that threw you off, can delete that testcase 🙏

Copy link
Member

@gerteck gerteck left a comment

Choose a reason for hiding this comment

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

lgtm with some small changes

var radio = new TokenConstructor('html_inline', '', 0);
var disabledAttr = disableRadio ? ' disabled="" ' : '';
if (token.content.indexOf('( ) ') === 0) {

Copy link
Member

Choose a reason for hiding this comment

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

Let's not cause a change in functionality (see comment in main thread)

I think the refactoring is good (naming checked and unChecked), can keep that.

Probably can consider using const instead of var, var is legacy and shouldn't be used anymore.

Though if you do might as well refactor the whole file which is legacy but that would go beyond the scope of the PR, and you culd and should probably do another PR for it. Tons of refactoring improvement possibilities:

  • Use startsWith instead of indexOf === 0
  • change all var to const
  • use template literatls instead of string concat
    etc etc

Maybe tackle broader refactoring if you wish, in another PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noted! Shall clean this up and work on refactoring in another PR in the future.

@MoshiMoshiMochi
Copy link
Contributor Author

As requested, I have reverted the logic changes in markdown & removed the redundant test cases

Kindly see the previously used example.

<frontmatter>
  layout: default.md
  title: Hello World
  pageNav: 1
  pageNavTitle: "Chapters of This Page"
</frontmatter>

- ( ) Item 1
- ( ) Item 2
- (x)
- ( )

Hello world
image

Copy link
Member

@gerteck gerteck left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for the quick update!

@gerteck gerteck merged commit 24cbff7 into MarkBind:master Jan 20, 2026
11 checks passed
@github-actions github-actions bot added the r.Patch Version resolver: increment by 0.0.1 label Jan 20, 2026
@github-actions
Copy link

Welcome, @MoshiMoshiMochi! 🎉 Thank you for your contribution to the MarkBind project!

@gerteck, please remember to add @MoshiMoshiMochi as an official contributor to our repository.

See the full list of contributors here. ✨

@gerteck
Copy link
Member

gerteck commented Jan 20, 2026

@all-contributors please add MoshiMoshiMochi for code

@allcontributors
Copy link
Contributor

@gerteck

I've put up a pull request to add @MoshiMoshiMochi! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.Patch Version resolver: increment by 0.0.1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Markdown-It Radio Button Plugin Crashes Due to Unsafe Token Access

2 participants