gomarkdown/markdown の IsSafeURL 関数が、短い URL でパニックを引き起こす

## 概要

IsSafeURL 関数は、`len(url) >= nPath` を確認する前に、`url[:nPath]` をスライスします。そのため、パスのプレフィックスよりも短い URL (0、1、または 2 バイト) が与えられると、スライス範囲外エラーが発生し、HTML の Safelink セキュリティ機能が有効になっており、入力に空または非常に短いリンク先が含まれている場合に、回復不能なクラッシュを引き起こす可能性があります。これは HEAD (e08cff8; 2022 年から存在) で確認されています。

## 欠陥

parser/parser.go, IsSafeURL:

```go
func IsSafeURL(url []byte) bool {
nLink := len(url)
for _, path := range validPaths { // "/", "./", "../"
nPath := len(path)
linkPrefix := url[:nPath] // 789 行目: 長さのチェックの前にスライスされる
if nLink >= nPath && bytes.Equal(linkPrefix, path) { // 790 行目: チェックが遅すぎる
...
```

`nLink >= nPath` のチェックが行われる前に、`url[:nPath]` が評価されます。`len(url) < nPath` であり、`cap(url) < nPath` の場合、スライス式がパニックを引き起こします。影響を受けるのは相対パスのループのみで、隣接する URI のループはすでに正しく保護されています (このループが異なるという兆候は、アンカーの場合と同じです)。入力: `IsSafeURL("")` がパニックを引き起こします ([:1] cap 0)、`IsSafeURL(".")` がパニックを引き起こします ([:2] cap 1)、`IsSafeURL("..")` がパニックを引き起こします ([:3] cap 2)、一方、`IsSafeURL("/")` は true を返します。エンドツーエンド: `markdown.ToHTML(input, html.CommonFlags|html.Safelink)` で、入力が `[x]()` の場合にパニックが発生します。攻撃者のモデル: (1) html.Safelink フラグ (URL のサニタイズを行うセキュリティ機能自体がクラッシュを引き起こす) が有効になっている、信頼できない Markdown をレンダリングするサービス、または (2) エクスポートされた `parser.IsSafeURL` 関数を、0/1/2 バイトの攻撃者によって作成された URL に対して呼び出すダウンストリームのシステム。`recover()` がどこにも存在しないため、呼び出し元のゴルーチンの未処理のパニックが発生します。

## 検証

ネガティブコントロールを用いたテストで検証済みです。直接的なテストでは、空の文字列や1/2文字の文字列の場合、正確なスライス範囲のエラーメッセージが表示され、"/" は true を返します。ToHTML 関数と html.CommonFlags|html.Safelink を組み合わせた場合、`[x]()` でエラーが発生しますが、`[x](/)`、`[x](http://example.com)`、プレーンテキスト、および `[x](javascript:alert(1))` (安全に無視される) ではエラーは発生しません。検証できていない点として、どのダウンストリームアプリケーションが Safelink を有効にしているか、または IsSafeURL を直接呼び出しているか (デフォルトでは Safelink が無効なレンダリングパスが使用されるため、IsSafeURL に到達しません) が挙げられます。

## 提案される修正

スライスをガード文の中に移動します。まず `nLink >= nPath` を確認し、その後で url[:nPath] を計算します (または、length-safe な bytes.HasPrefix(url, path) を使用します)。これは、すでに正しい URI の処理ループを反映した、1行の変更です。

また、CVE-2026-40890 (smartypants の smartLeftAngle における境界外アクセス) と CVE-2024-44337 (リスト/段落における無限ループ) が修正されており、深ネストは maxNesting=64 で制限されています。デフォルトでは、XSS は意図的に無効になっています (Safelink/SkipHTML は CommonFlags に含まれていません)。

## ツール

調査中に AI の支援を受けました。エラーが発生する状況は、ネガティブコントロールを用いたテストで検証されています (IsSafeURL は空の文字列や "./.." に対してスライス範囲のエラーを表示しますが、"/" は true を返します。また、ToHTML 関数と html.Safelink を組み合わせた場合、`[x]()` でエラーが発生しますが、有効なリンクや javascript: リンクではエラーは発生しません)。HEAD ブランチで確認したところ、IsSafeURL は `nLink >= nPath` のガード文の前に url[:nPath] を計算しています。

影響を受けるパッケージ:
- go github.com/gomarkdown/markdown: 影響範囲は < 0.0.0-20260724235538-61af6e1e6971 で、0.0.0-20260724235538-61af6e1e6971 で修正されています。