aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-02 17:41:39 +0200
committerDanilo M. <danix@danix.xyz>2026-08-04 12:52:28 +0200
commit5690c50ff9a6ef4555c2c4ccd9a7dbd7dc172c7a (patch)
tree90da159f0ae913ee8f6d1a12ddc0d70faa31183b /docs/superpowers/specs
parent14843569125f7aeb4adaf547c323c8eb18961461 (diff)
downloadqtmaildir-5690c50ff9a6ef4555c2c4ccd9a7dbd7dc172c7a.tar.gz
qtmaildir-5690c50ff9a6ef4555c2c4ccd9a7dbd7dc172c7a.zip
docs: scope the document-load exemption to an exact URL
The interceptor previously trusted the whole qtmaildir: scheme, so a hostile message body referencing qtmaildir://anything would have been allowed. That made the interceptor's correctness depend on the scheme handler in a different, later task. It now trusts only the exact base URL passed to setHtml() and fails closed when none is set. Records the resulting obligation on MessageView to call setDocumentUrl() with that same URL. Also corrects the attachment path guard to a separator-aware comparison and notes that it is unreachable defence-in-depth: safeFilename() runs first, so no caller-supplied name can reach it. A test driving saveTo() expecting refusal cannot pass; test safeFilename() instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'docs/superpowers/specs')
-rw-r--r--docs/superpowers/specs/2026-08-02-qtmaildir-design.md9
1 files changed, 9 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-08-02-qtmaildir-design.md b/docs/superpowers/specs/2026-08-02-qtmaildir-design.md
index 1edc75f..0f49b61 100644
--- a/docs/superpowers/specs/2026-08-02-qtmaildir-design.md
+++ b/docs/superpowers/specs/2026-08-02-qtmaildir-design.md
@@ -312,6 +312,15 @@ pointed at input from strangers.
from the current message's own parts are permitted. Remote images, CSS,
and fonts are blocked before a connection opens, which defeats tracking
pixels and read receipts.
+
+ The document-load exemption is scoped to the **exact** base URL passed to
+ `setHtml()`, not to the whole `qtmaildir:` scheme. A blanket
+ scheme-level allow would let a hostile body reference
+ `qtmaildir://anything` and have it trusted, making the interceptor's
+ correctness depend on the scheme handler's. The interceptor fails closed:
+ with no document URL set, every `qtmaildir:` URL is denied. `MessageView`
+ must therefore call `setDocumentUrl()` with the same URL it gives
+ `setHtml()`.
- When anything was blocked, the header bar shows "Remote content blocked"
with a **Load remote content** button. Clicking it re-renders that one
message with remote loads permitted. The grant is never sticky and never