fix(formatter): percent-encode quotes in Markdown URLs instead of cutting

Cutting the URL at the first quote dropped the rest of valid links such
as ?q=&quot;cat&quot;&page=2. Percent-encoding ", < and > keeps the URL
complete and still keeps it inside the attribute.
This commit is contained in:
Lain Soykaf 2026-10-22 16:28:06 +04:00
commit 58d4f6aa2c
No known key found for this signature in database
3 changed files with 19 additions and 11 deletions

View file

@ -252,9 +252,13 @@ defmodule Pleroma.Formatter do
defp sanitize_markdown_url(value, name) do
if String.downcase(to_string(name)) in ["href", "src"] do
value
|> String.split(~r/["<>]/, parts: 2)
|> hd()
# Percent-encode instead of cutting, so the URL stays complete but can
# never close the attribute or open a tag.
String.replace(value, ~r/["<>]/, fn
"\"" -> "%22"
"<" -> "%3C"
">" -> "%3E"
end)
else
value
end

View file

@ -388,10 +388,9 @@ defmodule Pleroma.FormatterTest do
test "escapes link attribute values" do
markdown = ~s|[click](http://example.com/?a=x" onerror="alert(1))|
html = Formatter.markdown_to_html(markdown)
assert html =~ ~s|href="http://example.com/?a=x"|
refute html =~ "onerror"
# The quotes are percent-encoded, so everything stays inside href.
assert Formatter.markdown_to_html(markdown) ==
~s|<p><a href="http://example.com/?a=x%22 onerror=%22alert(1)">click</a></p>|
end
test "preserves entities without rendering dangerous raw HTML" do
@ -416,10 +415,15 @@ defmodule Pleroma.FormatterTest do
test "rejects entity-encoded URL delimiters" do
markdown = "[click](http://example.com/?a=x&#34;onerror=alert(1))"
html = Formatter.markdown_to_html(markdown)
assert Formatter.markdown_to_html(markdown) ==
~s|<p><a href="http://example.com/?a=x%22onerror=alert(1)">click</a></p>|
end
assert html =~ ~s|href="http://example.com/?a=x"|
refute html =~ "onerror"
test "keeps URLs with encoded quotes complete" do
markdown = "[search](https://example.org/?q=&quot;cat&quot;&page=2)"
assert Formatter.markdown_to_html(markdown) ==
~s(<p><a href="https://example.org/?q=%22cat%22&amp;page=2">search</a></p>)
end
test "strips email autolinks without changing explicit mailto links" do

View file

@ -232,7 +232,7 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
code = ~s|[click](http://example.com/?a=x" onerror="alert(1))|
{result, [], []} = Utils.format_input(code, "text/markdown")
assert result =~ ~s(<a href="http://example.com/?a=x">)
assert result =~ ~s|<a href="http://example.com/?a=x%22 onerror=%22alert(1)">|
refute result =~ ~s|onerror="alert(1)|
refute result =~ ~s(<a href="http://example.com/?a=x" onerror=)
end