CVE-2026-24117

The Key to the Kingdom: SSRF in Sigstore Rekor

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 22, 2026·6 min read·3 visits

Executive Summary (TL;DR)

Rekor's `/api/v1/index/retrieve` endpoint allowed users to submit a URL for the server to fetch a public key. This resulted in a Blind SSRF vulnerability. Attackers could force the Rekor server to make requests to internal resources (like AWS metadata or Kubernetes APIs). The fix was a breaking change: the server no longer fetches URLs; the client must download the key first and send the bytes.

A 'convenient' feature in Sigstore's Rekor transparency log turned into a classic Server-Side Request Forgery hole. By allowing the server to fetch public keys via URL, developers inadvertently handed attackers a flashlight to explore their internal networks.

The Hook: Convenience is the Enemy of Security

Sigstore Rekor is the immutable transparency log that powers the modern software supply chain. It's supposed to be the vault where digital signatures are stored and verified. But like many secure vaults, someone decided to install a cat flap for 'usability.'

The feature in question resides in the Search Index API. Specifically, the endpoint /api/v1/index/retrieve. Its job is to help users find entries in the log associated with a specific public key. In a perfect world, you would upload the public key file, the server would hash it, and then look it up.

But uploading files is hard, right? So, the developers added a helpful little field called url inside the publicKey object. The idea was simple: "Hey Rekor, my key is over there at https://example.com/key.pub, go fetch it." Unfortunately, when you tell a server to "go fetch," you rarely get to control where it fetches from. This isn't just a feature; it's a proxy service for attackers.

The Flaw: A Classic SSRF Recipe

The vulnerability is a textbook Server-Side Request Forgery (SSRF). The root cause lies in how the SearchIndexHandler processed incoming requests. It accepted a JSON payload containing a publicKey structure. If that structure contained a url, the server passed it straight to a utility function called util.FileOrURLReadCloser.

Here is where the logic failed:

  1. No Protocol Validation: The server didn't insist on https://. It would happily talk to http:// or potentially other schemes supported by the Go HTTP client.
  2. No Allow-list: It didn't check if the destination was a trusted domain.
  3. No Network Segmentation: Crucially, it didn't block Private IP ranges (RFC 1918) or Link-Local addresses.

This means that while you thought you were asking Rekor to fetch a public key, you could actually ask it to fetch the AWS Instance Identity Document from http://169.254.169.254 or probe the Kubernetes API server on the local network. The server acts as a confused deputy, attacking the internal network on your behalf.

The Code: Before and After

The fix for this vulnerability was nuclear: they didn't just patch the validation; they ripped the feature out entirely. This is a rare example of a security fix being a "Breaking Change" by design.

The Vulnerable Logic (Conceptual Go): Inside pkg/api/index.go, the server blindly trusted the input URL.

// Vulnerable Handler Logic
func (h *APIHandler) SearchIndex(params SearchIndexParams) middleware.Responder {
    // ...
    if params.PublicKey.URL != nil {
        // DANGER: Server performs outbound request to user-supplied URL
        keyReader, err := util.FileOrURLReadCloser(*params.PublicKey.URL)
        if err != nil {
            return handleErr(err)
        }
        // ... process key ...
    }
}

The Fix (Commit 60ef2bc): The developers removed the url field from the OpenAPI spec (openapi.yaml) entirely. Now, the API only accepts the raw content of the key.

# openapi.yaml DIFF
 definitions:
   SearchIndexPublicKey:
     properties:
-      url:
-        type: string
-        format: strfmt
       content:
         type: string
         format: byte

The utility function FileOrURLReadCloser was left in the codebase (for the CLI to use), but with a stern warning added:

// This must never be called from any server codepath to prevent SSRF.

The responsibility for fetching the URL was pushed to the client (the CLI tool). The CLI now fetches the URL locally and sends the bytes to the server. This is the correct architectural pattern: Client-Side Fetch, Server-Side Process.

