zulip/zulip

ENABLE_FILE_LINKS=False is bypassable via explicit Markdown

Open

#39,628 opened on Jun 26, 2026

View on GitHub
 (4 comments) (0 reactions) (1 assignee)Python (7,339 forks)batch import
area: markdown (linkifiers)area: settings (admin/org)help wantedin progress

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 of allowed_schemes in zerver/lib/markdown/__init__.py (~line 108).
  • sanitize_url() (~line 1564) never checks settings.ENABLE_FILE_LINKS.
  • The ENABLE_FILE_LINKS gate lives only in the autolinker regex (~line 233). Explicit Markdown links skip that path and instead go through LinkInlineProcessorsanitize_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

Contributor guide