Gitea 1.22.0 - Stored XSS

Exploit Author: Catalin Iovita, Alexandru Postolache Analysis Author: www.bubbleslearn.ir Category: WebApps Language: Go Published Date: 2024-08-28
# Exploit Title: Stored XSS in Gitea
# Date: 27/08/2024
# Exploit Authors: Catalin Iovita & Alexandru Postolache
# Vendor Homepage: (https://github.com/go-gitea/gitea)
# Version: 1.22.0
# Tested on: Linux 5.15.0-107, Go 1.23.0
# CVE: CVE-2024-6886

## Vulnerability Description
Gitea 1.22.0 is vulnerable to a Stored Cross-Site Scripting (XSS) vulnerability. This vulnerability allows an attacker to inject malicious scripts that get stored on the server and executed in the context of another user's session.

## Steps to Reproduce
1. Log in to the application.
2. Create a new repository or modify an existing repository by clicking the Settings button from the `$username/$repo_name/settings` endpoint.
3. In the Description field, input the following payload:

    <a href=javascript:alert()>XSS test</a>

4. Save the changes.
5. Upon clicking the repository description, the payload was successfully injected in the Description field. By clicking on the message, an alert box will appear, indicating the execution of the injected script.


Gitea 1.22.0 — Stored XSS (CVE-2024-6886)

This article explains the Stored Cross‑Site Scripting (XSS) issue reported against Gitea 1.22.0 (CVE-2024-6886), its impact, detection techniques, and practical mitigation and hardening strategies for operators and developers. The goal is to provide accurate, defensible guidance without enabling exploit reproduction.

Summary and impact

Stored XSS occurs when an application accepts attacker-controlled input, saves it on the server, and later renders it inside a page without sufficient output encoding or sanitization. In this case, a crafted repository description could persist in Gitea and be rendered in other users' browsers, allowing script execution in the victim’s session context.

  • Affected software: Gitea 1.22.0 (reported as vulnerable)
  • CVE identifier: CVE‑2024‑6886
  • Impact: Execution of attacker-controlled JavaScript in the context of a victim user — possible session token theft, CSRF-like actions, UI redressing, or other client-side attacks.
  • Risk: High for instances with public or collaborative repositories, or any environment where users trust rendered repository metadata.

How the vulnerability is typically abused (high level)

An attacker who can edit repository metadata (for example, the repository description) stores crafted content that the application later renders into HTML pages without proper escaping. When another user views or interacts with that description, the browser interprets the malicious content and executes the attacker's script. This is a classic stored XSS scenario — the difference from reflected XSS is that the malicious payload is stored on the server.

Detection and indicators

Administrators and incident responders can look for indicators of stored XSS attempts and potential exploitation using both automated and manual checks.

  • Search repository descriptions and other user-controlled metadata for raw HTML tags, "javascript:" URIs, event attributes (e.g., onclick), or encoded script fragments.
  • Check server logs and audit trails for unexpected description edits or content changes tied to accounts that shouldn’t perform them.
  • Use the Gitea API to enumerate repositories and dump descriptions for offline scanning (see safe search patterns below).
  • Monitor web application logs for increased JavaScript errors on pages that render repository metadata — errors may indicate attempted script execution.

Safe scanning example (admin-side)

# Example: fetch repository metadata via the API and search for suspicious characters
# (This is a conceptual example — apply rate limits, auth, and safe handling for sensitive data.)
curl -s -H "Authorization: token YOUR_TOKEN" "https://gitea.example/api/v1/user/repos" | \
  jq -r '.[].description' | grep -n --color=always -E '\<|javascript:|on[a-z]+='

Explanation: This snippet demonstrates a defensive scan pattern that pulls repository descriptions and searches for characters and substrings commonly associated with inline HTML/script content. It is intended for administrators to detect possible malicious or unsafe stored content at scale. Replace jq and curl usage with your environment's tooling and ensure API access is properly secured.

Short-term mitigations for administrators

  • Immediately upgrade to a patched Gitea release when available. If a vendor patch is not yet applied, consider temporary mitigations below.
  • Restrict who can edit repository metadata (limit to trusted roles) until you can apply a patch.
  • Disable HTML rendering of free‑form fields (e.g., repository description) in templates, or escape output when rendering those fields.
  • Apply a Content Security Policy (CSP) that reduces the impact of XSS (e.g., disallow inline scripts with script-src 'self' and avoid 'unsafe-inline').
  • Rotate sensitive credentials, tokens, or OAuth app secrets if you suspect compromise or exploitation.

