CVE-2023-40584: Uncontrolled Resource Consumption (CWE-400)
value: Argo CD is a declarative continuous deployment for Kubernetes. All versions of ArgoCD starting from v2.4 have a bug where the ArgoCD repo-server component is vulnerable to a Denial-of-Service attack vector. Specifically, the said component extracts a user-controlled tar.gz file without validating the size of its inner files. As a result, a malicious, low-privileged user can send a malicious tar.gz file that exploits this vulnerability to the repo-server, thereby harming the system's functionality and availability. Additionally, the repo-server is susceptible to another vulnerability due to the fact that it does not check the extracted file permissions before attempting to delete them. Consequently, an attacker can craft a malicious tar.gz archive in a way that prevents the deletion of its inner files when the manifest generation process is completed. A patch for this vulnerability has been released in versions 2.6.15, 2.7.14, and 2.8.3. Users are advised to upgrade. The only way to completely resolve the issue is to upgrade, however users unable to upgrade should configure RBAC (Role-Based Access Control) and provide access for configuring applications only to a limited number of administrators. These administrators should utilize trusted and verified Helm charts.
CWE description: The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
CVSS v3 base score: 6.5
Published: 2023-09-07T23:15Z
Repository: https://github.com/argoproj/argo-cd
Language: YAML
Files changed: cmd/argocd-repo-server/commands/argocd_repo_server.go, docs/operator-manual/server-commands/argocd-repo-server.md, manifests/base/repo-server/argocd-repo-server-deployment.yaml, manifests/core-install.yaml, manifests/ha/install.yaml, manifests/ha/namespace-install.yaml, manifests/install.yaml, manifests/namespace-install.yaml, reposerver/repository/repository.go, util/helm/client.go, util/helm/client_test.go, util/helm/mocks/Client.go
Commit date: 2023-09-07 10:12:15 -0400
Commit message: Merge pull request from GHSA-g687-f2gx-6wm8

