Rekor affected by Server-Side Request Forgery (SSRF) via provided public key URL
Description
Rekor is a software supply chain transparency log. In versions 1.4.3 and below, attackers can trigger SSRF to arbitrary internal services because /api/v1/index/retrieve supports retrieving a public key via user-provided URL. Since the SSRF only can trigger GET requests, the request cannot mutate state. The response from the GET request is not returned to the caller so data exfiltration is not possible. A malicious actor could attempt to probe an internal network through Blind SSRF. The issue has been fixed in version 1.5.0. To workaround this issue, disable the search endpoint with --enable_retrieve_api=false.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/sigstore/rekorGo | < 1.5.0 | 1.5.0 |
Affected products
1Patches
160ef2bceba19Drop support for fetching public keys by URL in the search index (#2731)
8 files changed · +26 −53
cmd/rekor-cli/app/search.go+13 −5 modified@@ -115,13 +115,12 @@ var searchCmd = &cobra.Command{ hasher := sha256.New() var tee io.Reader if isURL(artifactStr) { - /* #nosec G107 */ - resp, err := http.Get(artifactStr) + r, err := util.FileOrURLReadCloser(cmd.Context(), artifactStr, nil) if err != nil { return nil, fmt.Errorf("error fetching '%v': %w", artifactStr, err) } - defer resp.Body.Close() - tee = io.TeeReader(resp.Body, hasher) + defer r.Close() + tee = io.TeeReader(r, hasher) } else { file, err := os.Open(filepath.Clean(artifactStr)) if err != nil { @@ -167,7 +166,16 @@ var searchCmd = &cobra.Command{ splitPubKeyString := strings.Split(publicKeyStr, ",") if len(splitPubKeyString) == 1 { if isURL(splitPubKeyString[0]) { - params.Query.PublicKey.URL = strfmt.URI(splitPubKeyString[0]) + r, err := util.FileOrURLReadCloser(cmd.Context(), splitPubKeyString[0], nil) + if err != nil { + return nil, fmt.Errorf("error fetching '%v': %w", splitPubKeyString[0], err) + } + defer r.Close() + c, err := io.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("error reading public key from '%v': %w", splitPubKeyString[0], err) + } + params.Query.PublicKey.Content = c } else { keyBytes, err := os.ReadFile(filepath.Clean(splitPubKeyString[0])) if err != nil {
openapi.yaml+0 −4 modified@@ -140,7 +140,6 @@ paths: summary: Creates an entry in the transparency log description: > Creates an entry in the transparency log for a detached signature, public key, and content. - Items can be included in the request or fetched by the server when URLs are specified. operationId: createLogEntry tags: - entries @@ -496,9 +495,6 @@ definitions: content: type: string format: byte - url: - type: string - format: uri required: - "format" hash:
pkg/api/index.go+2 −5 modified@@ -16,6 +16,7 @@ package api import ( + "bytes" "context" "crypto/sha256" "encoding/hex" @@ -62,11 +63,7 @@ func SearchIndexHandler(params index.SearchIndexParams) middleware.Responder { if err != nil { return handleRekorAPIError(params, http.StatusBadRequest, err, unsupportedPKIFormat) } - keyReader, err := util.FileOrURLReadCloser(httpReqCtx, params.Query.PublicKey.URL.String(), params.Query.PublicKey.Content) - if err != nil { - return handleRekorAPIError(params, http.StatusBadRequest, err, malformedPublicKey) - } - defer keyReader.Close() + keyReader := bytes.NewReader(params.Query.PublicKey.Content) key, err := af.NewPublicKey(keyReader) if err != nil {
pkg/generated/client/entries/entries_client.go+1 −1 modified@@ -84,7 +84,7 @@ type ClientService interface { /* CreateLogEntry creates an entry in the transparency log -Creates an entry in the transparency log for a detached signature, public key, and content. Items can be included in the request or fetched by the server when URLs are specified. +Creates an entry in the transparency log for a detached signature, public key, and content. */ func (a *Client) CreateLogEntry(params *CreateLogEntryParams, opts ...ClientOption) (*CreateLogEntryCreated, error) { // NOTE: parameters are not validated before sending
pkg/generated/models/search_index.go+0 −20 modified@@ -238,10 +238,6 @@ type SearchIndexPublicKey struct { // Required: true // Enum: ["pgp","x509","minisign","ssh","tuf"] Format *string `json:"format"` - - // url - // Format: uri - URL strfmt.URI `json:"url,omitempty"` } // Validate validates this search index public key @@ -252,10 +248,6 @@ func (m *SearchIndexPublicKey) Validate(formats strfmt.Registry) error { res = append(res, err) } - if err := m.validateURL(formats); err != nil { - res = append(res, err) - } - if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -314,18 +306,6 @@ func (m *SearchIndexPublicKey) validateFormat(formats strfmt.Registry) error { return nil } -func (m *SearchIndexPublicKey) validateURL(formats strfmt.Registry) error { - if swag.IsZero(m.URL) { // not required - return nil - } - - if err := validate.FormatOf("publicKey"+"."+"url", "body", "uri", m.URL.String(), formats); err != nil { - return err - } - - return nil -} - // ContextValidate validates this search index public key based on context it is used func (m *SearchIndexPublicKey) ContextValidate(ctx context.Context, formats strfmt.Registry) error { return nil
pkg/generated/restapi/embedded_spec.go+2 −14 modified@@ -144,7 +144,7 @@ func init() { } }, "post": { - "description": "Creates an entry in the transparency log for a detached signature, public key, and content. Items can be included in the request or fetched by the server when URLs are specified.\n", + "description": "Creates an entry in the transparency log for a detached signature, public key, and content.\n", "tags": [ "entries" ], @@ -589,10 +589,6 @@ func init() { "ssh", "tuf" ] - }, - "url": { - "type": "string", - "format": "uri" } } } @@ -1074,7 +1070,7 @@ func init() { } }, "post": { - "description": "Creates an entry in the transparency log for a detached signature, public key, and content. Items can be included in the request or fetched by the server when URLs are specified.\n", + "description": "Creates an entry in the transparency log for a detached signature, public key, and content.\n", "tags": [ "entries" ], @@ -2719,10 +2715,6 @@ func init() { "ssh", "tuf" ] - }, - "url": { - "type": "string", - "format": "uri" } } } @@ -2747,10 +2739,6 @@ func init() { "ssh", "tuf" ] - }, - "url": { - "type": "string", - "format": "uri" } } },
pkg/generated/restapi/operations/entries/create_log_entry.go+1 −1 modified@@ -50,7 +50,7 @@ func NewCreateLogEntry(ctx *middleware.Context, handler CreateLogEntryHandler) * # Creates an entry in the transparency log -Creates an entry in the transparency log for a detached signature, public key, and content. Items can be included in the request or fetched by the server when URLs are specified. +Creates an entry in the transparency log for a detached signature, public key, and content. */ type CreateLogEntry struct { Context *middleware.Context
pkg/util/fetch.go+7 −3 modified@@ -21,14 +21,18 @@ import ( "fmt" "io" "net/http" + "time" ) -// FileOrURLReadCloser Note: caller is responsible for closing ReadCloser returned from method! +// FileOrURLReadCloser reads content either from a URL or a byte slice +// Note: Caller is responsible for closing the returned ReadCloser +// Note: This must never be called from any server codepath to prevent SSRF func FileOrURLReadCloser(ctx context.Context, url string, content []byte) (io.ReadCloser, error) { var dataReader io.ReadCloser if url != "" { - //TODO: set timeout here, SSL settings? - client := &http.Client{} + client := &http.Client{ + Timeout: 30 * time.Second, + } req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return nil, err
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-4c4x-jm2x-pf9jghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-24117ghsaADVISORY
- github.com/sigstore/rekor/commit/60ef2bceba192c5bf9327d003bceea8bf1f8275fghsax_refsource_MISCWEB
- github.com/sigstore/rekor/releases/tag/v1.5.0ghsax_refsource_MISCWEB
- github.com/sigstore/rekor/security/advisories/GHSA-4c4x-jm2x-pf9jghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.