The Exploit: Knocking on Internal Doors

Since this is a Blind SSRF, the server doesn't just spit the response body back at you in the HTTP response (unless it crashes or leaks data in an error message). However, we can infer a lot.

Step 1: The Setup Imagine a Rekor instance running in a Kubernetes cluster on AWS. We want to see if we can reach the instance metadata service.

Step 2: The Payload We construct a request to /api/v1/index/retrieve. Instead of a public key URL, we point it at the link-local address.

POST /api/v1/index/retrieve HTTP/1.1
Host: rekor.example.com
Content-Type: application/json
 
{
  "publicKey": {
    "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
  }
}

Step 3: The Inference

  • Scenario A (Connection Refused): If we hit a closed port on localhost, the Go HTTP client might return a specific error instantly: dial tcp 127.0.0.1:xyz: connect: connection refused. This confirms the port is closed.
  • Scenario B (Timeout): If we hit an IP that doesn't exist or is firewalled, the request hangs until the server times out. This timing difference allows us to map the internal network topology.
  • Scenario C (Success-ish): If the server connects and retrieves the metadata, it will try to parse that IAM credential JSON as a PGP public key. It will obviously fail. However, the specific error message ("invalid armor", "unexpected EOF", etc.) might differ from a connection error, confirming we successfully hit a valid HTTP service.

The Impact: From Mapping to Taking Over

Why is this critical? Rekor is infrastructure plumbing. It often runs with high privileges in cloud environments to manage storage buckets or sign unrelated artifacts.

If an attacker can hit the Cloud Metadata service (AWS, GCP, Azure), they might be able to retrieve temporary credentials associated with the node (e.g., role-name). With those credentials, they can pivot from the web application vulnerability to full cloud account compromise.

Even without cloud metadata, access to http://kubernetes.default.svc allows an attacker to probe the Kubernetes API. If the pod service account is over-privileged (a common sin), they could list secrets or launch new pods. For a transparency log that relies on trust, allowing an attacker to poke holes in the hosting infrastructure undermines the entire promise of the system.

The Fix: A Hard Reset

The mitigation here isn't a firewall rule; it's an update. The Sigstore team correctly identified that this API design was fundamentally unsafe for a server environment.

For Administrators: Upgrade to Rekor v1.5.0 or later immediately. This version removes the vulnerable code path entirely. If you cannot upgrade, you can mitigate this by disabling the retrieve API using the flag --enable_retrieve_api=false.

For Developers: Learn from this. Never write a function that takes a URL from a user and fetches it on the server unless you absolutely have to (e.g., a webhook system). And if you do, you need a robust "request dispatch" layer that blocks private IPs, redirects, and non-HTTP schemes. Better yet, do what Rekor did: make the client fetch the data and send you the bytes. Don't be a proxy for bad guys.

Fix Analysis (1)

Technical Appendix

CVSS Score
9.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N

Affected Systems

Sigstore Rekor Server < v1.5.0Kubernetes clusters hosting vulnerable Rekor instancesCloud environments (AWS/GCP) exposing metadata services to Rekor pods

Affected Versions Detail

Product
Affected Versions
Fixed Version
sigstore/rekor
Sigstore
< 1.5.01.5.0
AttributeDetail
CWE IDCWE-918
Vulnerability TypeBlind SSRF
CVSS (Estimated)9.1 (Critical)
Attack VectorNetwork
Privileges RequiredNone
Breaking ChangeYes (API Field Removed)
CWE-918
Server-Side Request Forgery (SSRF)

The application does not validate or incorrectly validates a URL before fetching its content, allowing an attacker to force the application to make requests to unintended destinations.

Vulnerability Timeline

Fix commit merged to main branch
2026-01-22
Rekor v1.5.0 Released
2026-01-22
GHSA-4c4x-jm2x-pf9j Published
2026-01-22

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.