[AutoPR- Security] Patch skopeo for CVE-2026-24117 [MEDIUM]#15895
[AutoPR- Security] Patch skopeo for CVE-2026-24117 [MEDIUM]#15895azurelinux-security wants to merge 2 commits intomicrosoft:mainfrom
Conversation
|
The below vendor files are not available in azl source code. |
|
Buddy Build has passed. |
🔒 CVE Patch Review: CVE-2026-24117PR #15895 — [AutoPR- Security] Patch skopeo for CVE-2026-24117 [MEDIUM] Spec File Validation
Build Verification
🤖 AI Build Log Analysis
🧪 Test Log Analysis
🤖 AI Test Log Analysis
Patch Analysis
Detailed analysisUpstream fix (GHSA-4c4x-jm2x-pf9j) centers on eliminating server-side fetching of public keys by URL to mitigate blind SSRF. Key upstream changes include: (1) pkg/api/index.go switching SearchIndexHandler to create a reader from PublicKey.Content only, removing any use of a URL; (2) removal of the publicKey.url field from the API spec and generated server/client code; (3) updating CLI code to avoid raw http.Get and to read URL content client-side into PublicKey.Content; and (4) hardening util.FileOrURLReadCloser with a timeout and an explicit SSRF warning. The PR patch, applied under vendor/github.com/sigstore/rekor/, makes only three changes: (a) it updates the generated client entries_client.go description by removing mention of server-side URL fetching; (b) it removes the URL field and its validation from the generated SearchIndexPublicKey model; and (c) it updates util/fetch.go to add a 30-second timeout and SSRF warning in comments. It does not modify the server handler (pkg/api/index.go), the CLI (cmd/rekor-cli/app/search.go), or any OpenAPI/embedded spec files. Functionally, the most important upstream mitigation is the server-side removal of URL fetching. The PR does not implement that and so is not equivalent to the upstream patch from a security perspective. If the vendored Rekor code in skopeo does not include or use server paths (which is likely for a client-only package), the immediate SSRF risk within skopeo is low; however, strictly comparing to upstream, the absence of the server-side change and spec updates means the PR is incomplete. Additionally, without updating the OpenAPI/embedded spec in environments that use them, there could be mismatches between model and spec (model no longer has publicKey.url while spec may still describe it), potentially causing confusion or client/server interoperability issues. Therefore, the differences are significant and the risk of an incomplete mitigation is assessed as medium overall. Raw diff (upstream vs PR)--- upstream
+++ pr
@@ -1,262 +1,114 @@
-From 60ef2bceba192c5bf9327d003bceea8bf1f8275f Mon Sep 17 00:00:00 2001
-From: Hayden <8418760+Hayden-IO@users.noreply.github.com>
-Date: Wed, 21 Jan 2026 16:52:44 -0800
-Subject: [PATCH] Drop support for fetching public keys by URL in the search
- index (#2731)
-
-This mitigates blind SSRF. Note that this API was marked as experimental
-so while this is a breaking change to the API, we offered no guarantee
-of stability.
-
-Fixes GHSA-4c4x-jm2x-pf9j
-
-Signed-off-by: Hayden <8418760+Hayden-IO@users.noreply.github.com>
----
- cmd/rekor-cli/app/search.go | 18 ++++++++++++-----
- openapi.yaml | 4 ----
- pkg/api/index.go | 7 ++-----
- .../client/entries/entries_client.go | 2 +-
- pkg/generated/models/search_index.go | 20 -------------------
- pkg/generated/restapi/embedded_spec.go | 16 ++-------------
- .../operations/entries/create_log_entry.go | 2 +-
- pkg/util/fetch.go | 10 +++++++---
- 8 files changed, 26 insertions(+), 53 deletions(-)
-
-diff --git a/cmd/rekor-cli/app/search.go b/cmd/rekor-cli/app/search.go
-index b92b6d5b8..17f07e498 100644
---- a/cmd/rekor-cli/app/search.go
-+++ b/cmd/rekor-cli/app/search.go
-@@ -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 {
-diff --git a/openapi.yaml b/openapi.yaml
-index 638fec004..f67f3724c 100644
---- a/openapi.yaml
-+++ b/openapi.yaml
-@@ -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:
-diff --git a/pkg/api/index.go b/pkg/api/index.go
-index 7d958c5cb..f7961859d 100644
---- a/pkg/api/index.go
-+++ b/pkg/api/index.go
-@@ -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 {
-diff --git a/pkg/generated/client/entries/entries_client.go b/pkg/generated/client/entries/entries_client.go
-index f893db3dc..24f633cf6 100644
---- a/pkg/generated/client/entries/entries_client.go
-+++ b/pkg/generated/client/entries/entries_client.go
-@@ -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
-diff --git a/pkg/generated/models/search_index.go b/pkg/generated/models/search_index.go
-index a1b7d0800..98f7ee84c 100644
---- a/pkg/generated/models/search_index.go
-+++ b/pkg/generated/models/search_index.go
-@@ -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
-diff --git a/pkg/generated/restapi/embedded_spec.go b/pkg/generated/restapi/embedded_spec.go
-index d58691ef3..2054712d2 100644
---- a/pkg/generated/restapi/embedded_spec.go
-+++ b/pkg/generated/restapi/embedded_spec.go
-@@ -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"
- }
- }
- },
-diff --git a/pkg/generated/restapi/operations/entries/create_log_entry.go b/pkg/generated/restapi/operations/entries/create_log_entry.go
-index b1638ad68..cf2488864 100644
---- a/pkg/generated/restapi/operations/entries/create_log_entry.go
-+++ b/pkg/generated/restapi/operations/entries/create_log_entry.go
-@@ -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
-diff --git a/pkg/util/fetch.go b/pkg/util/fetch.go
-index 7f8e93fb0..5c5c4640d 100644
---- a/pkg/util/fetch.go
-+++ b/pkg/util/fetch.go
-@@ -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
+diff --git a/SPECS/skopeo/CVE-2026-24117.patch b/SPECS/skopeo/CVE-2026-24117.patch
+new file mode 100644
+index 00000000000..75cc90da0c7
+--- /dev/null
++++ b/SPECS/skopeo/CVE-2026-24117.patch
+@@ -0,0 +1,108 @@
++From 60ef2bceba192c5bf9327d003bceea8bf1f8275f Mon Sep 17 00:00:00 2001
++From: Hayden <8418760+Hayden-IO@users.noreply.github.com>
++Date: Wed, 21 Jan 2026 16:52:44 -0800
++Subject: [PATCH] Drop support for fetching public keys by URL in the search
++ index (#2731)
++
++This mitigates blind SSRF. Note that this API was marked as experimental
++so while this is a breaking change to the API, we offered no guarantee
++of stability.
++
++Fixes GHSA-4c4x-jm2x-pf9j
++
++Signed-off-by: Hayden <8418760+Hayden-IO@users.noreply.github.com>
++
++Upstream Patch reference: https://github.com/sigstore/rekor/commit/60ef2bceba192c5bf9327d003bceea8bf1f8275f.patch
++---
++ .../client/entries/entries_client.go | 2 +-
++ .../pkg/generated/models/search_index.go | 20 -------------------
++ .../sigstore/rekor/pkg/util/fetch.go | 10 +++++++---
++ 3 files changed, 8 insertions(+), 24 deletions(-)
++
++diff --git a/vendor/github.com/sigstore/rekor/pkg/generated/client/entries/entries_client.go b/vendor/github.com/sigstore/rekor/pkg/generated/client/entries/entries_client.go
++index fe2630e..668ec29 100644
++--- a/vendor/github.com/sigstore/rekor/pkg/generated/client/entries/entries_client.go
+++++ b/vendor/github.com/sigstore/rekor/pkg/generated/client/entries/entries_client.go
++@@ -58,7 +58,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) {
++ // TODO: Validate the params before sending
++diff --git a/vendor/github.com/sigstore/rekor/pkg/generated/models/search_index.go b/vendor/github.com/sigstore/rekor/pkg/generated/models/search_index.go
++index bb1cccc..e731a3b 100644
++--- a/vendor/github.com/sigstore/rekor/pkg/generated/models/search_index.go
+++++ b/vendor/github.com/sigstore/rekor/pkg/generated/models/search_index.go
++@@ -229,10 +229,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
++@@ -243,10 +239,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...)
++ }
++@@ -305,18 +297,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
++diff --git a/vendor/github.com/sigstore/rekor/pkg/util/fetch.go b/vendor/github.com/sigstore/rekor/pkg/util/fetch.go
++index 7f8e93f..5c5c464 100644
++--- a/vendor/github.com/sigstore/rekor/pkg/util/fetch.go
+++++ b/vendor/github.com/sigstore/rekor/pkg/util/fetch.go
++@@ -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
++--
++2.43.0
++
Verdict❌ CHANGES REQUESTED — Please address the issues flagged above. |
Auto Patch skopeo for CVE-2026-24117.
Autosec pipeline run -> https://dev.azure.com/mariner-org/mariner/_build/results?buildId=1051463&view=results
Merge Checklist
All boxes should be checked before merging the PR (just tick any boxes which don't apply to this PR)
*-staticsubpackages, etc.) have had theirReleasetag incremented../cgmanifest.json,./toolkit/scripts/toolchain/cgmanifest.json,.github/workflows/cgmanifest.json)./LICENSES-AND-NOTICES/SPECS/data/licenses.json,./LICENSES-AND-NOTICES/SPECS/LICENSES-MAP.md,./LICENSES-AND-NOTICES/SPECS/LICENSE-EXCEPTIONS.PHOTON)*.signatures.jsonfilessudo make go-tidy-allandsudo make go-test-coveragepassSummary
What does the PR accomplish, why was it needed?
Change Log
Does this affect the toolchain?
YES/NO
Associated issues
Links to CVEs
Test Methodology