VYPR
High severity7.8NVD Advisory· Published Apr 9, 2026· Updated Apr 17, 2026

CVE-2026-35205

CVE-2026-35205

Description

Helm is a package manager for Charts for Kubernetes. From 4.0.0 to 4.1.3, Helm will install plugins missing provenance (.prov file) when signature verification is required. This vulnerability is fixed in 4.1.4.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
helm.sh/helm/v4Go
>= 4.0.0, < 4.1.44.1.4

Affected products

1
  • cpe:2.3:a:helm:helm:*:*:*:*:*:*:*:*
    Range: >=4.0.0,<4.1.4

Patches

1
05fa37973dc9

fix: Plugin missing provenance bypass

https://github.com/helm/helmGeorge JenkinsMar 6, 2026via ghsa
3 files changed · +55 42
  • internal/plugin/installer/installer.go+16 17 modified
    @@ -98,24 +98,23 @@ func InstallWithOptions(i Installer, opts Options) (*VerificationResult, error)
     
     		// Check if provenance data exists
     		if len(provData) == 0 {
    -			// No .prov file found - emit warning but continue installation
    -			fmt.Fprintf(os.Stderr, "WARNING: No provenance file found for plugin. Plugin is not signed and cannot be verified.\n")
    -		} else {
    -			// Provenance data exists - verify the plugin
    -			verification, err := plugin.VerifyPlugin(archiveData, provData, filename, opts.Keyring)
    -			if err != nil {
    -				return nil, fmt.Errorf("plugin verification failed: %w", err)
    -			}
    +			return nil, fmt.Errorf("plugin verification failed: no provenance file (.prov) found")
    +		}
     
    -			// Collect verification info
    -			result = &VerificationResult{
    -				SignedBy:    make([]string, 0),
    -				Fingerprint: fmt.Sprintf("%X", verification.SignedBy.PrimaryKey.Fingerprint),
    -				FileHash:    verification.FileHash,
    -			}
    -			for name := range verification.SignedBy.Identities {
    -				result.SignedBy = append(result.SignedBy, name)
    -			}
    +		// Provenance data exists - verify the plugin
    +		verification, err := plugin.VerifyPlugin(archiveData, provData, filename, opts.Keyring)
    +		if err != nil {
    +			return nil, fmt.Errorf("plugin verification failed: %w", err)
    +		}
    +
    +		// Collect verification info
    +		result = &VerificationResult{
    +			SignedBy:    make([]string, 0),
    +			Fingerprint: fmt.Sprintf("%X", verification.SignedBy.PrimaryKey.Fingerprint),
    +			FileHash:    verification.FileHash,
    +		}
    +		for name := range verification.SignedBy.Identities {
    +			result.SignedBy = append(result.SignedBy, name)
     		}
     	}
     
    
  • internal/plugin/installer/verification_test.go+36 22 modified
    @@ -16,10 +16,8 @@ limitations under the License.
     package installer
     
     import (
    -	"bytes"
     	"crypto/sha256"
     	"fmt"
    -	"io"
     	"os"
     	"path/filepath"
     	"strings"
    @@ -44,33 +42,49 @@ func TestInstallWithOptions_VerifyMissingProvenance(t *testing.T) {
     	}
     	defer os.RemoveAll(installer.Path())
     
    -	// Capture stderr to check warning message
    -	oldStderr := os.Stderr
    -	r, w, _ := os.Pipe()
    -	os.Stderr = w
    -
    -	// Install with verification enabled (should warn but succeed)
    +	// Install with verification enabled should fail when .prov is missing
     	result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: "dummy"})
     
    -	// Restore stderr and read captured output
    -	w.Close()
    -	os.Stderr = oldStderr
    -	var buf bytes.Buffer
    -	io.Copy(&buf, r)
    -	output := buf.String()
    -
    -	// Should succeed with nil result (no verification performed)
    -	if err != nil {
    -		t.Fatalf("Expected installation to succeed despite missing .prov file, got error: %v", err)
    +	// Should fail with a missing provenance error
    +	if err == nil {
    +		t.Fatal("Expected installation to fail when .prov file is missing and verification is enabled")
    +	}
    +	if !strings.Contains(err.Error(), "no provenance file") {
    +		t.Errorf("Expected 'no provenance file' in error message, got: %v", err)
     	}
     	if result != nil {
     		t.Errorf("Expected nil verification result when .prov file is missing, got: %+v", result)
     	}
     
    -	// Should contain warning message
    -	expectedWarning := "WARNING: No provenance file found for plugin"
    -	if !strings.Contains(output, expectedWarning) {
    -		t.Errorf("Expected warning message '%s' in output, got: %s", expectedWarning, output)
    +	// Plugin should NOT be installed
    +	if _, err := os.Stat(installer.Path()); !os.IsNotExist(err) {
    +		t.Errorf("Plugin should not be installed when verification fails due to missing .prov")
    +	}
    +}
    +
    +func TestInstallWithOptions_NoVerifyMissingProvenance(t *testing.T) {
    +	ensure.HelmHome(t)
    +
    +	// Create a temporary plugin tarball without .prov file
    +	pluginDir := createTestPluginDir(t)
    +	pluginTgz := createTarballFromPluginDir(t, pluginDir)
    +	defer os.Remove(pluginTgz)
    +
    +	// Create local installer
    +	installer, err := NewLocalInstaller(pluginTgz)
    +	if err != nil {
    +		t.Fatalf("Failed to create installer: %v", err)
    +	}
    +	defer os.RemoveAll(installer.Path())
    +
    +	// Install with verification explicitly disabled should succeed without .prov
    +	result, err := InstallWithOptions(installer, Options{Verify: false})
    +
    +	if err != nil {
    +		t.Fatalf("Expected installation to succeed with --verify=false, got error: %v", err)
    +	}
    +	if result != nil {
    +		t.Errorf("Expected nil verification result when verification is disabled, got: %+v", result)
     	}
     
     	// Plugin should be installed
    
  • pkg/cmd/plugin_install.go+3 3 modified
    @@ -50,11 +50,11 @@ const pluginInstallDesc = `
     This command allows you to install a plugin from a url to a VCS repo or a local path.
     
     By default, plugin signatures are verified before installation when installing from
    -tarballs (.tgz or .tar.gz). This requires a corresponding .prov file to be available
    -alongside the tarball.
    +tarballs (.tgz or .tar.gz). A corresponding .prov file must be available alongside
    +the tarball; installation will fail if it is missing or invalid.
     For local development, plugins installed from local directories are automatically
     treated as "local dev" and do not require signatures.
    -Use --verify=false to skip signature verification for remote plugins.
    +Use --verify=false to explicitly skip signature verification (NOT recommended).
     `
     
     func newPluginInstallCmd(out io.Writer) *cobra.Command {
    

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.