Skip to content

Commit faf100c

Browse files
authored
πŸš€ RELEASE: v0.7.0 (#171)
Write the 0.7.0 changelog entry: the #143 security fixes (renderer escaping, stricter attrs defaults, ReDoS), the gfm_autolink and texmath hang fixes, the section_ref plugin, the markdown-it-py >= 3.0 floor, and upgrade notes for every change of rendered output.
1 parent 1478f5b commit faf100c

1 file changed

Lines changed: 123 additions & 10 deletions

File tree

β€ŽCHANGELOG.mdβ€Ž

Lines changed: 123 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,137 @@
11
# Change Log
22

3-
## 0.7.0 - 2026-07-19
4-
5-
- ✨ NEW: Add section reference plugin (`section_ref`) (#144)
6-
7-
The `section_ref` plugin captures section-sign references β€” the syntax LLMs
8-
commonly use to point at numbered headings β€” into dedicated `section_ref` tokens,
3+
## 0.7.0 - 2026-11-10
4+
5+
A security and bug-fix release.
6+
Plugin renderers now escape user content in HTML attribute, label and math positions,
7+
`attrs` drops event-handler attributes by default and validates URL-valued attributes,
8+
and the regular expressions in `texmath` ```` ```math ```` blocks and `admon` headers no longer backtrack polynomially (#143).
9+
It also fixes parser hangs in `gfm_autolink` (#160) and `texmath` (#156),
10+
and adds the `section_ref` plugin.
11+
The release requires markdown-it-py >= 3.0 and supports Python 3.10 to 3.14.
12+
Several fixes change rendered output: see **Upgrade notes** below.
13+
14+
### Upgrade notes
15+
16+
- **Requires markdown-it-py >= 3.0** ([#170](https://github.com/executablebooks/mdit-py-plugins/pull/170)).
17+
The declared floor was 2.0, but 0.5.0 and later already failed to import `subscript` with markdown-it-py 2.x.
18+
`section_ref`, `gfm` and `gfm_autolink` still need markdown-it-py >= 4.1 and raise `RuntimeError` on older versions.
19+
Python 3.10 to 3.14 are supported.
20+
- **`attrs_plugin` / `attrs_block_plugin` defaults are stricter** ([#150](https://github.com/executablebooks/mdit-py-plugins/pull/150)).
21+
With no `allowed` list, event-handler attributes (any key starting with `on`, in any case) are removed
22+
and moved to `token.meta["insecure_attrs"]`; `style` is kept.
23+
Whatever `allowed` says, `href`, `src`, `action`, `formaction` and `xlink:href` are removed when `md.validateLink` rejects their value,
24+
so `[a](https://x){href="javascript:alert(1)"}` keeps `href="https://x"`.
25+
Text spans (`[text]{...}`) now honour `allowed`, which they used to bypass.
26+
This is a baseline, not a sanitiser: for untrusted input, pass an explicit list such as `allowed=("id", "class")`.
27+
- **Renderers escape their output** ([#150](https://github.com/executablebooks/mdit-py-plugins/pull/150), [#165](https://github.com/executablebooks/mdit-py-plugins/pull/165)).
28+
The `texmath` default renderer HTML-escapes the math source (`$a<b$` now renders `<eq>a&lt;b</eq>`),
29+
and the `dollarmath` equation label, the `myst_block` target label, the `colon_fence` class name
30+
and the `tasklists` `label_after` label are escaped too.
31+
Benign text containing `&`, `<`, `>` or `"` in these positions is now emitted as entities.
32+
- **`anchors_plugin` ids can change** ([#159](https://github.com/executablebooks/mdit-py-plugins/pull/159)).
33+
An explicit heading id (such as `{#custom}` from `attrs_block_plugin`) is now kept instead of being overwritten,
34+
and generated slugs avoid it.
35+
The default slug function no longer strips whitespace from the title,
36+
matching MyST-Parser's `github_slugify`:
37+
a title that starts or ends with a space next to an image, raw HTML or an entity gets a different id
38+
(`# Foo ![img](x.png)` now gives `foo-`, it was `foo`).
39+
To keep the old ids, pass `slug_func=lambda title: slugify(title.strip())`, with `slugify` from `mdit_py_plugins.anchors.index`.
40+
- **`mdit_py_plugins.attrs.parse.parse()` raises on an unterminated attribute group**, instead of succeeding at the end of the string
41+
([#153](https://github.com/executablebooks/mdit-py-plugins/pull/153)).
42+
Every plugin call site declines the group, so `` `a`{.a `` now renders `<code>a</code>{.a`; it used to drop the `{.a`.
43+
- **The `section_ref` token shape is public API** ([#169](https://github.com/executablebooks/mdit-py-plugins/pull/169)): see its entry below.
44+
45+
### πŸ”’ Security
46+
47+
Thanks to [@KrisKennawayDD](https://github.com/KrisKennawayDD) for reporting these issues in #143,
48+
and to [@KyleKing](https://github.com/KyleKing) for the ReDoS analysis and fixes.
49+
50+
- πŸ”’ 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))
51+
52+
With markdown-it-py's `html` option off, untrusted Markdown could still inject HTML or script through:
53+
the `texmath` default renderer (math source), the `dollarmath` equation label (`id` and permalink `href`),
54+
the `myst_block` `(name)=` target label, and `attrs` / `attrs_block` event-handler and `javascript:` URL attributes.
55+
All of these are now escaped or filtered (see **Upgrade notes**),
56+
and `tests/test_xss.py` renders injection probes through each plugin's default renderer.
57+
58+
- πŸ”’ FIX: Escape the `colon_fence` class name and the `tasklists` `label_after` label ([#165](https://github.com/executablebooks/mdit-py-plugins/pull/165))
59+
60+
`:::a"onmouseover="alert(1)` rendered an attribute-breaking `class="block-a"onmouseover="alert(1)"`,
61+
and `- [ ] <img src=x onerror=alert(1)>` with `label=True, label_after=True` rendered a raw `<img>`.
62+
63+
- πŸ”’ 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))
64+
65+
The `texmath` ```` ```math ```` patterns (the `gitlab` and `julia` delimiters) backtracked cubically
66+
on a fence followed by a long whitespace run with no closing fence,
67+
and the `admon` multi-tag title pattern backtracked quadratically on a header with a long run of spaces or double quotes.
68+
Both now run in linear time and match what they matched before, so output is unchanged.
69+
70+
### ✨ New
71+
72+
- ✨ 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))
73+
74+
The `section_ref` plugin captures section-sign references, the syntax LLMs
75+
commonly use to point at numbered headings, into dedicated `section_ref` tokens,
976
so downstream renderers (e.g. MyST-Parser) can resolve them to heading cross-references:
1077

1178
```markdown
1279
See Β§1, Β§1.1 and Β§2.3.4 for details.
1380
```
1481

15-
A `Β§` must be immediately followed by ASCII digits (dot-separated for nested
16-
levels, no spaces); the parsed section number is stored on the token's
17-
`meta["numbers"]` as a list of ints (e.g. `[1, 1]` for `Β§1.1`).
82+
A `Β§` must be immediately followed by one or more `.`-separated levels of 1 to 9 ASCII digits, with no spaces.
83+
A trailing `.` is not part of the reference, and a reference directly followed by an ASCII letter (`Β§1a`),
84+
or with a level longer than nine digits, stays literal text.
85+
Each reference is a `section_ref` leaf token whose `content` is the text as written
86+
and whose `meta["numbers"]` lists each level as an int (e.g. `[1, 1]` for `Β§1.1`).
87+
The grammar and the token shape are documented in the plugin docstring and are public API from this release.
88+
It renders as `<span class="section-ref">Β§1.1</span>` by default.
1889

1990
**Requires markdown-it-py >= 4.1.0.**
2091

21-
- πŸ› 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)
92+
### πŸ› Fixes
93+
94+
- πŸ› 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))
95+
- πŸ› 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))
96+
- πŸ› 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))
97+
- πŸ› 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))
98+
- πŸ› 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))
99+
100+
A block closed by `...` used to leak into the document as text when the `...` was the document's last line or had trailing spaces,
101+
and otherwise kept the `...` in `token.content`.
102+
The marker must be at column 0 and may be followed by spaces only.
103+
104+
- πŸ› 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))
105+
106+
A `[^named]` reference or a nested `^[...]` inside an inline footnote no longer loses the inner note, duplicates an id, or raises `KeyError: 'count'`.
107+
108+
- πŸ› 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))
109+
- πŸ› FIX: `attrs`: unterminated groups, class accumulation and closing-token merge ([#153](https://github.com/executablebooks/mdit-py-plugins/pull/153))
110+
111+
An unterminated attribute group no longer swallows the text after it.
112+
Classes from adjacent attribute groups are combined on spans and links (`[a]{.x}{.y}` gives `class="x y"`),
113+
as they already were on inline code and images.
114+
An attributes block at the end of a container is no longer merged onto the closing token
115+
(`> {.a}` rendered `</blockquote class="a">`).
116+
117+
- πŸ› FIX: `myst_role` no longer rejects a role at the start of inline content when the content ends with a backslash,
118+
and `` \\{name}`x` `` (an escaped backslash before a role) now parses the role (#62) ([#145](https://github.com/executablebooks/mdit-py-plugins/pull/145))
119+
120+
### πŸ“š Documentation
121+
122+
- πŸ“š 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))
123+
- πŸ“š DOCS: A runnable usage example (#44), the `dollarmath` rendering contract and a "Rendering dollarmath output" guide (#111),
124+
and Read the Docs builds on Python 3.13 ([#166](https://github.com/executablebooks/mdit-py-plugins/pull/166))
125+
126+
### πŸ”§ Maintenance
127+
128+
- πŸ”§ 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))
129+
- πŸ”§ Releases are published to PyPI with trusted publishing (#141), with attestations ([#142](https://github.com/executablebooks/mdit-py-plugins/pull/142)),
130+
from distributions built with `python -m build` and checked on every pull request ([#164](https://github.com/executablebooks/mdit-py-plugins/pull/164))
131+
- πŸ”§ 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)),
132+
and a non-blocking Codecov upload ([#167](https://github.com/executablebooks/mdit-py-plugins/pull/167))
133+
134+
**Full Changelog**: <https://github.com/executablebooks/mdit-py-plugins/compare/v0.6.1...v0.7.0>
22135

23136
## 0.6.1 - 2026-05-13
24137

0 commit comments

Comments
Β (0)