From 61d07d87a9b54cd102699e065a349d5c3fc4a06fbe7a96c255e43aa182c02be7 Mon Sep 17 00:00:00 2001 From: Nicholas Johnson <> Date: Fri, 18 Sep 2026 00:00:00 +0000 Subject: Drop scripting URL schemes from links and images Both render hooks passed the destination through safeURL, which bypasses the sanitising that html/template would otherwise apply, so a javascript: or data:text/html destination in Markdown became a live scripting URL in the page. That matters for any site built from content its author did not write. safeURL cannot simply be dropped: it is what allows gemini:// and other schemes html/template does not recognise to survive, which this theme depends on. Reject the scripting schemes explicitly instead, render the link text on its own, and warn during the build so the author can see what was dropped. data: is still allowed for images, where it is a legitimate way to inline one. Co-Authored-By: Claude Opus 5 --- layouts/_markup/render-image.html | 8 +++++++- layouts/_markup/render-link.html | 11 ++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'layouts/_markup') diff --git a/layouts/_markup/render-image.html b/layouts/_markup/render-image.html index 590c9bf..cd003f3 100644 --- a/layouts/_markup/render-image.html +++ b/layouts/_markup/render-image.html @@ -1 +1,7 @@ -{{ .Text }} \ No newline at end of file +{{/* .Destination is marked safe below, so scripting schemes are dropped here */ -}} +{{ $scheme := lower (urls.Parse .Destination).Scheme -}} +{{ if in (slice "javascript" "vbscript") $scheme -}} +{{ warnidf "unsafe-image-scheme" "dropped %s: image in %s" $scheme .Page.Path -}} +{{ else -}} +{{ .Text }} +{{- end -}} diff --git a/layouts/_markup/render-link.html b/layouts/_markup/render-link.html index 8fb3c26..bb507d2 100644 --- a/layouts/_markup/render-link.html +++ b/layouts/_markup/render-link.html @@ -1,3 +1,12 @@ {{ $emoji := cond (and (not (.Page.Params.makerefs | default true)) (.Page.Params.showlinkemoji | default true)) (emojify ":link: ") "" -}} {{ $isExternalLink := (urls.Parse .Destination).IsAbs -}} -{{ $emoji }}{{ .Text }} \ No newline at end of file + +{{/* .Destination is marked safe below so that schemes the web knows nothing */ -}} +{{/* about, such as gemini://, survive; scripting schemes are dropped instead */ -}} +{{ $scheme := lower (urls.Parse .Destination).Scheme -}} +{{ if in (slice "javascript" "vbscript" "data") $scheme -}} +{{ warnidf "unsafe-link-scheme" "dropped %s: link in %s" $scheme .Page.Path -}} +{{ .Text -}} +{{ else -}} +{{ $emoji }}{{ .Text }} +{{- end -}} -- cgit v1.2.3