Headline
CVE-2023-23947: Merge pull request from GHSA-3jfq-742w-xg8j · argoproj/argo-cd@fbb0b99
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. All Argo CD versions starting with 2.3.0-rc1 and prior to 2.3.17, 2.4.23 2.5.11, and 2.6.2 are vulnerable to an improper authorization bug which allows users who have the ability to update at least one cluster secret to update any cluster secret. The attacker could use this access to escalate privileges (potentially controlling Kubernetes resources) or to break Argo CD functionality (by preventing connections to external clusters). A patch for this vulnerability has been released in Argo CD versions 2.6.2, 2.5.11, 2.4.23, and 2.3.17. Two workarounds are available. Either modify the RBAC configuration to completely revoke all clusters, update
access, or use the destinations
and clusterResourceWhitelist
fields to apply similar restrictions as the namespaces
and clusterResources
fields.
@@ -3,6 +3,7 @@ package cluster import ( “context” “encoding/json” “fmt” “testing” “time”
@@ -49,6 +50,117 @@ func newNoopEnforcer() *rbac.Enforcer { return enf }
func TestUpdateCluster_RejectInvalidParams(t *testing.T) { testCases := []struct { name string request clusterapi.ClusterUpdateRequest }{ { name: "allowed cluster URL in body, disallowed cluster URL in query", request: clusterapi.ClusterUpdateRequest{Cluster: &v1alpha1.Cluster{Name: "", Server: "https://127.0.0.1", Project: "", ClusterResources: true}, Id: &clusterapi.ClusterID{Type: "", Value: "https://127.0.0.2"}, UpdatedFields: []string{"clusterResources", "project"}}, }, { name: "allowed cluster URL in body, disallowed cluster name in query", request: clusterapi.ClusterUpdateRequest{Cluster: &v1alpha1.Cluster{Name: "", Server: "https://127.0.0.1", Project: "", ClusterResources: true}, Id: &clusterapi.ClusterID{Type: "name", Value: "disallowed-unscoped"}, UpdatedFields: []string{"clusterResources", "project"}}, }, { name: "allowed cluster URL in body, disallowed cluster name in query, changing unscoped to scoped", request: clusterapi.ClusterUpdateRequest{Cluster: &v1alpha1.Cluster{Name: "", Server: "https://127.0.0.1", Project: "allowed-project", ClusterResources: true}, Id: &clusterapi.ClusterID{Type: "", Value: "https://127.0.0.2"}, UpdatedFields: []string{"clusterResources", "project"}}, }, { name: "allowed cluster URL in body, disallowed cluster URL in query, changing unscoped to scoped", request: clusterapi.ClusterUpdateRequest{Cluster: &v1alpha1.Cluster{Name: "", Server: "https://127.0.0.1", Project: "allowed-project", ClusterResources: true}, Id: &clusterapi.ClusterID{Type: "name", Value: "disallowed-unscoped"}, UpdatedFields: []string{"clusterResources", "project"}}, }, }
db := &dbmocks.ArgoDB{}
clusters := []v1alpha1.Cluster{ { Name: "allowed-unscoped", Server: "https://127.0.0.1", }, { Name: "disallowed-unscoped", Server: "https://127.0.0.2", }, { Name: "allowed-scoped", Server: "https://127.0.0.3", Project: "allowed-project", }, { Name: "disallowed-scoped", Server: "https://127.0.0.4", Project: "disallowed-project", }, }
db.On("ListClusters", mock.Anything).Return( func(ctx context.Context) *v1alpha1.ClusterList { return &v1alpha1.ClusterList{ ListMeta: v1.ListMeta{}, Items: clusters, } }, func(ctx context.Context) error { return nil }, ) db.On("UpdateCluster", mock.Anything, mock.Anything).Return( func(ctx context.Context, c *v1alpha1.Cluster) *v1alpha1.Cluster { for _, cluster := range clusters { if c.Server == cluster.Server { return c } } return nil }, func(ctx context.Context, c *v1alpha1.Cluster) error { for _, cluster := range clusters { if c.Server == cluster.Server { return nil } } return fmt.Errorf("cluster ‘%s’ not found", c.Server) }, ) db.On("GetCluster", mock.Anything, mock.Anything).Return( func(ctx context.Context, server string) *v1alpha1.Cluster { for _, cluster := range clusters { if server == cluster.Server { return &cluster } } return nil }, func(ctx context.Context, server string) error { for _, cluster := range clusters { if server == cluster.Server { return nil } } return fmt.Errorf("cluster ‘%s’ not found", server) }, )
enf := rbac.NewEnforcer(fake.NewSimpleClientset(test.NewFakeConfigMap()), test.FakeArgoCDNamespace, common.ArgoCDConfigMapName, nil) _ = enf.SetBuiltinPolicy(`p, role:test, clusters, *, https://127.0.0.1, allow p, role:test, clusters, *, allowed-project/*, allow`) enf.SetDefaultRole(“role:test”) server := NewServer(db, enf, newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
for _, c := range testCases { cc := c t.Run(cc.name, func(t *testing.T) { t.Parallel() out, err := server.Update(context.Background(), &cc.request) require.Nil(t, out) assert.ErrorIs(t, err, common.PermissionDeniedAPIError) }) } }
func TestGetCluster_UrlEncodedName(t *testing.T) { db := &dbmocks.ArgoDB{}
Related news
Red Hat Security Advisory 2023-0803-01 - An update is now available for Red Hat OpenShift GitOps 1.7. Red Hat Product Security has rated this update as having a security impact of Important.
Red Hat Security Advisory 2023-0804-01 - An update is now available for Red Hat OpenShift GitOps 1.5. Red Hat Product Security has rated this update as having a security impact of Important.
Red Hat Security Advisory 2023-0802-01 - An update is now available for Red Hat OpenShift GitOps 1.6. Red Hat Product Security has rated this update as having a security impact of Important.
An update is now available for Red Hat OpenShift GitOps 1.5. Red Hat Product Security has rated this update as having a security impact of Important. A Common Vulnerability Scoring System (CVSS) base score, which gives a detailed severity rating, is available for each vulnerability from the CVE link(s) in the References section.This content is licensed under the Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0/). If you distribute this content, or a modified version of it, you must provide attribution to Red Hat Inc. and provide a link to the original. Related CVEs: * CVE-2021-4238: A flaw was found in goutils where randomly generated alphanumeric strings contain significantly less entropy than expected. Both the `RandomAlphaNumeric` and `CryptoRandomAlphaNumeric` functions always return strings containing at least one digit from 0 to 9. This issue significantly reduces the amount of entropy generated in short strings by these functio...
An update is now available for Red Hat OpenShift GitOps 1.7. Red Hat Product Security has rated this update as having a security impact of Important. A Common Vulnerability Scoring System (CVSS) base score, which gives a detailed severity rating, is available for each vulnerability from the CVE link(s) in the References section.This content is licensed under the Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0/). If you distribute this content, or a modified version of it, you must provide attribution to Red Hat Inc. and provide a link to the original. Related CVEs: * CVE-2021-4238: A flaw was found in goutils where randomly generated alphanumeric strings contain significantly less entropy than expected. Both the `RandomAlphaNumeric` and `CryptoRandomAlphaNumeric` functions always return strings containing at least one digit from 0 to 9. This issue significantly reduces the amount of entropy generated in short strings by these functio...
An update is now available for Red Hat OpenShift GitOps 1.6. Red Hat Product Security has rated this update as having a security impact of Important. A Common Vulnerability Scoring System (CVSS) base score, which gives a detailed severity rating, is available for each vulnerability from the CVE link(s) in the References section.This content is licensed under the Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0/). If you distribute this content, or a modified version of it, you must provide attribution to Red Hat Inc. and provide a link to the original. Related CVEs: * CVE-2021-4238: A flaw was found in goutils where randomly generated alphanumeric strings contain significantly less entropy than expected. Both the `RandomAlphaNumeric` and `CryptoRandomAlphaNumeric` functions always return strings containing at least one digit from 0 to 9. This issue significantly reduces the amount of entropy generated in short strings by these functio...
### Impact All Argo CD versions starting with v2.3.0-rc1 are vulnerable to an improper authorization bug which allows users who have the ability to update at least one cluster secret to update any cluster secret. The attacker could use this access to escalate privileges (potentially controlling Kubernetes resources) or to break Argo CD functionality (by preventing connections to external clusters). #### How the Attack Works Argo CD stores [cluster access configurations](https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#clusters) as Kubernetes Secrets. To take advantage of the vulnerability, an attacker must know the server URL for the cluster secret they want to modify. The attacker must be authenticated with the Argo CD API server, and they must be authorized to update at least one ([non project-scoped](https://argo-cd.readthedocs.io/en/stable/user-guide/projects/#project-scoped-repositories-and-clusters)) cluster. Then they must craft a malicious reque...