From bb448f3dc2c4909d47b92b478d94c29546aa7f12 Mon Sep 17 00:00:00 2001
From: Gusted <postmaster@gusted.xyz>
Date: Wed, 7 Aug 2024 17:04:03 +0200
Subject: [PATCH] disallow javascript: URI in the repository description

- Fixes an XSS that was introduced in
https://codeberg.org/forgejo/forgejo/pulls/1433
- This XSS allows for `href`s in anchor elements to be set to a
`javascript:` uri in the repository description, which would upon
clicking (and not upon loading) the anchor element execute the specified
javascript in that uri.
- [`AllowStandardURLs`](https://pkg.go.dev/github.com/microcosm-cc/bluemonday#Policy.AllowStandardURLs) is now called for the repository description
policy, which ensures that URIs in anchor elements are `mailto:`,
`http://` or `https://` and thereby disallowing the `javascript:` URI.
It also now allows non-relative links and sets `rel="nofollow"` on
anchor elements.
- Unit test added.
---
 modules/markup/sanitizer.go      | 1 +
 modules/markup/sanitizer_test.go | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go
index c40a3c6b65..ddc218c1b8 100644
--- a/modules/markup/sanitizer.go
+++ b/modules/markup/sanitizer.go
@@ -179,6 +179,7 @@ func createDefaultPolicy() *bluemonday.Policy {
 // repository descriptions.
 func createRepoDescriptionPolicy() *bluemonday.Policy {
 	policy := bluemonday.NewPolicy()
+	policy.AllowStandardURLs()
 
 	// Allow italics and bold.
 	policy.AllowElements("i", "b", "em", "strong")
diff --git a/modules/markup/sanitizer_test.go b/modules/markup/sanitizer_test.go
index 56b2fcf474..4441a41544 100644
--- a/modules/markup/sanitizer_test.go
+++ b/modules/markup/sanitizer_test.go
@@ -84,12 +84,15 @@ func TestDescriptionSanitizer(t *testing.T) {
 		`<span class="emoji" aria-label="thumbs up">THUMBS UP</span>`, `<span class="emoji" aria-label="thumbs up">THUMBS UP</span>`,
 		`<span style="color: red">Hello World</span>`, `<span>Hello World</span>`,
 		`<br>`, ``,
-		`<a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a>`, `<a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a>`,
+		`<a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a>`, `<a href="https://example.com" target="_blank" rel="noopener noreferrer nofollow">https://example.com</a>`,
 		`<mark>Important!</mark>`, `Important!`,
 		`<details>Click me! <summary>Nothing to see here.</summary></details>`, `Click me! Nothing to see here.`,
 		`<input type="hidden">`, ``,
 		`<b>I</b> have a <i>strong</i> <strong>opinion</strong> about <em>this</em>.`, `<b>I</b> have a <i>strong</i> <strong>opinion</strong> about <em>this</em>.`,
 		`Provides alternative <code>wg(8)</code> tool`, `Provides alternative <code>wg(8)</code> tool`,
+		`<a href="javascript:alert('xss')">Click me</a>.`, `Click me.`,
+		`<a href="data:text/html,<script>alert('xss')</script>">Click me</a>.`, `Click me.`,
+		`<a href="vbscript:msgbox("xss")">Click me</a>.`, `Click me.`,
 	}
 
 	for i := 0; i < len(testCases); i += 2 {