ENABLE_FILE_LINKS=False is bypassable via explicit Markdown
#39,628 opened on Jun 26, 2026
Repository metrics
- Stars
- (19,672 stars)
- PR merge metrics
- (Avg merge 36d 6h) (110 merged PRs in 30d)
Description
Description
ENABLE_FILE_LINKS only gates autolinked bare file:///… URLs. Explicit Markdown links still render as clickable file:// links even when the setting is off — which is the default, including in production.
Steps to reproduce
With ENABLE_FILE_LINKS=False (the default), send a message containing:
[click me](file:///etc/passwd)
Expected: the link is not rendered as a file:// hyperlink, consistent with the setting being disabled.
Actual: it renders as a clickable <a href="file:///etc/passwd">. The bare-URL form (file:///etc/passwd on its own) is correctly suppressed, but the explicit [...](...) form is not.
I also confirmed sanitize_url() returns file:///etc/passwd (and file://host/share) unchanged regardless of the setting.
Root cause
"file"is unconditionally part ofallowed_schemesinzerver/lib/markdown/__init__.py(~line 108).sanitize_url()(~line 1564) never checkssettings.ENABLE_FILE_LINKS.- The
ENABLE_FILE_LINKSgate lives only in the autolinker regex (~line 233). Explicit Markdown links skip that path and instead go throughLinkInlineProcessor→sanitize_url()(~line 2105), which has no such gate.
Impact
Low. This is not an XSS — javascript:/data:/vbscript: are still correctly stripped. In the web client, browsers block file:// navigation, so impact there is essentially nil. It's mostly relevant to native/desktop clients where file:// isn't browser-blocked. Realistically it's a "the setting doesn't fully do what it says" consistency issue rather than an exploitable vulnerability.
Suggested fix
Make the file scheme conditional on settings.ENABLE_FILE_LINKS inside sanitize_url() so both link forms behave consistently, and add a test for the [label](file:///…) case alongside the existing bare-URL test in zerver/tests/test_markdown.py (~line 584).
CZO thread: #issues > ENABLE_FILE_LINKS=False is bypassable via explicit Markdown