Skip to content

Commit 60c62a9

Browse files
crenshaw-devalexmt
andauthored
fix(security): repository.GetDetailedProject exposes repo secrets (#24391)
Signed-off-by: Alexander Matyushentsev <[email protected]> Signed-off-by: Michael Crenshaw <[email protected]> Co-authored-by: Alexander Matyushentsev <[email protected]>
1 parent fe6efec commit 60c62a9

File tree

9 files changed

+116
-17
lines changed

9 files changed

+116
-17
lines changed

docs/operator-manual/upgrading/2.13-2.14.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,12 @@ Eg, `https://github.com/argoproj/argo-cd/manifests/ha/cluster-install?ref=v2.14.
1111
## Upgraded Helm Version
1212

1313
Helm was upgraded to 3.16.2 and the skipSchemaValidation Flag was added to
14-
the [CLI and Application CR](https://argo-cd.readthedocs.io/en/latest/user-guide/helm/#helm-skip-schema-validation).
14+
the [CLI and Application CR](https://argo-cd.readthedocs.io/en/latest/user-guide/helm/#helm-skip-schema-validation).
15+
16+
## Breaking Changes
17+
18+
## Sanitized project API response
19+
20+
Due to security reasons ([GHSA-786q-9hcg-v9ff](https://github.com/argoproj/argo-cd/security/advisories/GHSA-786q-9hcg-v9ff)),
21+
the project API response was sanitized to remove sensitive information. This includes
22+
credentials of project-scoped repositories and clusters.

docs/operator-manual/upgrading/2.14-3.0.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,9 @@ resource.customizations.ignoreDifferences.apiextensions.k8s.io_CustomResourceDef
492492
```
493493

494494
More details for ignored resource updates in the [Diffing customization](../../user-guide/diffing.md) documentation.
495+
496+
### Sanitized project API response
497+
498+
Due to security reasons ([GHSA-786q-9hcg-v9ff](https://github.com/argoproj/argo-cd/security/advisories/GHSA-786q-9hcg-v9ff)),
499+
the project API response was sanitized to remove sensitive information. This includes
500+
credentials of project-scoped repositories and clusters.

docs/operator-manual/upgrading/3.0-3.1.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,11 @@ Argo CD v3.1 upgrades the bundled Helm version to 3.18.4. There are no breaking
5555

5656
Argo CD v3.1 upgrades the bundled Kustomize version to 5.7.0. There are no breaking changes in Kustomize 5.7 according
5757
to the [release notes](https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv5.7.0).
58+
59+
## Breaking Changes
60+
61+
## Sanitized project API response
62+
63+
Due to security reasons ([GHSA-786q-9hcg-v9ff](https://github.com/argoproj/argo-cd/security/advisories/GHSA-786q-9hcg-v9ff)),
64+
the project API response was sanitized to remove sensitive information. This includes
65+
credentials of project-scoped repositories and clusters.

pkg/apis/application/v1alpha1/repository_types.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,6 @@ func (repo *Repository) Sanitized() *Repository {
347347
Repo: repo.Repo,
348348
Type: repo.Type,
349349
Name: repo.Name,
350-
Username: repo.Username,
351350
Insecure: repo.IsInsecure(),
352351
EnableLFS: repo.EnableLFS,
353352
EnableOCI: repo.EnableOCI,

pkg/apis/application/v1alpha1/types.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,6 +2234,32 @@ type Cluster struct {
22342234
Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,13,opt,name=annotations"`
22352235
}
22362236

2237+
func (c *Cluster) Sanitized() *Cluster {
2238+
return &Cluster{
2239+
ID: c.ID,
2240+
Server: c.Server,
2241+
Name: c.Name,
2242+
Project: c.Project,
2243+
Namespaces: c.Namespaces,
2244+
Shard: c.Shard,
2245+
Labels: c.Labels,
2246+
Annotations: c.Annotations,
2247+
ClusterResources: c.ClusterResources,
2248+
ConnectionState: c.ConnectionState,
2249+
ServerVersion: c.ServerVersion,
2250+
Info: c.Info,
2251+
RefreshRequestedAt: c.RefreshRequestedAt,
2252+
Config: ClusterConfig{
2253+
AWSAuthConfig: c.Config.AWSAuthConfig,
2254+
ProxyUrl: c.Config.ProxyUrl,
2255+
DisableCompression: c.Config.DisableCompression,
2256+
TLSClientConfig: TLSClientConfig{
2257+
Insecure: c.Config.Insecure,
2258+
},
2259+
},
2260+
}
2261+
}
2262+
22372263
// Equals returns true if two cluster objects are considered to be equal
22382264
func (c *Cluster) Equals(other *Cluster) bool {
22392265
if c.Server != other.Server {

pkg/apis/application/v1alpha1/types_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4543,3 +4543,58 @@ func TestCluster_ParseProxyUrl(t *testing.T) {
45434543
}
45444544
}
45454545
}
4546+
4547+
func TestSanitized(t *testing.T) {
4548+
now := metav1.Now()
4549+
cluster := &Cluster{
4550+
ID: "123",
4551+
Server: "https://example.com",
4552+
Name: "example",
4553+
ServerVersion: "v1.0.0",
4554+
Namespaces: []string{"default", "kube-system"},
4555+
Project: "default",
4556+
Labels: map[string]string{
4557+
"env": "production",
4558+
},
4559+
Annotations: map[string]string{
4560+
"annotation-key": "annotation-value",
4561+
},
4562+
ConnectionState: ConnectionState{
4563+
Status: ConnectionStatusSuccessful,
4564+
Message: "Connection successful",
4565+
ModifiedAt: &now,
4566+
},
4567+
Config: ClusterConfig{
4568+
Username: "admin",
4569+
Password: "password123",
4570+
BearerToken: "abc",
4571+
TLSClientConfig: TLSClientConfig{
4572+
Insecure: true,
4573+
},
4574+
ExecProviderConfig: &ExecProviderConfig{
4575+
Command: "test",
4576+
},
4577+
},
4578+
}
4579+
4580+
assert.Equal(t, &Cluster{
4581+
ID: "123",
4582+
Server: "https://example.com",
4583+
Name: "example",
4584+
ServerVersion: "v1.0.0",
4585+
Namespaces: []string{"default", "kube-system"},
4586+
Project: "default",
4587+
Labels: map[string]string{"env": "production"},
4588+
Annotations: map[string]string{"annotation-key": "annotation-value"},
4589+
ConnectionState: ConnectionState{
4590+
Status: ConnectionStatusSuccessful,
4591+
Message: "Connection successful",
4592+
ModifiedAt: &now,
4593+
},
4594+
Config: ClusterConfig{
4595+
TLSClientConfig: TLSClientConfig{
4596+
Insecure: true,
4597+
},
4598+
},
4599+
}, cluster.Sanitized())
4600+
}

server/cluster/cluster.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -471,19 +471,8 @@ func (s *Server) RotateAuth(ctx context.Context, q *cluster.ClusterQuery) (*clus
471471
}
472472

473473
func (s *Server) toAPIResponse(clust *appv1.Cluster) *appv1.Cluster {
474+
clust = clust.Sanitized()
474475
_ = s.cache.GetClusterInfo(clust.Server, &clust.Info)
475-
476-
clust.Config.Password = ""
477-
clust.Config.BearerToken = ""
478-
clust.Config.KeyData = nil
479-
if clust.Config.ExecProviderConfig != nil {
480-
// We can't know what the user has put into args or
481-
// env vars on the exec provider that might be sensitive
482-
// (e.g. --private-key=XXX, PASSWORD=XXX)
483-
// Implicitly assumes the command executable name is non-sensitive
484-
clust.Config.ExecProviderConfig.Env = make(map[string]string)
485-
clust.Config.ExecProviderConfig.Args = nil
486-
}
487476
// populate deprecated fields for backward compatibility
488477
//nolint:staticcheck
489478
clust.ServerVersion = clust.Info.ServerVersion

server/project/project.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,12 +310,20 @@ func (s *Server) GetDetailedProject(ctx context.Context, q *project.ProjectQuery
310310
}
311311
proj.NormalizeJWTTokens()
312312
globalProjects := argo.GetGlobalProjects(proj, listersv1alpha1.NewAppProjectLister(s.projInformer.GetIndexer()), s.settingsMgr)
313+
var apiRepos []*v1alpha1.Repository
314+
for _, repo := range repositories {
315+
apiRepos = append(apiRepos, repo.Normalize().Sanitized())
316+
}
317+
var apiClusters []*v1alpha1.Cluster
318+
for _, cluster := range clusters {
319+
apiClusters = append(apiClusters, cluster.Sanitized())
320+
}
313321

314322
return &project.DetailedProjectsResponse{
315323
GlobalProjects: globalProjects,
316324
Project: proj,
317-
Repositories: repositories,
318-
Clusters: clusters,
325+
Repositories: apiRepos,
326+
Clusters: apiClusters,
319327
}, err
320328
}
321329

server/repository/repository_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ func TestRepositoryServer(t *testing.T) {
313313
testRepo := &appsv1.Repository{
314314
Repo: url,
315315
Type: "git",
316-
Username: "foo",
316+
Username: "",
317317
InheritedCreds: true,
318318
}
319319
db.On("ListRepositories", t.Context()).Return([]*appsv1.Repository{testRepo}, nil)

0 commit comments

Comments
 (0)