CVE-2024-25620 (Go)

Helm is a tool for managing Charts. Charts are packages of pre-configured Kubernetes resources. When either the Helm client or SDK is used to save a chart whose name within the `Chart.yaml` file includes a relative path change, the chart would be saved outside its expected directory based on the changes in the relative path. The validation and linting did not detect the path changes in the name. This issue has been resolved in Helm v3.14.1. Users unable to upgrade should check all charts used by Helm for path changes in their name as found in the `Chart.yaml` file. This includes dependencies.

Weakness:
CWE-73: name: External Control of File Name or Path
description: The product allows user input to control or influence paths or file names that are used in filesystem operations.
CWE-22: name: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

Repository: https://github.com/helm/helm

Vulnerable code:
file_path: pkg/chart/metadata.go
snippet: func (md *Metadata) Validate() error {
	if md == nil {
		return ValidationError("chart.metadata is required")
	}

	md.Name = sanitizeString(md.Name)
	md.Description = sanitizeString(md.Description)
	md.Home = sanitizeString(md.Home)
	md.Icon = sanitizeString(md.Icon)
	md.Condition = sanitizeString(md.Condition)
	md.Tags = sanitizeString(md.Tags)
	md.AppVersion = sanitizeString(md.AppVersion)
	md.KubeVersion = sanitizeString(md.KubeVersion)
	for i := range md.Sources {
		md.Sources[i] = sanitizeString(md.Sources[i])
	}
	for i := range md.Keywords {
		md.Keywords[i] = sanitizeString(md.Keywords[i])
	}

	if md.APIVersion == "" {
		return ValidationError("chart.metadata.apiVersion is required")
	}
	if md.Name == "" {
		return ValidationError("chart.metadata.name is required")
	}
	if md.Version == "" {
		return ValidationError("chart.metadata.version is required")
	}
	if !isValidSemver(md.Version) {
		return ValidationErrorf("chart.metadata.version %q is invalid", md.Version)
	}
	if !isValidChartType(md.Type) {
		return ValidationError("chart.metadata.type must be application or library")
	}

	for _, m := range md.Maintainers {
		if err := m.Validate(); err != nil {
			return err
		}
	}

	// Aliases need to be validated here to make sure that the alias name does
	// not contain any illegal characters.
	dependencies := map[string]*Dependency{}
	for _, dependency := range md.Dependencies {
		if err := dependency.Validate(); err != nil {
			return err
		}
		key := dependency.Name
		if dependency.Alias != "" {
			key = dependency.Alias
		}
		if dependencies[key] != nil {
			return ValidationErrorf("more than one dependency with name or alias %q", key)
		}
		dependencies[key] = dependency
	}
	return nil
}

Fixed code:
file_path: pkg/chart/metadata.go
snippet: 	"path/filepath"

file_path: pkg/chart/metadata.go
snippet: func (md *Metadata) Validate() error {
	if md == nil {
		return ValidationError("chart.metadata is required")
	}

	md.Name = sanitizeString(md.Name)
	md.Description = sanitizeString(md.Description)
	md.Home = sanitizeString(md.Home)
	md.Icon = sanitizeString(md.Icon)
	md.Condition = sanitizeString(md.Condition)
	md.Tags = sanitizeString(md.Tags)
	md.AppVersion = sanitizeString(md.AppVersion)
	md.KubeVersion = sanitizeString(md.KubeVersion)
	for i := range md.Sources {
		md.Sources[i] = sanitizeString(md.Sources[i])
	}
	for i := range md.Keywords {
		md.Keywords[i] = sanitizeString(md.Keywords[i])
	}

	if md.APIVersion == "" {
		return ValidationError("chart.metadata.apiVersion is required")
	}
	if md.Name == "" {
		return ValidationError("chart.metadata.name is required")
	}

	if md.Name != filepath.Base(md.Name) {
		return ValidationErrorf("chart.metadata.name %q is invalid", md.Name)
	}

	if md.Version == "" {
		return ValidationError("chart.metadata.version is required")
	}
	if !isValidSemver(md.Version) {
		return ValidationErrorf("chart.metadata.version %q is invalid", md.Version)
	}
	if !isValidChartType(md.Type) {
		return ValidationError("chart.metadata.type must be application or library")
	}

	for _, m := range md.Maintainers {
		if err := m.Validate(); err != nil {
			return err
		}
	}

	// Aliases need to be validated here to make sure that the alias name does
	// not contain any illegal characters.
	dependencies := map[string]*Dependency{}
	for _, dependency := range md.Dependencies {
		if err := dependency.Validate(); err != nil {
			return err
		}
		key := dependency.Name
		if dependency.Alias != "" {
			key = dependency.Alias
		}
		if dependencies[key] != nil {
			return ValidationErrorf("more than one dependency with name or alias %q", key)
		}
		dependencies[key] = dependency
	}
	return nil
}