CVE-2026-102941: gomarkdown/markdown IsSafeURL panics on short URLs

Published Oct 16, 2026
·
Updated

Summary

IsSafeURL slices url[:nPath] before checking that len(url) >= nPath, so a URL shorter than a path prefix (0, 1 or 2 bytes) triggers a slice-bounds panic, and this is reached end to end when the html.Safelink hardening flag is enabled and the input contains an empty or very short link destination, giving an unrecoverable crash DoS. Confirmed at HEAD (e08cff8; present since 2022).

The defect

parser/parser.go, IsSafeURL:

go func IsSafeURL(url []byte) bool { nLink := len(url) for , path := range validPaths { // "/", "./", "../" nPath := len(path) linkPrefix := url[:nPath] // line 789: sliced BEFORE the length guard if nLink >= nPath && bytes.Equal(linkPrefix, path) { // line 790: guard is too late ...

url[:nPath] is evaluated before the nLink >= nPath check. When len(url) < nPath and cap(url) < nPath, the slice expression panics. Only the relative-path loop is affected; the adjacent URIs loop is already correctly guarded (the signal that this one deviates, the same signal as the anchor). Input: IsSafeURL("") panics ([:1] cap 0), IsSafeURL(".") panics ([:2] cap 1), IsSafeURL("..") panics ([:3] cap 2), while IsSafeURL("/") returns true. End to end: markdown.ToHTML(input, html.CommonFlags|html.Safelink) with input x panics. Attacker model: (1) any service rendering untrusted Markdown with the html.Safelink flag (the URL-sanitizing hardening flag itself introduces the crash); or (2) any downstream that calls the exported parser.IsSafeURL on a 0/1/2-byte attacker URL, no flag required. No recover() anywhere, so an uncaught crash of the calling goroutine.

Verification

EXECUTED with negative controls. Direct: the empty/1/2-char cases panic with the exact slice-bounds message while "/" returns true. End to end via ToHTML with html.CommonFlags|html.Safelink: x panics, while x, x, plain text, and x) (safely dropped) do not. NOT verified: how many downstream apps enable Safelink or call IsSafeURL directly (the default no-Safelink render path does not reach it).

Suggested fix

Move the slice inside the guard: check nLink >= nPath first, then compute url[:nPath] (or use bytes.HasPrefix(url, path), which is length-safe). One-line change, mirroring the already-correct URIs loop.

Also checked and sound: CVE-2026-40890 (smartypants smartLeftAngle OOB) is fixed; CVE-2024-44337 (list/paragraph infinite loop) is fixed (deep nesting capped at maxNesting=64); default XSS is by design (Safelink/SkipHTML not in CommonFlags).

Tooling

AI assistance was used while investigating. The panic is executed-verified with negative controls (IsSafeURL on empty/./.. panics with a slice-bounds error while "/" returns true; ToHTML with html.Safelink on x panics while valid and javascript: links do not), and I confirmed at HEAD that IsSafeURL computes url[:nPath] before the nLink >= nPath guard.

Other sources

The package github.com/gomarkdown/markdown is a Go library for parsing Markdown text and rendering as HTML. Prior to 0.0.0-20260724235538-61af6e1e6971, parser.IsSafeURL in parser/parser.go slices url[:nPath] before the len(url) >= nPath guard. A short destination causes a slice-bounds panic when the loop reaches a relative-path prefix for which len(url) < nPath and cap(url) < nPath. The one-byte destination / is an explicit non-panic counterexample because it matches the first valid path and returns before a longer prefix is sliced. Demonstrated panic cases include empty, ., and .. destinations under those conditions. The panic is reachable when markdown.ToHTML renders untrusted Markdown with html.Safelink enabled, including an empty link destination, and is also reachable by callers that pass a short attacker-controlled URL directly to the exported parser.IsSafeURL function. An uncaught panic can terminate the calling process and cause denial of service. This issue is fixed in 0.0.0-20260724235538-61af6e1e6971.

— MITRE

Affected Software

1 affected componentFixes available
go/github.com/gomarkdown/markdown<0.0.0-20260724235538-61af6e1e6971
0.0.0-20260724235538-61af6e1e6971

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade go/github.com/gomarkdown/markdown to a version that resolves this vulnerability.

    Fixed in 0.0.0-20260724235538-61af6e1e6971
  2. Upgrade

    Upgrade github.com/gomarkdown/markdown to a version that resolves this vulnerability.

    Fixed in 0.0.0-20260724235538-61af6e1e6971

Event History

Oct 16, 2026
CVE Published
via MITRE·03:38 PM
Data Sourced
via MITRE·03:38 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·03:41 PM
Data Sourced
via GitHub·03:41 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Which applications are exposed to this denial-of-service condition?

Applications are exposed when they render untrusted Markdown through markdown.ToHTML with html.Safelink enabled. Callers that pass short attacker-controlled URLs directly to the exported parser.IsSafeURL function are also exposed.

2

What input is needed to trigger the panic?

An attacker needs to supply a short URL or Markdown link destination that reaches a relative-path prefix check where the URL length and capacity are both shorter than that prefix. Demonstrated panic inputs include an empty destination, ".", and ".."; "/" does not panic because it matches an earlier valid path.

3

Is the vulnerable behavior dependent on authentication or user interaction?

No. The reported vector is network-reachable with low attack complexity, requires no privileges or user interaction, provided the application processes attacker-controlled Markdown or URLs through the affected code path.

4

What should be done if upgrading cannot happen immediately?

Avoid passing attacker-controlled short URLs to parser.IsSafeURL, and avoid rendering untrusted Markdown with markdown.ToHTML while html.Safelink is enabled unless inputs are validated to exclude panic-triggering short destinations. Ensure panics are recovered so a malformed destination cannot terminate the calling process.

5

How can I determine whether the issue is fixed?

The issue is fixed in github.com/gomarkdown/markdown version 0.0.0-20260724235538-61af6e1e6971. Check the resolved module version and whether your application uses markdown.ToHTML with html.Safelink enabled or directly invokes parser.IsSafeURL on untrusted input.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203