fix: escape HTML tags in inline code blocks in description (#10897)

Fix rendering of repository descriptions containing HTML symbols inside Markdown inline code block. This patch escapes content within inline code blocks.

Resolves #10770.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10897
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: oidq <oidq@oidq.dev>
Co-committed-by: oidq <oidq@oidq.dev>
This commit is contained in:
oidq 2026-01-25 23:10:56 +01:00 committed by Gusted
parent 6412ee12d0
commit 8866bf2781
3 changed files with 73 additions and 1 deletions

View file

@ -300,7 +300,7 @@ func RenderDescriptionHTML(
descriptionLinkProcessor,
emojiShortCodeProcessor,
emojiProcessor,
}, content)
}, escapeInlineCodeBlocks(content))
}
// RenderEmoji for when we want to just process emoji and shortcodes
@ -1543,3 +1543,9 @@ func optionalRepoSlugAndInstancePath(ctx *RenderContext, text *string, fullURL,
}
}
}
// escapeInlineCodeBlocks escapes HTML symbols in contents of Markdown inline code blocks
// to prevent clashing with HTML parsing
func escapeInlineCodeBlocks(input string) string {
return InlineCodeBlockRegex.ReplaceAllStringFunc(input, html.EscapeString)
}

View file

@ -615,3 +615,30 @@ func TestRegExp_shortLinkPattern(t *testing.T) {
assert.False(t, shortLinkPattern.MatchString(testCase))
}
}
func TestRender_escapeInlineCodeBlocks(t *testing.T) {
test := func(input, expected string) {
result := escapeInlineCodeBlocks(input)
assert.Equal(t, expected, result)
}
test("`<test>`",
"`&lt;test&gt;`")
test("<test>",
"<test>")
test("`<foo>` <bar> `<baz>`",
"`&lt;foo&gt;` <bar> `&lt;baz&gt;`")
test("<foo> `<bar>` <baz>",
"<foo> `&lt;bar&gt;` <baz>")
test("<foo> `<bar> <baz>",
"<foo> `<bar> <baz>")
test("<foo> `<bar>` `<baz>",
"<foo> `&lt;bar&gt;` `<baz>")
test("<foo> `<bar>` `",
"<foo> `&lt;bar&gt;` `")
test("<foo> `<bar>` ``",
"<foo> `&lt;bar&gt;` ``")
test("```",
"```")
test("``<`",
"``&lt;`")
}

View file

@ -1329,3 +1329,42 @@ func TestRender_FilePreview(t *testing.T) {
)
})
}
func TestRenderDescriptionHTML(t *testing.T) {
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
test := func(input, expected string) {
buffer, err := markup.RenderDescriptionHTML(&markup.RenderContext{
Ctx: git.DefaultContext,
}, input)
require.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
}
markup.InitializeSanitizer()
test(
"https://www.example.com",
`<a href="https://www.example.com" target="_blank" rel="noopener noreferrer">https://www.example.com</a>`)
test(
"Example repository with `Arc`",
"Example repository with `Arc`")
test(
"Example repository with `Arc` and tools.",
"Example repository with `Arc` and tools.")
test(
"`Arc<Test>` implements",
"`Arc&lt;Test&gt;` implements")
test(
"Arc<test> is broken",
"Arc<test> is broken</test>")
// issue #10770
test(
"A weird alternative to `Arc<RwLock<T>>`",
"A weird alternative to `Arc&lt;RwLock&lt;T&gt;&gt;`")
}