From 18d223f69a7510b331f574747f241eb4e30bf901 Mon Sep 17 00:00:00 2001 From: Jordan Waters <1waterrj@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:00:11 -0400 Subject: [PATCH] Exempt the app's own render load from navigation policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CVE-2019-12173 navigation guard vetoes file:// navigations that target executables. Legacy WebView reports our own loadHTMLString:baseURL: render as a main-frame navigation of type "other" whose URL is the base URL — the document file itself. For a Markdown file with the POSIX execute bit set (common for files that ever lived on Windows/exFAT/SMB volumes), the guard therefore vetoed the entire preview load, leaving the pane permanently blank while the editor worked normally. Recognize the in-flight render load (render in progress, main frame, URL equal to the renderer base URL) and let it through before the content-navigation policy runs. Rendering a document is not executing it. The guard is unchanged for content-initiated navigations: clicking a Markdown link to an executable still raises the security alert, and out-of-scope JS navigations are still blocked. Worst case for a same-URL JS navigation during the brief render window is the raw Markdown bytes displayed as text — never execution. Verified on macOS 26.5 (Tahoe), Apple Silicon: executable-flagged files now render, normal files unaffected, executable-link guard still fires, full test suite passes (871 tests). Related to #431 --- MacDown/Code/Document/MPDocument.m | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/MacDown/Code/Document/MPDocument.m b/MacDown/Code/Document/MPDocument.m index 75cc0fea..0bd25f1a 100644 --- a/MacDown/Code/Document/MPDocument.m +++ b/MacDown/Code/Document/MPDocument.m @@ -1193,6 +1193,30 @@ - (void)webView:(WebView *)webView // Otherwise this is somewhere else on the same page. Jump there. break; default: + // Issue #431: Our own loadHTMLString:baseURL: render arrives + // here as a main-frame navigation of type "other" targeting the + // base URL (the document file itself). Rendering a document is + // not executing it, so the render load must bypass the + // content-initiated navigation policy below. Without this, a + // Markdown file with the POSIX execute bit set (common for + // files that lived on Windows/exFAT/SMB volumes) renders a + // permanently blank preview, because the executable check + // below vetoes the entire page load. + // + // A render load is identified by: a render in flight + // (alreadyRenderingInWeb), targeting the main frame, with the + // exact URL the renderer uses as its base. Worst case for a + // same-URL JS navigation slipping through this window is the + // raw Markdown bytes displayed as text — never execution. + if (self.alreadyRenderingInWeb && frame == webView.mainFrame + && url.isFileURL) + { + NSURL *renderBase = self.fileURL + ?: self.preferences.htmlDefaultDirectoryUrl; + if ([url isEqual:renderBase] + || [url isEqual:self.currentBaseUrl]) + break; + } // CVE-2019-12173: Block file:// navigations from non-user-initiated // actions (e.g., JavaScript auto-click) unless they target the // current document scope and are not executable.