From 565e3312385d533f96c359979a3ae7cc14eba671 Mon Sep 17 00:00:00 2001 From: Gusted Date: Wed, 17 Jan 2024 16:16:46 +0100 Subject: [PATCH] [SECURITY] Test XSS in wiki last commit information On the wiki and revisions page, information is shown about the last commit that modified that wiki page. This includes the time it was last edited and by whom. Verify it is sanitized. --- tests/integration/xss_test.go | 75 +++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/integration/xss_test.go b/tests/integration/xss_test.go index e575ed3990..42ce35150c 100644 --- a/tests/integration/xss_test.go +++ b/tests/integration/xss_test.go @@ -4,14 +4,24 @@ package integration import ( + "context" + "fmt" "net/http" + "net/url" + "os" + "path/filepath" "testing" + "time" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/tests" + gogit "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/object" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestXSSUserFullName(t *testing.T) { @@ -37,3 +47,68 @@ func TestXSSUserFullName(t *testing.T) { htmlDoc.doc.Find("div.content").Find(".header.text.center").Text(), ) } + +func TestXSSWikiLastCommitInfo(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + // Prepare the environment. + dstPath := t.TempDir() + r := fmt.Sprintf("%suser2/repo1.wiki.git", u.String()) + u, err := url.Parse(r) + assert.NoError(t, err) + u.User = url.UserPassword("user2", userPassword) + assert.NoError(t, git.CloneWithArgs(context.Background(), git.AllowLFSFiltersArgs(), u.String(), dstPath, git.CloneRepoOptions{})) + + // Use go-git here, because using git wouldn't work, it has code to remove + // `<`, `>` and `\n` in user names. Even though this is permitted and + // wouldn't result in a error by a Git server. + gitRepo, err := gogit.PlainOpen(dstPath) + require.NoError(t, err) + + w, err := gitRepo.Worktree() + require.NoError(t, err) + + filename := filepath.Join(dstPath, "Home.md") + err = os.WriteFile(filename, []byte("Oh, a XSS attack?"), 0o644) + require.NoError(t, err) + + _, err = w.Add("Home.md") + require.NoError(t, err) + + _, err = w.Commit("Yay XSS", &gogit.CommitOptions{ + Author: &object.Signature{ + Name: `Gusted`, + Email: "valid@example.org", + When: time.Date(2024, time.January, 31, 0, 0, 0, 0, time.UTC), + }, + }) + require.NoError(t, err) + + // Push. + _, _, err = git.NewCommand(git.DefaultContext, "push").AddArguments(git.ToTrustedCmdArgs([]string{"origin", "master"})...).RunStdString(&git.RunOpts{Dir: dstPath}) + require.NoError(t, err) + + // Check on page view. + t.Run("Page view", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + req := NewRequest(t, http.MethodGet, "/user2/repo1/wiki/Home") + resp := MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + + htmlDoc.AssertElement(t, "script.evil", false) + assert.Contains(t, htmlDoc.Find(".ui.sub.header").Text(), `Gusted edited this page 2024-01-31`) + }) + + // Check on revisions page. + t.Run("Revision page", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + req := NewRequest(t, http.MethodGet, "/user2/repo1/wiki/Home?action=_revision") + resp := MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + + htmlDoc.AssertElement(t, "script.evil", false) + assert.Contains(t, htmlDoc.Find(".ui.sub.header").Text(), `Gusted edited this page 2024-01-31`) + }) + }) +}