GHSA-cv23-7vc5-jfh7: XSS

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.

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. Compensating control

    In parser/parser.go, update IsSafeURL so it checks nLink >= nPath before evaluating url[:nPath]; alternatively use bytes.HasPrefix(url, path), which is length-safe.

Event History

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

Frequently Asked Questions

1

Which deployments are exposed to the end-to-end crash?

Applications using go/github.com/gomarkdown/markdown are exposed when the html.Safelink hardening flag is enabled and they process input containing an empty or very short link destination. The available data does not state whether this flag is enabled by default.

2

What input is needed to trigger the panic?

A link destination shorter than one of the relative-path prefixes can trigger the vulnerable slice operation. Confirmed examples are an empty destination, ".", and ".."; "/" does not panic.

3

Does exploitation require authentication or user interaction?

The supplied vector indicates network reachability, low attack complexity, no privileges required, and no user interaction. In an application that accepts attacker-controlled Markdown or link destinations under the affected configuration, processing the input can cause an unrecoverable denial-of-service crash.

4

How can I determine whether the vulnerable code is present?

The issue was confirmed at repository HEAD commit e08cff8 and is reported as present since 2022. The affected implementation is parser/parser.go's IsSafeURL function, where url[:nPath] is evaluated before verifying that len(url) is at least nPath.

5

Is there a referenced code fix?

The advisory references commit 61af6e1e69710c5ca13cfbaaaa1bc11bc763a8a9. The provided data does not identify a released fixed version.

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