← Back to Feed CACHED · 2026-08-12 14:40:03 · CACHE_KEY CVE-2026-34966
CVE-2026-34966 · CWE-918 · Disclosed 2026-08-05

Gitea prior to 1.27.0 contains a server-side request forgery vulnerability

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

Like giving a janitor with a master key a periscope into every room in the building

CVE-2026-34966 is a server-side request forgery in Gitea < 1.27.0. Three code paths — migration release-asset downloads, pull-request patch fetches, and OAuth2 avatar synchronization — call Go's bare http.Get() instead of the custom httplib client with Gitea's hostmatcher SSRF guard. An attacker who already holds admin or organization-owner privileges can craft a migration that points asset-download URLs at http://169.254.169.254/latest/meta-data/…, file:///data/gitea/conf/app.ini, or any RFC-1918 address. The response body is persisted as a release asset the attacker can later download, turning a blind SSRF into a full-read SSRF with data exfiltration. All Gitea versions from at least 1.20 through 1.26.x are affected; the fix shipped in 1.27.0 on 12 July 2026.

The vendor scored this 7.6 HIGH (CVSS 3.1) and 8.3 HIGH (CVSS 4.0). That rating is directionally correct but slightly generous for most real deployments. The PR:H requirement means the attacker must already control an admin-level Gitea account — a position that already grants read/write to every repository and every CI secret stored in Gitea. The SSRF's incremental value is lateral movement to cloud instance-metadata credentials and internal services, which is serious in cloud-hosted CI environments but conditional on IMDSv1 being available and internal services being unauthed. We shave ~0.8 points off the vendor score but keep the verdict firmly at HIGH because Gitea is, by definition, a CI/CD and source-code management component where a successful chain can cascade to supply-chain compromise.

"Admin-gated SSRF in a CI/CD forge: hard to reach, ugly when it lands"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Obtain Gitea admin or org-owner session

The attacker needs PR:H — a Gitea account with admin or organization-owner privileges. This could come from credential stuffing, a prior phishing campaign, a leaked API token, or an insider threat. Without this, the SSRF is unreachable.
Conditions required:
  • Valid admin or org-owner Gitea credentials or API token
  • Network access to the Gitea web UI or API (typically port 3000 or reverse-proxied on 443)
Where this breaks in practice:
  • Admin accounts are a small fraction of total Gitea users
  • MFA, if enforced, blocks credential-stuffing
  • SSO/OIDC login flows add a second IdP layer the attacker must also defeat
Detection/coverage: Failed login attempts visible in Gitea audit log; anomalous API token creation detectable via user.token audit events
STEP 02

Create a malicious migration manifest

The attacker uses the Gitea migration API (POST /api/v1/repos/migrate) or the web UI's 'New Migration' flow to import a repository. The migration payload includes release-asset download URLs pointing at internal targets — e.g., http://169.254.169.254/latest/meta-data/iam/security-credentials/ for AWS metadata, or file:///data/gitea/conf/app.ini for the Gitea config file containing DB credentials, JWT signing secrets, and internal OAuth2 client secrets.
Conditions required:
  • Admin session from Step 1
  • Migration feature enabled (default: enabled for admins)
Where this breaks in practice:
  • Gitea instances behind corporate proxies may not route to 169.254.169.254
  • IMDSv2 (token-required) blocks GET-only SSRF to AWS metadata
  • Non-cloud (bare-metal / VM) deployments have no metadata endpoint to hit
Detection/coverage: Migration creation logged in Gitea; WAF rules on 169.254.169.254 or file:// in request bodies can catch the payload
STEP 03

Gitea fetches attacker-controlled URLs via raw http.Get

Because the migration release-asset downloader, PR patch fetcher, and OAuth avatar code paths use Go's default http.Get() without a custom DialContext, Gitea's hostmatcher SSRF allowlist/blocklist is never consulted. The request goes directly to the attacker-specified URL, including RFC-1918 addresses, link-local metadata IPs, and file:// URIs.
Conditions required:
  • Vulnerable Gitea version < 1.27.0
Where this breaks in practice:
  • Network-level egress filtering or microsegmentation may block Gitea from reaching internal services
  • Host-based firewall on the Gitea server blocking outbound to 169.254.169.254
Detection/coverage: Network IDS/IPS signatures for metadata-endpoint access from non-instance-identity sources; DNS logging for internal hostname resolution from the Gitea pod/container
STEP 04

Exfiltrate response as a release asset

The SSRF response body is saved as a binary release asset in the newly migrated repository. The attacker downloads the asset via the Gitea UI or API, obtaining the cloud IAM temporary credentials, Gitea app.ini secrets, or internal service responses. With AWS STS credentials, the attacker can pivot to S3 buckets, EC2 instances, or other cloud resources assigned to that IAM role.
Conditions required:
  • SSRF response returns useful data (not a 403 or empty body)
  • Attacker retains access to download the release asset
Where this breaks in practice:
  • Cloud IAM roles scoped to least-privilege limit blast radius of stolen credentials
  • STS credential lifetime (typically 1-6 hours) limits the exploitation window
  • CloudTrail / GCP Audit Logs flag credential use from unexpected source IPs
