From 13974a733dfc428d53f10a3610856612f6f75a31 Mon Sep 17 00:00:00 2001 From: Chris Sewell Date: Tue, 10 Nov 2026 15:51:58 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=9A=80=20RELEASE:=20v0.7.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Write the full 0.7.0 changelog entry, dated 2026-11-10 (re-date to the tag day): a headline, upgrade notes for the changed output, and every PR merged since v0.6.1, grouped by kind, with contributors credited. --- CHANGELOG.md | 126 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1b78b3..9f5431a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,130 @@ # Change Log -## 0.7.0 - 2026-07-19 - -- โœจ NEW: Add section reference plugin (`section_ref`) (#144) - - The `section_ref` plugin captures section-sign references โ€” the syntax LLMs - commonly use to point at numbered headings โ€” into dedicated `section_ref` tokens, +## 0.7.0 - 2026-11-10 + +A security and bug-fix release. +Plugin renderers now escape user content in HTML attribute, label and math positions, +`attrs` drops event-handler attributes by default and validates URL-valued attributes, +and the regular expressions in `texmath` ```` ```math ```` blocks and `admon` headers no longer backtrack polynomially (#143). +It also fixes parser hangs in `gfm_autolink` (#160) and `texmath` (#156), +and adds the `section_ref` plugin. +Several fixes change rendered output: see **Upgrade notes** below. + +### Upgrade notes + +- **`attrs_plugin` / `attrs_block_plugin` defaults are stricter** ([#150](https://github.com/executablebooks/mdit-py-plugins/pull/150)). + With no `allowed` list, event-handler attributes (any key starting with `on`, in any case) are removed + and moved to `token.meta["insecure_attrs"]`; `style` is kept. + Whatever `allowed` says, `href`, `src`, `action`, `formaction` and `xlink:href` are removed when `md.validateLink` rejects their value, + so `[a](https://x){href="javascript:alert(1)"}` keeps `href="https://x"`. + Text spans (`[text]{...}`) now honour `allowed`, which they used to bypass. + This is a baseline, not a sanitiser: for untrusted input, pass an explicit list such as `allowed=("id", "class")`. +- **Renderers escape their output** ([#150](https://github.com/executablebooks/mdit-py-plugins/pull/150), [#165](https://github.com/executablebooks/mdit-py-plugins/pull/165)). + The `texmath` default renderer HTML-escapes the math source (`$aa<b`), + and the `dollarmath` equation label, the `myst_block` target label, the `colon_fence` class name + and the `tasklists` `label_after` label are escaped too. + Benign text containing `&`, `<`, `>` or `"` in these positions is now emitted as entities. +- **`anchors_plugin` ids can change** ([#159](https://github.com/executablebooks/mdit-py-plugins/pull/159)). + An explicit heading id (such as `{#custom}` from `attrs_block_plugin`) is now kept instead of being overwritten, + and generated slugs avoid it. + The default slug function no longer strips whitespace from the title, + matching MyST-Parser's `github_slugify`: + a title that starts or ends with a space next to an image, raw HTML or an entity gets a different id + (`# Foo ![img](x.png)` now gives `foo-`, it was `foo`). + To keep the old ids, pass `slug_func=lambda title: slugify(title.strip())`, with `slugify` from `mdit_py_plugins.anchors.index`. +- **`mdit_py_plugins.attrs.parse.parse()` raises on an unterminated attribute group**, instead of succeeding at the end of the string + ([#153](https://github.com/executablebooks/mdit-py-plugins/pull/153)). + Every plugin call site declines the group, so `` `a`{.a `` now renders `a{.a`; it used to drop the `{.a`. +- **The `section_ref` token shape is public API** ([#169](https://github.com/executablebooks/mdit-py-plugins/pull/169)): see its entry below. + +### ๐Ÿ”’ Security + +Thanks to [@KrisKennawayDD](https://github.com/KrisKennawayDD) for reporting these issues in #143, +and to [@KyleKing](https://github.com/KyleKing) for the ReDoS analysis and fixes. + +- ๐Ÿ”’ FIX: Escape plugin renderer output and harden the `attrs` defaults, thanks to [@KyleKing](https://github.com/KyleKing) for the cross-plugin XSS test ([#150](https://github.com/executablebooks/mdit-py-plugins/pull/150), folding in [#151](https://github.com/executablebooks/mdit-py-plugins/pull/151)) + + With markdown-it-py's `html` option off, untrusted Markdown could still inject HTML or script through: + the `texmath` default renderer (math source), the `dollarmath` equation label (`id` and permalink `href`), + the `myst_block` `(name)=` target label, and `attrs` / `attrs_block` event-handler and `javascript:` URL attributes. + All of these are now escaped or filtered (see **Upgrade notes**), + and `tests/test_xss.py` renders injection probes through each plugin's default renderer. + +- ๐Ÿ”’ FIX: Escape the `colon_fence` class name and the `tasklists` `label_after` label ([#165](https://github.com/executablebooks/mdit-py-plugins/pull/165)) + + `:::a"onmouseover="alert(1)` rendered an attribute-breaking `class="block-a"onmouseover="alert(1)"`, + and `- [ ] ` with `label=True, label_after=True` rendered a raw ``. + +- ๐Ÿ”’ FIX: ReDoS in `texmath` ```` ```math ```` blocks and `admon` headers, thanks to [@KyleKing](https://github.com/KyleKing) ([#148](https://github.com/executablebooks/mdit-py-plugins/pull/148)) + + The `texmath` ```` ```math ```` patterns (the `gitlab` and `julia` delimiters) backtracked cubically + on a fence followed by a long whitespace run with no closing fence, + and the `admon` multi-tag title pattern backtracked quadratically on a header with a long run of spaces or double quotes. + Both now run in linear time and match what they matched before, so output is unchanged. + +### โœจ New + +- โœจ NEW: Add the section reference plugin (`section_ref`) ([#144](https://github.com/executablebooks/mdit-py-plugins/pull/144), [#168](https://github.com/executablebooks/mdit-py-plugins/pull/168), [#169](https://github.com/executablebooks/mdit-py-plugins/pull/169)) + + The `section_ref` plugin captures section-sign references, the syntax LLMs + commonly use to point at numbered headings, into dedicated `section_ref` tokens, so downstream renderers (e.g. MyST-Parser) can resolve them to heading cross-references: ```markdown See ยง1, ยง1.1 and ยง2.3.4 for details. ``` - A `ยง` must be immediately followed by ASCII digits (dot-separated for nested - levels, no spaces); the parsed section number is stored on the token's - `meta["numbers"]` as a list of ints (e.g. `[1, 1]` for `ยง1.1`). + A `ยง` must be immediately followed by one or more `.`-separated levels of 1 to 9 ASCII digits, with no spaces. + A trailing `.` is not part of the reference, and a reference directly followed by an ASCII letter (`ยง1a`), + or with a level longer than nine digits, stays literal text. + Each reference is a `section_ref` leaf token whose `content` is the text as written + and whose `meta["numbers"]` lists each level as an int (e.g. `[1, 1]` for `ยง1.1`). + The grammar and the token shape are documented in the plugin docstring and are public API from this release. + It renders as `ยง1.1` by default. **Requires markdown-it-py >= 4.1.0.** -- ๐Ÿ› FIX: `myst_role` no longer mis-rejects a role at the start of inline content when the content ends with a backslash, and `\\{name}`x`` (an escaped backslash before a role) now parses the role (#62) +### ๐Ÿ› Fixes + +- ๐Ÿ› FIX: `gfm_autolink` no longer hangs on autolink-like text in link labels (#160), thanks to [@AryanRG](https://github.com/AryanRG) ([#161](https://github.com/executablebooks/mdit-py-plugins/pull/161)) +- ๐Ÿ› FIX: `texmath` no longer loops forever on block math opened in a blockquote and closed after it (#156), thanks to [@acaprino](https://github.com/acaprino) ([#157](https://github.com/executablebooks/mdit-py-plugins/pull/157)) +- ๐Ÿ› FIX: `dollarmath`: a same-line `$$โ€ฆ$$` followed by text no longer swallows the following lines (#147), thanks to [@KyleKing](https://github.com/KyleKing) ([#149](https://github.com/executablebooks/mdit-py-plugins/pull/149)) +- ๐Ÿ› FIX: `dollarmath`: multi-line `$$` blocks in a blockquote no longer keep the `>` prefixes in their content (#125), thanks to [@BetterAndBetterII](https://github.com/BetterAndBetterII) ([#152](https://github.com/executablebooks/mdit-py-plugins/pull/152)) +- ๐Ÿ› FIX: `front_matter`: parse front matter closed by the YAML `...` document-end marker, thanks to [@feiiiiii5](https://github.com/feiiiiii5) ([#158](https://github.com/executablebooks/mdit-py-plugins/pull/158)) + + A block whose last line was `...` used to leak into the document as text. + The marker must be at column 0 and may be followed by spaces only. + +- ๐Ÿ› FIX: `footnote`: reserve an inline footnote's id before parsing its content, thanks to [@civilwarinfrance](https://github.com/civilwarinfrance) ([#162](https://github.com/executablebooks/mdit-py-plugins/pull/162)) + + A `[^named]` reference or a nested `^[...]` inside an inline footnote no longer loses the inner note, duplicates an id, or raises `KeyError: 'count'`. + +- ๐Ÿ› FIX: `anchors`: keep explicit heading ids, and do not strip slug titles, thanks to [@muneikh](https://github.com/muneikh) ([#159](https://github.com/executablebooks/mdit-py-plugins/pull/159)) +- ๐Ÿ› FIX: `attrs`: unterminated groups, class accumulation and closing-token merge ([#153](https://github.com/executablebooks/mdit-py-plugins/pull/153)) + + An unterminated attribute group no longer swallows the text after it. + Classes from adjacent attribute groups are combined on spans and links (`[a]{.x}{.y}` gives `class="x y"`), + as they already were on inline code and images. + An attributes block at the end of a container is no longer merged onto the closing token + (`> {.a}` rendered ``). + +- ๐Ÿ› FIX: `myst_role` no longer rejects a role at the start of inline content when the content ends with a backslash, + and `` \\{name}`x` `` (an escaped backslash before a role) now parses the role (#62) ([#145](https://github.com/executablebooks/mdit-py-plugins/pull/145)) + +### ๐Ÿ“š Documentation + +- ๐Ÿ“š DOCS: Explain front matter extraction and HTML rendering (#133), thanks to [@Gonghan-Princess](https://github.com/Gonghan-Princess) ([#154](https://github.com/executablebooks/mdit-py-plugins/pull/154)) +- ๐Ÿ“š DOCS: A runnable usage example (#44), the `dollarmath` rendering contract and a "Rendering dollarmath output" guide (#111), + and Read the Docs builds on Python 3.13 ([#166](https://github.com/executablebooks/mdit-py-plugins/pull/166)) + +### ๐Ÿ”ง Maintenance + +- ๐Ÿ”ง Releases are published to PyPI with trusted publishing (#141), with attestations ([#142](https://github.com/executablebooks/mdit-py-plugins/pull/142)), + from distributions built with `python -m build` and checked on every pull request ([#164](https://github.com/executablebooks/mdit-py-plugins/pull/164)) +- ๐Ÿ”ง pre-commit autoupdate (ruff 0.17, mypy 2.4) with a pinned ruff base rule set ([#138](https://github.com/executablebooks/mdit-py-plugins/pull/138)), + and a non-blocking Codecov upload ([#167](https://github.com/executablebooks/mdit-py-plugins/pull/167)) + +**Full Changelog**: ## 0.6.1 - 2026-05-13 From 998d14a8d335a7519be1b4024bcfd6c7ed07b505 Mon Sep 17 00:00:00 2001 From: Chris Sewell Date: Tue, 10 Nov 2026 16:33:14 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9A=20DOCS:=200.7.0=20changelog:?= =?UTF-8?q?=20the=20markdown-it-py=20>=3D=203.0=20floor=20and=20Python=203?= =?UTF-8?q?.14=20(#170)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f5431a..be2a4a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,17 @@ Plugin renderers now escape user content in HTML attribute, label and math posit `attrs` drops event-handler attributes by default and validates URL-valued attributes, and the regular expressions in `texmath` ```` ```math ```` blocks and `admon` headers no longer backtrack polynomially (#143). It also fixes parser hangs in `gfm_autolink` (#160) and `texmath` (#156), -and adds the `section_ref` plugin. +and adds the `section_ref` plugin; +it requires markdown-it-py >= 3.0 and supports Python 3.10 to 3.14. Several fixes change rendered output: see **Upgrade notes** below. ### Upgrade notes +- **Requires markdown-it-py >= 3.0** ([#170](https://github.com/executablebooks/mdit-py-plugins/pull/170)). + The declared floor was 2.0, but 0.5.0 and later already failed to import `subscript` with markdown-it-py 2.x. + `section_ref`, `gfm` and `gfm_autolink` still need markdown-it-py >= 4.1 and raise `RuntimeError` on older versions. + Python 3.10 to 3.14 are supported. + - **`attrs_plugin` / `attrs_block_plugin` defaults are stricter** ([#150](https://github.com/executablebooks/mdit-py-plugins/pull/150)). With no `allowed` list, event-handler attributes (any key starting with `on`, in any case) are removed and moved to `token.meta["insecure_attrs"]`; `style` is kept. @@ -119,6 +125,7 @@ and to [@KyleKing](https://github.com/KyleKing) for the ReDoS analysis and fixes ### ๐Ÿ”ง Maintenance +- ๐Ÿ”ง Require markdown-it-py >= 3.0, test the floor and Python 3.14 in CI, and update the classifiers ([#170](https://github.com/executablebooks/mdit-py-plugins/pull/170)) - ๐Ÿ”ง Releases are published to PyPI with trusted publishing (#141), with attestations ([#142](https://github.com/executablebooks/mdit-py-plugins/pull/142)), from distributions built with `python -m build` and checked on every pull request ([#164](https://github.com/executablebooks/mdit-py-plugins/pull/164)) - ๐Ÿ”ง pre-commit autoupdate (ruff 0.17, mypy 2.4) with a pinned ruff base rule set ([#138](https://github.com/executablebooks/mdit-py-plugins/pull/138)), From 6669918fb844b74a9a88703e04786feb7a2da0c5 Mon Sep 17 00:00:00 2001 From: Chris Sewell Date: Tue, 10 Nov 2026 16:45:57 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=93=9A=20DOCS:=200.7.0=20changelog:?= =?UTF-8?q?=20front=5Fmatter=20wording,=20floor=20sentence,=20tight=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be2a4a3..7a8d414 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,8 @@ Plugin renderers now escape user content in HTML attribute, label and math posit `attrs` drops event-handler attributes by default and validates URL-valued attributes, and the regular expressions in `texmath` ```` ```math ```` blocks and `admon` headers no longer backtrack polynomially (#143). It also fixes parser hangs in `gfm_autolink` (#160) and `texmath` (#156), -and adds the `section_ref` plugin; -it requires markdown-it-py >= 3.0 and supports Python 3.10 to 3.14. +and adds the `section_ref` plugin. +The release requires markdown-it-py >= 3.0 and supports Python 3.10 to 3.14. Several fixes change rendered output: see **Upgrade notes** below. ### Upgrade notes @@ -17,7 +17,6 @@ Several fixes change rendered output: see **Upgrade notes** below. The declared floor was 2.0, but 0.5.0 and later already failed to import `subscript` with markdown-it-py 2.x. `section_ref`, `gfm` and `gfm_autolink` still need markdown-it-py >= 4.1 and raise `RuntimeError` on older versions. Python 3.10 to 3.14 are supported. - - **`attrs_plugin` / `attrs_block_plugin` defaults are stricter** ([#150](https://github.com/executablebooks/mdit-py-plugins/pull/150)). With no `allowed` list, event-handler attributes (any key starting with `on`, in any case) are removed and moved to `token.meta["insecure_attrs"]`; `style` is kept. @@ -98,7 +97,8 @@ and to [@KyleKing](https://github.com/KyleKing) for the ReDoS analysis and fixes - ๐Ÿ› FIX: `dollarmath`: multi-line `$$` blocks in a blockquote no longer keep the `>` prefixes in their content (#125), thanks to [@BetterAndBetterII](https://github.com/BetterAndBetterII) ([#152](https://github.com/executablebooks/mdit-py-plugins/pull/152)) - ๐Ÿ› FIX: `front_matter`: parse front matter closed by the YAML `...` document-end marker, thanks to [@feiiiiii5](https://github.com/feiiiiii5) ([#158](https://github.com/executablebooks/mdit-py-plugins/pull/158)) - A block whose last line was `...` used to leak into the document as text. + A block closed by `...` used to leak into the document as text when the `...` was the document's last line or had trailing spaces, + and otherwise kept the `...` in `token.content`. The marker must be at column 0 and may be followed by spaces only. - ๐Ÿ› FIX: `footnote`: reserve an inline footnote's id before parsing its content, thanks to [@civilwarinfrance](https://github.com/civilwarinfrance) ([#162](https://github.com/executablebooks/mdit-py-plugins/pull/162))