* feat: use untar with limiter

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: use untar with limiter

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
Diff: diff --git a/cmd/argocd-repo-server/commands/argocd_repo_server.go b/cmd/argocd-repo-server/commands/argocd_repo_server.go
index cace5cbc0..69358d2a9 100644
--- a/cmd/argocd-repo-server/commands/argocd_repo_server.go
+++ b/cmd/argocd-repo-server/commands/argocd_repo_server.go
@@ -63,10 +63,12 @@ func NewCommand() *cobra.Command {
 		maxCombinedDirectoryManifestsSize string
 		cmpTarExcludedGlobs               []string
 		allowOutOfBoundsSymlinks          bool
 		streamedManifestMaxTarSize        string
 		streamedManifestMaxExtractedSize  string
+		helmManifestMaxExtractedSize      string
+		disableManifestMaxExtractedSize   bool
 	)
 	var command = cobra.Command{
 		Use:               cliName,
 		Short:             "Run ArgoCD Repository Server",
 		Long:              "ArgoCD Repository Server is an internal service which maintains a local cache of the Git repository holding the application manifests, and is responsible for generating and returning the Kubernetes manifests.  This command runs Repository Server in the foreground.  It can be configured by following options.",
@@ -101,10 +103,13 @@ func NewCommand() *cobra.Command {
 			errors.CheckError(err)
 
 			streamedManifestMaxExtractedSizeQuantity, err := resource.ParseQuantity(streamedManifestMaxExtractedSize)
 			errors.CheckError(err)
 
+			helmManifestMaxExtractedSizeQuantity, err := resource.ParseQuantity(helmManifestMaxExtractedSize)
+			errors.CheckError(err)
+
 			askPassServer := askpass.NewServer()
 			metricsServer := metrics.NewMetricsServer()
 			cacheutil.CollectMetrics(redisClient, metricsServer)
 			server, err := reposerver.NewServer(metricsServer, cache, tlsConfigCustomizer, repository.RepoServerInitConstants{
 				ParallelismLimit: parallelismLimit,
@@ -115,10 +120,11 @@ func NewCommand() *cobra.Command {
 				MaxCombinedDirectoryManifestsSize:            maxCombinedDirectoryManifestsQuantity,
 				CMPTarExcludedGlobs:                          cmpTarExcludedGlobs,
 				AllowOutOfBoundsSymlinks:                     allowOutOfBoundsSymlinks,
 				StreamedManifestMaxExtractedSize:             streamedManifestMaxExtractedSizeQuantity.ToDec().Value(),
 				StreamedManifestMaxTarSize:                   streamedManifestMaxTarSizeQuantity.ToDec().Value(),
+				HelmManifestMaxExtractedSize:                 helmManifestMaxExtractedSizeQuantity.ToDec().Value(),
 			}, askPassServer)
 			errors.CheckError(err)
 
 			if otlpAddress != "" {
 				var closer func()
@@ -195,10 +201,12 @@ func NewCommand() *cobra.Command {
 	command.Flags().StringVar(&maxCombinedDirectoryManifestsSize, "max-combined-directory-manifests-size", env.StringFromEnv("ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE", "10M"), "Max combined size of manifest files in a directory-type Application")
 	command.Flags().StringArrayVar(&cmpTarExcludedGlobs, "plugin-tar-exclude", env.StringsFromEnv("ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS", []string{}, ";"), "Globs to filter when sending tarballs to plugins.")
 	command.Flags().BoolVar(&allowOutOfBoundsSymlinks, "allow-oob-symlinks", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_ALLOW_OUT_OF_BOUNDS_SYMLINKS", false), "Allow out-of-bounds symlinks in repositories (not recommended)")
 	command.Flags().StringVar(&streamedManifestMaxTarSize, "streamed-manifest-max-tar-size", env.StringFromEnv("ARGOCD_REPO_SERVER_STREAMED_MANIFEST_MAX_TAR_SIZE", "100M"), "Maximum size of streamed manifest archives")
 	command.Flags().StringVar(&streamedManifestMaxExtractedSize, "streamed-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_STREAMED_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of streamed manifest archives when extracted")
+	command.Flags().StringVar(&helmManifestMaxExtractedSize, "helm-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of helm manifest archives when extracted")
+	command.Flags().BoolVar(&disableManifestMaxExtractedSize, "disable-helm-manifest-max-extracted-size", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE", false), "Disable maximum size of helm manifest archives when extracted")
 	tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command)
 	cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
 		redisClient = client
 	})
 	return &command
diff --git a/docs/operator-manual/server-commands/argocd-repo-server.md b/docs/operator-manual/server-commands/argocd-repo-server.md
index af4a1c4f0..18229c4a4 100644
--- a/docs/operator-manual/server-commands/argocd-repo-server.md
+++ b/docs/operator-manual/server-commands/argocd-repo-server.md
@@ -14,11 +14,13 @@ argocd-repo-server [flags]
 
 ```
       --address string                                 Listen on given address for incoming connections (default "0.0.0.0")
       --allow-oob-symlinks                             Allow out-of-bounds symlinks in repositories (not recommended)
       --default-cache-expiration duration              Cache expiration default (default 24h0m0s)
+      --disable-helm-manifest-max-extracted-size       Disable maximum size of helm manifest archives when extracted
       --disable-tls                                    Disable TLS on the gRPC endpoint
+      --helm-manifest-max-extracted-size string        Maximum size of helm manifest archives when extracted (default "1G")
   -h, --help                                           help for argocd-repo-server
       --logformat string                               Set the logging format. One of: text|json (default "text")
       --loglevel string                                Set the logging level. One of: debug|info|warn|error (default "info")
       --max-combined-directory-manifests-size string   Max combined size of manifest files in a directory-type Application (default "10M")
       --metrics-address string                         Listen on given address for metrics (default "0.0.0.0")
diff --git a/manifests/base/repo-server/argocd-repo-server-deployment.yaml b/manifests/base/repo-server/argocd-repo-server-deployment.yaml
index 735f6436f..eb230e0f9 100644
--- a/manifests/base/repo-server/argocd-repo-server-deployment.yaml
+++ b/manifests/base/repo-server/argocd-repo-server-deployment.yaml
@@ -148,10 +148,22 @@ spec:
             valueFrom:
               configMapKeyRef:
                 key: reposerver.streamed.manifest.max.extracted.size
                 name: argocd-cmd-params-cm
                 optional: true
+          - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+            valueFrom:
+              configMapKeyRef:
+                key: reposerver.helm.manifest.max.extracted.size
+                name: argocd-cmd-params-cm
+                optional: true
+          - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+            valueFrom:
+              configMapKeyRef:
+                name: argocd-cmd-params-cm
+                key: reposerver.disable.helm.manifest.max.extracted.size
+                optional: true
           - name: ARGOCD_GIT_MODULES_ENABLED
             valueFrom:
               configMapKeyRef:
                 key: reposerver.enable.git.submodule
                 name: argocd-cmd-params-cm
diff --git a/manifests/core-install.yaml b/manifests/core-install.yaml
index 0e919238d..97c8ef98b 100644
--- a/manifests/core-install.yaml
+++ b/manifests/core-install.yaml
@@ -19172,10 +19172,22 @@ spec:
           valueFrom:
             configMapKeyRef:
               key: reposerver.streamed.manifest.max.extracted.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
+        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.disable.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
         - name: ARGOCD_GIT_MODULES_ENABLED
           valueFrom:
             configMapKeyRef:
               key: reposerver.enable.git.submodule
               name: argocd-cmd-params-cm
diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml
index c5f45e932..67622fb18 100644
--- a/manifests/ha/install.yaml
+++ b/manifests/ha/install.yaml
@@ -20629,10 +20629,22 @@ spec:
           valueFrom:
             configMapKeyRef:
               key: reposerver.streamed.manifest.max.extracted.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
+        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.disable.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
         - name: ARGOCD_GIT_MODULES_ENABLED
           valueFrom:
             configMapKeyRef:
               key: reposerver.enable.git.submodule
               name: argocd-cmd-params-cm
diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml
index 03e2dd32f..5cd8bffea 100644
--- a/manifests/ha/namespace-install.yaml
+++ b/manifests/ha/namespace-install.yaml
@@ -2129,10 +2129,22 @@ spec:
           valueFrom:
             configMapKeyRef:
               key: reposerver.streamed.manifest.max.extracted.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
+        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.disable.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
         - name: ARGOCD_GIT_MODULES_ENABLED
           valueFrom:
             configMapKeyRef:
               key: reposerver.enable.git.submodule
               name: argocd-cmd-params-cm
diff --git a/manifests/install.yaml b/manifests/install.yaml
index b48239ab5..7a76d2c91 100644
--- a/manifests/install.yaml
+++ b/manifests/install.yaml
@@ -19686,10 +19686,22 @@ spec:
           valueFrom:
             configMapKeyRef:
               key: reposerver.streamed.manifest.max.extracted.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
+        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.disable.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
         - name: ARGOCD_GIT_MODULES_ENABLED
           valueFrom:
             configMapKeyRef:
               key: reposerver.enable.git.submodule
               name: argocd-cmd-params-cm
diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml
index ac244c7cc..b1dfd7fc6 100644
--- a/manifests/namespace-install.yaml
+++ b/manifests/namespace-install.yaml
@@ -1186,10 +1186,22 @@ spec:
           valueFrom:
             configMapKeyRef:
               key: reposerver.streamed.manifest.max.extracted.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
+        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.disable.helm.manifest.max.extracted.size
+              name: argocd-cmd-params-cm
+              optional: true
         - name: ARGOCD_GIT_MODULES_ENABLED
           valueFrom:
             configMapKeyRef:
               key: reposerver.enable.git.submodule
               name: argocd-cmd-params-cm
diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go
index 09509645e..12eab7232 100644
--- a/reposerver/repository/repository.go
+++ b/reposerver/repository/repository.go
@@ -104,10 +104,12 @@ type RepoServerInitConstants struct {
 	MaxCombinedDirectoryManifestsSize            resource.Quantity
 	CMPTarExcludedGlobs                          []string
 	AllowOutOfBoundsSymlinks                     bool
 	StreamedManifestMaxExtractedSize             int64
 	StreamedManifestMaxTarSize                   int64
+	HelmManifestMaxExtractedSize                 int64
+	DisableHelmManifestMaxExtractedSize          bool
 }
 
 // NewService returns a new instance of the Manifest service
 func NewService(metricsServer *metrics.MetricsServer, cache *cache.Cache, initConstants RepoServerInitConstants, resourceTracking argo.ResourceTracking, gitCredsStore git.CredsStore, rootDir string) *Service {
 	var parallelismLimitSemaphore *semaphore.Weighted
@@ -343,11 +345,11 @@ func (s *Service) runRepoOperation(
 		}
 		helmPassCredentials := false
 		if source.Helm != nil {
 			helmPassCredentials = source.Helm.PassCredentials
 		}
-		chartPath, closer, err := helmClient.ExtractChart(source.Chart, revision, helmPassCredentials)
+		chartPath, closer, err := helmClient.ExtractChart(source.Chart, revision, helmPassCredentials, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize)
 		if err != nil {
 			return err
 		}
 		defer io.Close(closer)
 		if !s.initConstants.AllowOutOfBoundsSymlinks {
@@ -2264,11 +2266,11 @@ func (s *Service) GetRevisionChartDetails(ctx context.Context, q *apiclient.Repo
 	}
 	helmClient, revision, err := s.newHelmClientResolveRevision(q.Repo, q.Revision, q.Name, true)
 	if err != nil {
 		return nil, fmt.Errorf("helm client error: %v", err)
 	}
-	chartPath, closer, err := helmClient.ExtractChart(q.Name, revision, false)
+	chartPath, closer, err := helmClient.ExtractChart(q.Name, revision, false, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize)
 	if err != nil {
 		return nil, fmt.Errorf("error extracting chart: %v", err)
 	}
 	defer io.Close(closer)
 	helmCmd, err := helm.NewCmdWithVersion(chartPath, helm.HelmV3, q.Repo.EnableOCI, q.Repo.Proxy)
diff --git a/util/helm/client.go b/util/helm/client.go
index fcb1e665d..2b9e29123 100644
--- a/util/helm/client.go
+++ b/util/helm/client.go
@@ -6,10 +6,11 @@ import (
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/json"
 	"errors"
 	"fmt"
+	executil "github.com/argoproj/argo-cd/v2/util/exec"
 	"io"
 	"net/http"
 	"net/url"
 	"os"
 	"os/exec"
@@ -23,11 +24,10 @@ import (
 	"gopkg.in/yaml.v2"
 	"oras.land/oras-go/v2/registry/remote"
 	"oras.land/oras-go/v2/registry/remote/auth"
 
 	"github.com/argoproj/argo-cd/v2/util/cache"
-	executil "github.com/argoproj/argo-cd/v2/util/exec"
 	argoio "github.com/argoproj/argo-cd/v2/util/io"
 	"github.com/argoproj/argo-cd/v2/util/io/files"
 	"github.com/argoproj/argo-cd/v2/util/proxy"
 )
 
@@ -50,11 +50,11 @@ type indexCache interface {
 	GetHelmIndex(repo string, indexData *[]byte) error
 }
 
 type Client interface {
 	CleanChartCache(chart string, version string) error
-	ExtractChart(chart string, version string, passCredentials bool) (string, argoio.Closer, error)
+	ExtractChart(chart string, version string, passCredentials bool, manifestMaxExtractedSize int64, disableManifestMaxExtractedSize bool) (string, argoio.Closer, error)
 	GetIndex(noCache bool) (*Index, error)
 	GetTags(chart string, noCache bool) (*TagsList, error)
 	TestHelmOCI() (bool, error)
 }
 
@@ -120,11 +120,25 @@ func (c *nativeHelmChart) CleanChartCache(chart string, version string) error {
 		return err
 	}
 	return os.RemoveAll(cachePath)
 }
 
-func (c *nativeHelmChart) ExtractChart(chart string, version string, passCredentials bool) (string, argoio.Closer, error) {
+func untarChart(tempDir string, cachedChartPath string, manifestMaxExtractedSize int64, disableManifestMaxExtractedSize bool) error {
+	if disableManifestMaxExtractedSize {
+		cmd := exec.Command("tar", "-zxvf", cachedChartPath)
+		cmd.Dir = tempDir
+		_, err := executil.Run(cmd)
+		return err
+	}
+	reader, err := os.Open(cachedChartPath)
+	if err != nil {
+		return err
+	}
+	return files.Untgz(tempDir, reader, manifestMaxExtractedSize, false)
+}
+
+func (c *nativeHelmChart) ExtractChart(chart string, version string, passCredentials bool, manifestMaxExtractedSize int64, disableManifestMaxExtractedSize bool) (string, argoio.Closer, error) {
 	// always use Helm V3 since we don't have chart content to determine correct Helm version
 	helmCmd, err := NewCmdWithVersion("", HelmV3, c.enableOci, c.proxy)
 
 	if err != nil {
 		return "", nil, err
@@ -194,19 +208,18 @@ func (c *nativeHelmChart) ExtractChart(chart string, version string, passCredent
 			return "", nil, err
 		}
 		if len(infos) != 1 {
 			return "", nil, fmt.Errorf("expected 1 file, found %v", len(infos))
 		}
+
 		err = os.Rename(filepath.Join(tempDest, infos[0].Name()), cachedChartPath)
 		if err != nil {
 			return "", nil, err
 		}
 	}
 
-	cmd := exec.Command("tar", "-zxvf", cachedChartPath)
-	cmd.Dir = tempDir
-	_, err = executil.Run(cmd)
+	err = untarChart(tempDir, cachedChartPath, manifestMaxExtractedSize, disableManifestMaxExtractedSize)
 	if err != nil {
 		_ = os.RemoveAll(tempDir)
 		return "", nil, err
 	}
 	return path.Join(tempDir, normalizeChartName(chart)), argoio.NewCloser(func() error {
diff --git a/util/helm/client_test.go b/util/helm/client_test.go
index 63b57b7fa..3cda26feb 100644
--- a/util/helm/client_test.go
+++ b/util/helm/client_test.go
@@ -2,10 +2,11 @@ package helm
 
 import (
 	"bytes"
 	"encoding/json"
 	"fmt"
+	"math"
 	"os"
 	"strings"
 	"testing"
 
 	"net/http"
@@ -69,21 +70,27 @@ func TestIndex(t *testing.T) {
 
 }
 
 func Test_nativeHelmChart_ExtractChart(t *testing.T) {
 	client := NewClient("https://argoproj.github.io/argo-helm", Creds{}, false, "")
-	path, closer, err := client.ExtractChart("argo-cd", "0.7.1", false)
+	path, closer, err := client.ExtractChart("argo-cd", "0.7.1", false, math.MaxInt64, true)
 	assert.NoError(t, err)
 	defer io.Close(closer)
 	info, err := os.Stat(path)
 	assert.NoError(t, err)
 	assert.True(t, info.IsDir())
 }
 
+func Test_nativeHelmChart_ExtractChartWithLimiter(t *testing.T) {
+	client := NewClient("https://argoproj.github.io/argo-helm", Creds{}, false, "")
+	_, _, err := client.ExtractChart("argo-cd", "0.7.1", false, 100, false)
+	assert.Error(t, err, "error while iterating on tar reader: unexpected EOF")
+}
+
 func Test_nativeHelmChart_ExtractChart_insecure(t *testing.T) {
 	client := NewClient("https://argoproj.github.io/argo-helm", Creds{InsecureSkipVerify: true}, false, "")
-	path, closer, err := client.ExtractChart("argo-cd", "0.7.1", false)
+	path, closer, err := client.ExtractChart("argo-cd", "0.7.1", false, math.MaxInt64, true)
 	assert.NoError(t, err)
 	defer io.Close(closer)
 	info, err := os.Stat(path)
 	assert.NoError(t, err)
 	assert.True(t, info.IsDir())
diff --git a/util/helm/mocks/Client.go b/util/helm/mocks/Client.go
index 31b5a11e2..6dc25e4af 100644
--- a/util/helm/mocks/Client.go
+++ b/util/helm/mocks/Client.go
@@ -27,11 +27,11 @@ func (_m *Client) CleanChartCache(chart string, version string) error {
 
 	return r0
 }
 
 // ExtractChart provides a mock function with given fields: chart, version
-func (_m *Client) ExtractChart(chart string, version string, passCredentials bool) (string, io.Closer, error) {
+func (_m *Client) ExtractChart(chart string, version string, passCredentials bool, manifestMaxExtractedSize int64, disableManifestMaxExtractedSize bool) (string, io.Closer, error) {
 	ret := _m.Called(chart, version)
 
 	var r0 string
 	if rf, ok := ret.Get(0).(func(string, string) string); ok {
 		r0 = rf(chart, version)

Vulnerable code: 		chartPath, closer, err := helmClient.ExtractChart(source.Chart, revision, helmPassCredentials)
	chartPath, closer, err := helmClient.ExtractChart(q.Name, revision, false)
	executil "github.com/argoproj/argo-cd/v2/util/exec"
	ExtractChart(chart string, version string, passCredentials bool) (string, argoio.Closer, error)
func (c *nativeHelmChart) ExtractChart(chart string, version string, passCredentials bool) (string, argoio.Closer, error) {
	cmd := exec.Command("tar", "-zxvf", cachedChartPath)
	cmd.Dir = tempDir
	_, err = executil.Run(cmd)
	path, closer, err := client.ExtractChart("argo-cd", "0.7.1", false)
	path, closer, err := client.ExtractChart("argo-cd", "0.7.1", false)
func (_m *Client) ExtractChart(chart string, version string, passCredentials bool) (string, io.Closer, error) {
Fixed code: 		helmManifestMaxExtractedSize      string
		disableManifestMaxExtractedSize   bool
			helmManifestMaxExtractedSizeQuantity, err := resource.ParseQuantity(helmManifestMaxExtractedSize)
			errors.CheckError(err)

				HelmManifestMaxExtractedSize:                 helmManifestMaxExtractedSizeQuantity.ToDec().Value(),
	command.Flags().StringVar(&helmManifestMaxExtractedSize, "helm-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of helm manifest archives when extracted")
	command.Flags().BoolVar(&disableManifestMaxExtractedSize, "disable-helm-manifest-max-extracted-size", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE", false), "Disable maximum size of helm manifest archives when extracted")
      --disable-helm-manifest-max-extracted-size       Disable maximum size of helm manifest archives when extracted
      --helm-manifest-max-extracted-size string        Maximum size of helm manifest archives when extracted (default "1G")
          - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
            valueFrom:
              configMapKeyRef:
                key: reposerver.helm.manifest.max.extracted.size
                name: argocd-cmd-params-cm
                optional: true
          - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
            valueFrom:
              configMapKeyRef:
                name: argocd-cmd-params-cm
                key: reposerver.disable.helm.manifest.max.extracted.size
                optional: true
        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.disable.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.disable.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.disable.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.disable.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
        - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE
          valueFrom:
            configMapKeyRef:
              key: reposerver.disable.helm.manifest.max.extracted.size
              name: argocd-cmd-params-cm
              optional: true
	HelmManifestMaxExtractedSize                 int64
	DisableHelmManifestMaxExtractedSize          bool
		chartPath, closer, err := helmClient.ExtractChart(source.Chart, revision, helmPassCredentials, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize)
	chartPath, closer, err := helmClient.ExtractChart(q.Name, revision, false, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize)
	executil "github.com/argoproj/argo-cd/v2/util/exec"
	ExtractChart(chart string, version string, passCredentials bool, manifestMaxExtractedSize int64, disableManifestMaxExtractedSize bool) (string, argoio.Closer, error)
func untarChart(tempDir string, cachedChartPath string, manifestMaxExtractedSize int64, disableManifestMaxExtractedSize bool) error {
	if disableManifestMaxExtractedSize {
		cmd := exec.Command("tar", "-zxvf", cachedChartPath)
		cmd.Dir = tempDir
		_, err := executil.Run(cmd)
		return err
	}
	reader, err := os.Open(cachedChartPath)
	if err != nil {
		return err
	}
	return files.Untgz(tempDir, reader, manifestMaxExtractedSize, false)
}

func (c *nativeHelmChart) ExtractChart(chart string, version string, passCredentials bool, manifestMaxExtractedSize int64, disableManifestMaxExtractedSize bool) (string, argoio.Closer, error) {

	err = untarChart(tempDir, cachedChartPath, manifestMaxExtractedSize, disableManifestMaxExtractedSize)
	"math"
	path, closer, err := client.ExtractChart("argo-cd", "0.7.1", false, math.MaxInt64, true)
func Test_nativeHelmChart_ExtractChartWithLimiter(t *testing.T) {
	client := NewClient("https://argoproj.github.io/argo-helm", Creds{}, false, "")
	_, _, err := client.ExtractChart("argo-cd", "0.7.1", false, 100, false)
	assert.Error(t, err, "error while iterating on tar reader: unexpected EOF")
}

	path, closer, err := client.ExtractChart("argo-cd", "0.7.1", false, math.MaxInt64, true)
func (_m *Client) ExtractChart(chart string, version string, passCredentials bool, manifestMaxExtractedSize int64, disableManifestMaxExtractedSize bool) (string, io.Closer, error) {