Detection/coverage: CloudTrail AssumeRole / GetCallerIdentity from anomalous IP; Gitea release-asset download audit log
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNot observed. No KEV listing, no known campaigns as of 2026-08-12. No GreyNoise tags for this CVE.
Proof of ConceptNo public PoC repository identified. The attack is straightforward for anyone familiar with Gitea's migration API — no novel tooling required beyond curl.
EPSS Score0.00314 (~31st percentile) — low predicted exploitation probability in the next 30 days.
KEV StatusNot listed on CISA KEV as of 2026-08-12.
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:N — network-attackable, low complexity, but requires high privileges. Changed scope reflects SSRF reaching beyond Gitea itself.
Affected VersionsAll Gitea versions < 1.27.0 (at least back to 1.20.x). Forgejo forks may also be affected — check Forgejo advisories separately.
Fixed VersionGitea 1.27.0 (released 2026-07-12). Patch commit: b969123b7fac51c88daab5cb64e5b2f4abd53288.
Exposure DataShodan shows ~34,000 internet-facing Gitea instances globally. Roughly 4,000 appear to be production systems on major cloud/VPS platforms (SecurityWeek).
Disclosure Date2026-08-05 (CVE reserved 2026-03-31). Gitea 1.27.0 shipped the fix on 2026-07-12, ~3 weeks before public disclosure.
ReporterKhaled Nassar via Gitea's security advisory process (GHSA-2wm4-vwp6-v7xc).
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to HIGH (6.8/10)

The single most decisive factor is the PR:H (admin-level) authentication requirement, which limits the reachable attacker population to those who have already compromised a Gitea administrator account — a prerequisite that itself represents a significant prior breach. However, Gitea's canonical deployment role as a CI/CD source-code forge means a successful chain can cascade to cloud-credential theft and supply-chain compromise, which floors the verdict at HIGH despite the access friction.

HIGH Vulnerability existence and affected version range
HIGH Attack-path mechanics (raw http.Get bypass is well-documented in the commit)
MEDIUM Real-world exploitability — dependent on cloud hosting, IMDSv1, and network segmentation

Why this verdict

  • PR:H gate is real friction. The attacker must already hold admin or org-owner privileges on Gitea. This is not a low-privilege or unauthenticated bug — it assumes a prior significant compromise of the Gitea identity layer, compounding downward pressure by ~0.8 points from the vendor's 7.6.
  • Role multiplier: CI/CD source-code forge (HIGH floor). Gitea is canonically a CI/CD component. In cloud-hosted deployments, SSRF to 169.254.169.254 yields IAM credentials whose blast radius can be fleet-scale (S3, EC2, Lambda). In on-prem deployments, file:/// reads expose app.ini containing DB credentials and JWT signing keys. Both outcomes are supply-chain-adjacent. This floors the verdict at HIGH.
  • Changed scope (S:C) is earned. The SSRF escapes the Gitea application boundary to reach cloud metadata services, internal APIs, and the local filesystem — resources the attacker's admin session was never intended to access.
  • No exploitation in the wild and low EPSS (0.00314) mean there is no urgency multiplier pushing the score upward. The bug is a post-compromise lateral-movement primitive, not a first-stage entry vector.

Why not higher?

CRITICAL would require either active exploitation, unauthenticated access, or a scenario where the majority of Gitea installs are immediately exploitable. The PR:H requirement means the attacker has already breached an admin account — a non-trivial precondition. Additionally, IMDSv2 adoption on AWS (and equivalent on GCP/Azure) blocks the highest-impact cloud-metadata exfiltration path in modern deployments. The bug amplifies an existing compromise rather than creating one.

Why not lower?

Gitea is a supply-chain component by definition — it holds source code, CI secrets, and pipeline definitions. The SSRF's ability to read app.ini (DB creds, JWT secrets) and cloud IAM credentials from a single HTTP request represents a qualitative escalation beyond what even a Gitea admin should be able to do. Roughly 34,000 instances are internet-facing, with ~4,000 on cloud platforms where metadata SSRF is most dangerous. Downgrading to MEDIUM would undervalue the blast radius when the chain succeeds.

05 · Compensating Control

What to do — in priority order.

  1. Enforce IMDSv2 on all cloud instances hosting Gitea — IMDSv2 requires a PUT-based token exchange before metadata reads succeed. A GET-only SSRF like this one cannot obtain the token, completely neutralizing the cloud-credential theft path. Deploy within the noisgate HIGH mitigation SLA of 30 days if you cannot patch Gitea immediately.
  2. Disable repository migration for non-site-admin users — Set [migrations] ALLOWED_DOMAINS to an empty list or set DISABLE_MIGRATIONS = true in app.ini to eliminate the primary attack surface. This breaks legitimate migration workflows but removes the SSRF entry point entirely.
  3. Enforce MFA on all Gitea admin accounts — The PR:H requirement means MFA on admin accounts directly raises the cost of reaching the vulnerable code path. Use TOTP or WebAuthn — not email-based OTP.
  4. Network-segment the Gitea server away from sensitive internal services — Place Gitea in a DMZ or isolated VLAN with egress filtering that blocks RFC-1918, link-local (169.254.0.0/16), and localhost destinations. This limits SSRF blast radius even if the vulnerability is triggered.
  5. Rotate app.ini secrets and DB credentials after patching — If you suspect exploitation, the SSRF may have already exfiltrated app.ini. Rotate JWT_SECRET, INTERNAL_TOKEN, SECRET_KEY, LFS_JWT_SECRET, and database passwords after upgrading to 1.27.0.
