VYPR
Medium severity5.8OSV Advisory· Published Jan 23, 2026· Updated Apr 15, 2026

CVE-2026-24137

CVE-2026-24137

Description

sigstore framework is a common go library shared across sigstore services and clients. In versions 1.10.3 and below, the legacy TUF client (pkg/tuf/client.go) supports caching target files to disk. It constructs a filesystem path by joining a cache base directory with a target name sourced from signed target metadata; however, it does not validate that the resulting path stays within the cache base directory. A malicious TUF repository can trigger arbitrary file overwriting, limited to the permissions that the calling process has. Note that this should only affect clients that are directly using the TUF client in sigstore/sigstore or are using an older version of Cosign. Public Sigstore deployment users are unaffected, as TUF metadata is validated by a quorum of trusted collaborators. This issue has been fixed in version 1.10.4. As a workaround, users can disable disk caching for the legacy client by setting SIGSTORE_NO_CACHE=true in the environment, migrate to https://github.com/sigstore/sigstore-go/tree/main/pkg/tuf, or upgrade to the latest sigstore/sigstore release.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/sigstore/sigstoreGo
< 1.10.41.10.4

Affected products

1
  • Range: pkg/signature/kms/aws/v1.10.0, pkg/signature/kms/aws/v1.10.2, pkg/signature/kms/aws/v1.10.3, …

Patches

1
8ec410a2993e

Escape target name - GHSA-fcv2-xgw5-pqxf (#2265)

https://github.com/sigstore/sigstoreHaydenJan 22, 2026via ghsa
2 files changed · +96 2
  • pkg/tuf/client.go+6 2 modified
    @@ -671,12 +671,16 @@ type diskCache struct {
     	memory *memoryCache
     }
     
    +func (d *diskCache) safePath(p string) string {
    +	return filepath.FromSlash(filepath.Join(d.base, url.PathEscape(p)))
    +}
    +
     func (d *diskCache) Get(p string) ([]byte, error) {
     	// Read from the in-memory cache first.
     	if b, err := d.memory.Get(p); err == nil {
     		return b, nil
     	}
    -	fp := filepath.FromSlash(filepath.Join(d.base, p))
    +	fp := d.safePath(p)
     	return os.ReadFile(fp)
     }
     
    @@ -685,7 +689,7 @@ func (d *diskCache) Set(p string, b []byte) error {
     		return err
     	}
     
    -	fp := filepath.FromSlash(filepath.Join(d.base, p))
    +	fp := d.safePath(p)
     	if err := os.MkdirAll(filepath.Dir(fp), 0o700); err != nil {
     		return fmt.Errorf("creating targets dir: %w", err)
     	}
    
  • pkg/tuf/client_test.go+90 0 modified
    @@ -894,3 +894,93 @@ func Test_remoteFromMirror(t *testing.T) {
     		t.Fatalf("unexpected error with GCS mirror: %v", err)
     	}
     }
    +
    +func TestDiskCache_safePath(t *testing.T) {
    +	tests := []struct {
    +		name     string
    +		base     string
    +		input    string
    +		expected string
    +	}{
    +		{
    +			name:     "simple filename",
    +			base:     "/tmp/cache",
    +			input:    "target.json",
    +			expected: filepath.Join("/tmp/cache", "target.json"),
    +		},
    +		{
    +			name:     "path with subdirectory",
    +			base:     "/tmp/cache",
    +			input:    "subdir/target.json",
    +			expected: filepath.Join("/tmp/cache", "subdir%2Ftarget.json"),
    +		},
    +		{
    +			name:     "path traversal attempt with ..",
    +			base:     "/tmp/cache",
    +			input:    "../../../etc/passwd",
    +			expected: filepath.Join("/tmp/cache", "..%2F..%2F..%2Fetc%2Fpasswd"),
    +		},
    +		{
    +			name:     "path with leading slash",
    +			base:     "/tmp/cache",
    +			input:    "/etc/passwd",
    +			expected: filepath.Join("/tmp/cache", "%2Fetc%2Fpasswd"),
    +		},
    +		{
    +			name:     "path with special characters",
    +			base:     "/tmp/cache",
    +			input:    "file with spaces.json",
    +			expected: filepath.Join("/tmp/cache", "file%20with%20spaces.json"),
    +		},
    +		{
    +			name:     "path with URL-encoded characters",
    +			base:     "/tmp/cache",
    +			input:    "file%2Fname.json",
    +			expected: filepath.Join("/tmp/cache", "file%252Fname.json"),
    +		},
    +		{
    +			name:     "empty input",
    +			base:     "/tmp/cache",
    +			input:    "",
    +			expected: filepath.Join("/tmp/cache", ""),
    +		},
    +		{
    +			name:     "path with backslash",
    +			base:     "/tmp/cache",
    +			input:    "..\\..\\etc\\passwd",
    +			expected: filepath.Join("/tmp/cache", "..%5C..%5Cetc%5Cpasswd"),
    +		},
    +		{
    +			name:     "path with null byte",
    +			base:     "/tmp/cache",
    +			input:    "file\x00.json",
    +			expected: filepath.Join("/tmp/cache", "file%00.json"),
    +		},
    +		{
    +			name:     "deeply nested path traversal",
    +			base:     "/tmp/cache",
    +			input:    "a/../b/../c/../../../etc/passwd",
    +			expected: filepath.Join("/tmp/cache", "a%2F..%2Fb%2F..%2Fc%2F..%2F..%2F..%2Fetc%2Fpasswd"),
    +		},
    +	}
    +
    +	for _, tt := range tests {
    +		t.Run(tt.name, func(t *testing.T) {
    +			d := &diskCache{
    +				base:   tt.base,
    +				memory: &memoryCache{},
    +			}
    +
    +			result := d.safePath(tt.input)
    +			if result != tt.expected {
    +				t.Errorf("safePath(%q) = %q, want %q", tt.input, result, tt.expected)
    +			}
    +
    +			// Verify the result doesn't escape the base directory
    +			// by checking if the result starts with the base path
    +			if !strings.HasPrefix(result, tt.base) {
    +				t.Errorf("safePath(%q) = %q escapes base directory %q", tt.input, result, tt.base)
    +			}
    +		})
    +	}
    +}
    

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

6

News mentions

0

No linked articles in our index yet.