Long-term fixes and coding best practices

To eliminate stored XSS vulnerabilities, developers should adopt a defense-in-depth approach centered on proper input handling, output encoding, and secure rendering practices:

  • Always escape user-provided content on output. In Go templates, use html/template which performs automatic escaping for data inserted into templates.
  • If HTML input is permitted, sanitize it using a well-maintained HTML sanitizer library that enforces a tight whitelist (allowed tags and attributes). Do not implement ad-hoc sanitization logic.
  • Use a Content Security Policy to reduce the impact of any injected scripts that might bypass sanitization.
  • Avoid using dangerously-permissive helpers that insert raw HTML unless content has been validated and sanitized.
  • Employ automated security testing (unit tests for sanitization, SAST tools, dynamic scans) as part of CI to catch regressions.

Example: sanitizing repository descriptions in Go (recommended pattern)

package main

import (
    "fmt"
    "github.com/microcosm-cc/bluemonday"
)

// sanitizeDescription applies a strict policy for user-supplied repository descriptions.
// It allows a small safe subset of HTML or returns plain text when needed.
func sanitizeDescription(input string) string {
    // UGCPolicy permits a reasonable set for user-generated content, adjust as needed.
    policy := bluemonday.UGCPolicy()
    // Optionally tighten the policy:
    policy.AllowAttrs("href").OnElements("a")
    // Sanitize and return a safe HTML string.
    return policy.Sanitize(input)
}

func main() {
    raw := `alert('x')Project info`
    safe := sanitizeDescription(raw)
    fmt.Println(safe)
}

Explanation: This Go example uses the bluemonday library to sanitize user-provided strings before storing or rendering them. bluemonday.UGCPolicy() provides a default whitelist suited to user-generated content, and you can tighten or expand allowed tags/attributes as necessary. The sanitized output should then be safely rendered in templates without reintroducing raw HTML insertion risks.

Example: safe rendering with Go html/template

package main

import (
    "html/template"
    "net/http"
)

var pageTpl = template.Must(template.New("page").Parse(`


{{.RepoName}}

{{.SanitizedDescription}}
`)) // Handler uses a sanitized description (string) and lets html/template escape content safely. func handler(w http.ResponseWriter, r *http.Request) { data := struct { RepoName string SanitizedDescription string }{ RepoName: "example", SanitizedDescription: "<b>Project</b> info", // or sanitized HTML if using safe subset } pageTpl.Execute(w, data) }

Explanation: The html/template package automatically escapes values inserted into templates, preventing raw HTML from being interpreted by the browser. If you must render a sanitized HTML fragment, only use template.HTML on content that has been validated/sanitized by a trusted library; otherwise, keep user input as plain text so it is escaped.

Content Security Policy (CSP) example

Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'

Explanation: A strict CSP reduces the blast radius of an XSS vulnerability by restricting where scripts can be loaded from and preventing loading of plugins/frames. Note that CSP is a mitigation, not a replacement for proper input/output handling.

Recommended incident response steps

  • Patch or upgrade Gitea to a version that explicitly addresses CVE‑2024‑6886 as soon as it is available from the vendor.
  • Search repository descriptions and other stored metadata for suspicious content and remove or sanitize any unsafe entries.
  • Examine audit logs to determine whether untrusted users edited repository metadata and whether any web sessions showed unusual activity.
  • Notify impacted users and rotate credentials or tokens if there is evidence of compromise.
  • Implement the hardening steps above to avoid recurrence.
ItemRecommendation
Immediate actionApply vendor patch / restrict metadata edits
Short-term mitigationEscape outputs, disable HTML rendering, enable CSP
Developer fixSanitize inputs with whitelist and use html/template
MonitoringScan repo metadata, review logs, audit tokens

Responsible disclosure and upgrade guidance

If you run a Gitea instance, follow the vendor guidance and release notes for the official patch addressing CVE‑2024‑6886. Prioritize production instances, especially those with public or multi-user access. Where an immediate patch cannot be applied, use the short-term mitigations described above and consider taking administrative actions to reduce risk until a vendor fix is installed.

Conclusion

Stored XSS remains one of the most impactful client-side vulnerabilities because it can be injected once and affect many users. The right combination of secure output encoding, vetted HTML sanitization, strict CSP, and careful access controls will protect Gitea deployments from this class of issues. Apply vendor patches promptly and adopt secure coding and CI practices to prevent regressions.