What doesn't work
  • WAF rules on the Gitea reverse proxy — the SSRF is server-initiated, not client-initiated. The malicious URL is in the migration API payload body, not in the request URL. Most WAFs won't inspect JSON body fields for SSRF patterns unless explicitly configured with custom rules.
  • Gitea's built-in [migrations] ALLOWED_DOMAINS allowlist — this CVE exists precisely because the vulnerable code paths bypass the hostmatcher. The allowlist is not consulted for the affected http.Get() calls. Only upgrading to 1.27.0 fixes the bypass.
  • Rate limiting on the Gitea API — the attacker needs only a single migration request to exfiltrate data. Rate limiting does not meaningfully reduce risk.
06 · Verification

Crowdsourced verification payload.

Run this on the Gitea server itself (or any host that can reach the Gitea API). Requires curl and jq. Invoke as: bash check_cve_2026_34966.sh https://gitea.example.com. No authentication needed — it checks the version endpoint.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_34966.sh — Detect Gitea SSRF (CVE-2026-34966)
# Usage: bash check_cve_2026_34966.sh <GITEA_BASE_URL>
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN

set -euo pipefail

if [ $# -lt 1 ]; then
  echo "Usage: $0 <GITEA_BASE_URL>"
  echo "Example: $0 https://gitea.example.com"
  exit 2
fi

BASE_URL="${1%/}"

# Fetch Gitea version from the API
VERSION_JSON=$(curl -sf --max-time 10 "${BASE_URL}/api/v1/version" 2>/dev/null) || {
  echo "UNKNOWN — could not reach ${BASE_URL}/api/v1/version"
  exit 2
}

VERSION=$(echo "$VERSION_JSON" | jq -r '.version // empty' 2>/dev/null)
if [ -z "$VERSION" ]; then
  echo "UNKNOWN — could not parse version from API response"
  exit 2
fi

echo "Detected Gitea version: $VERSION"

# Compare versions: fixed in 1.27.0
# Extract major.minor.patch
IFS='.' read -r MAJOR MINOR PATCH <<< "$(echo "$VERSION" | sed 's/-.*//' | sed 's/+.*//')"
MAJOR=${MAJOR:-0}; MINOR=${MINOR:-0}; PATCH=${PATCH:-0}

FIXED_MAJOR=1; FIXED_MINOR=27; FIXED_PATCH=0

if [ "$MAJOR" -gt "$FIXED_MAJOR" ] 2>/dev/null; then
  echo "PATCHED — version $VERSION >= 1.27.0"
  exit 0
elif [ "$MAJOR" -eq "$FIXED_MAJOR" ] 2>/dev/null; then
  if [ "$MINOR" -gt "$FIXED_MINOR" ] 2>/dev/null; then
    echo "PATCHED — version $VERSION >= 1.27.0"
    exit 0
  elif [ "$MINOR" -eq "$FIXED_MINOR" ] 2>/dev/null; then
    if [ "$PATCH" -ge "$FIXED_PATCH" ] 2>/dev/null; then
      echo "PATCHED — version $VERSION >= 1.27.0"
      exit 0
    fi
  fi
fi

echo "VULNERABLE — version $VERSION < 1.27.0 (CVE-2026-34966)"
exit 1
07 · Bottom Line

If you remember one thing.

TL;DR
Upgrade Gitea to 1.27.0 immediately. The patch has been available since July 12 — there is no reason to remain on a vulnerable version. Per the noisgate mitigation SLA for HIGH-severity findings, deploy compensating controls (enforce IMDSv2, disable migrations, enforce MFA on admins) within 30 days if you cannot patch right away. The noisgate remediation SLA gives you 180 days to complete the full upgrade across all instances, but given that 1.27.0 has been stable for a month and Gitea upgrades are typically low-friction, aim to finish within 2-3 weeks. If your Gitea instance is cloud-hosted and still using IMDSv1, treat the IMDSv2 migration as equally urgent — it neutralizes the most dangerous exfiltration path regardless of Gitea version. After patching, rotate app.ini secrets (JWT_SECRET, INTERNAL_TOKEN, SECRET_KEY) and database credentials as a precaution.

Sources

  1. CVE-2026-34966 Detail — THREATINT
  2. Gitea 1.27.0 Release Notes
  3. GHSA-2wm4-vwp6-v7xc — GitHub Security Advisory
  4. Gitea 1.27.0 Patches Major Security Flaws — AlternativeTo
  5. Gitea 1.27 Delivers 45 Security Fixes — LinuxSecurity
  6. Gitea Vulnerability Exposed 30,000 Deployments — SecurityWeek
  7. Gitea June 2026 Security Release Explained — Hive Security
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.