Skip to content

Commit 968b05f

Browse files
alexmtcrenshaw-devdependabot[bot]
authored
fix(security): repository.GetDetailedProject exposes repo secrets (#24387) (#24463)
Signed-off-by: Alexander Matyushentsev <[email protected]> Signed-off-by: Michael Crenshaw <[email protected]> Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Michael Crenshaw <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent bc51fa1 commit 968b05f

File tree

8 files changed

+134
-22
lines changed

8 files changed

+134
-22
lines changed

.github/workflows/ci-build.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ jobs:
7878
with:
7979
go-version: ${{ env.GOLANG_VERSION }}
8080
- name: Restore go build cache
81-
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
81+
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
8282
with:
8383
path: ~/.cache/go-build
8484
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -148,7 +148,7 @@ jobs:
148148
run: |
149149
echo "/usr/local/bin" >> $GITHUB_PATH
150150
- name: Restore go build cache
151-
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
151+
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
152152
with:
153153
path: ~/.cache/go-build
154154
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -217,7 +217,7 @@ jobs:
217217
run: |
218218
echo "/usr/local/bin" >> $GITHUB_PATH
219219
- name: Restore go build cache
220-
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
220+
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
221221
with:
222222
path: ~/.cache/go-build
223223
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -309,7 +309,7 @@ jobs:
309309
node-version: '21.6.1'
310310
- name: Restore node dependency cache
311311
id: cache-dependencies
312-
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
312+
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
313313
with:
314314
path: ui/node_modules
315315
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -346,7 +346,7 @@ jobs:
346346
fetch-depth: 0
347347
- name: Restore node dependency cache
348348
id: cache-dependencies
349-
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
349+
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
350350
with:
351351
path: ui/node_modules
352352
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -444,7 +444,7 @@ jobs:
444444
sudo chmod go-r $HOME/.kube/config
445445
kubectl version
446446
- name: Restore go build cache
447-
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
447+
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
448448
with:
449449
path: ~/.cache/go-build
450450
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}

docs/operator-manual/upgrading/2.10-2.11.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,13 @@ spec:
5555
+ protocol: UDP
5656
+ - port: 53
5757
+ protocol: TCP
58-
```
58+
```
59+
60+
## Sanitized project API response
61+
62+
Due to security reasons ([GHSA-786q-9hcg-v9ff](https://github.com/argoproj/argo-cd/security/advisories/GHSA-786q-9hcg-v9ff)),
63+
the project API response was sanitized to remove sensitive information. This includes
64+
credentials of project-scoped repositories and clusters.
65+
66+
> **Note:** The 2.11 series has been EOL for some time and has not received security updates. 2.11.14 was patched for critical
67+
> CVE-2025-55190 but was not patched for other vulnerabilities. It is important to upgrade to a supported version as quickly as possible.

pkg/apis/application/v1alpha1/repository_types.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"net/url"
66
"strings"
77

8+
"github.com/argoproj/argo-cd/v2/common"
89
"github.com/argoproj/argo-cd/v2/util/cert"
910
"github.com/argoproj/argo-cd/v2/util/git"
1011
"github.com/argoproj/argo-cd/v2/util/helm"
@@ -276,6 +277,32 @@ func (m *Repository) StringForLogging() string {
276277
return fmt.Sprintf("&Repository{Repo: %q, Type: %q, Name: %q, Project: %q}", m.Repo, m.Type, m.Name, m.Project)
277278
}
278279

280+
// Sanitized returns a copy of the Repository with sensitive information removed.
281+
func (repo *Repository) Sanitized() *Repository {
282+
return &Repository{
283+
Repo: repo.Repo,
284+
Type: repo.Type,
285+
Name: repo.Name,
286+
Insecure: repo.IsInsecure(),
287+
EnableLFS: repo.EnableLFS,
288+
EnableOCI: repo.EnableOCI,
289+
Proxy: repo.Proxy,
290+
Project: repo.Project,
291+
ForceHttpBasicAuth: repo.ForceHttpBasicAuth,
292+
InheritedCreds: repo.InheritedCreds,
293+
GithubAppId: repo.GithubAppId,
294+
GithubAppInstallationId: repo.GithubAppInstallationId,
295+
GitHubAppEnterpriseBaseURL: repo.GitHubAppEnterpriseBaseURL,
296+
}
297+
}
298+
299+
func (repo *Repository) Normalize() *Repository {
300+
if repo.Type == "" {
301+
repo.Type = common.DefaultRepoType
302+
}
303+
return repo
304+
}
305+
279306
// Repositories defines a list of Repository configurations
280307
type Repositories []*Repository
281308

pkg/apis/application/v1alpha1/types.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,6 +1791,30 @@ type Cluster struct {
17911791
Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,13,opt,name=annotations"`
17921792
}
17931793

1794+
func (c *Cluster) Sanitized() *Cluster {
1795+
return &Cluster{
1796+
ID: c.ID,
1797+
Server: c.Server,
1798+
Name: c.Name,
1799+
Project: c.Project,
1800+
Namespaces: c.Namespaces,
1801+
Shard: c.Shard,
1802+
Labels: c.Labels,
1803+
Annotations: c.Annotations,
1804+
ClusterResources: c.ClusterResources,
1805+
ConnectionState: c.ConnectionState,
1806+
ServerVersion: c.ServerVersion,
1807+
Info: c.Info,
1808+
RefreshRequestedAt: c.RefreshRequestedAt,
1809+
Config: ClusterConfig{
1810+
AWSAuthConfig: c.Config.AWSAuthConfig,
1811+
TLSClientConfig: TLSClientConfig{
1812+
Insecure: c.Config.Insecure,
1813+
},
1814+
},
1815+
}
1816+
}
1817+
17941818
// Equals returns true if two cluster objects are considered to be equal
17951819
func (c *Cluster) Equals(other *Cluster) bool {
17961820
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
@@ -3673,3 +3673,58 @@ func TestApplicationSpec_GetSourcePtrByIndex(t *testing.T) {
36733673
})
36743674
}
36753675
}
3676+
3677+
func TestSanitized(t *testing.T) {
3678+
now := metav1.Now()
3679+
cluster := &Cluster{
3680+
ID: "123",
3681+
Server: "https://example.com",
3682+
Name: "example",
3683+
ServerVersion: "v1.0.0",
3684+
Namespaces: []string{"default", "kube-system"},
3685+
Project: "default",
3686+
Labels: map[string]string{
3687+
"env": "production",
3688+
},
3689+
Annotations: map[string]string{
3690+
"annotation-key": "annotation-value",
3691+
},
3692+
ConnectionState: ConnectionState{
3693+
Status: ConnectionStatusSuccessful,
3694+
Message: "Connection successful",
3695+
ModifiedAt: &now,
3696+
},
3697+
Config: ClusterConfig{
3698+
Username: "admin",
3699+
Password: "password123",
3700+
BearerToken: "abc",
3701+
TLSClientConfig: TLSClientConfig{
3702+
Insecure: true,
3703+
},
3704+
ExecProviderConfig: &ExecProviderConfig{
3705+
Command: "test",
3706+
},
3707+
},
3708+
}
3709+
3710+
assert.Equal(t, &Cluster{
3711+
ID: "123",
3712+
Server: "https://example.com",
3713+
Name: "example",
3714+
ServerVersion: "v1.0.0",
3715+
Namespaces: []string{"default", "kube-system"},
3716+
Project: "default",
3717+
Labels: map[string]string{"env": "production"},
3718+
Annotations: map[string]string{"annotation-key": "annotation-value"},
3719+
ConnectionState: ConnectionState{
3720+
Status: ConnectionStatusSuccessful,
3721+
Message: "Connection successful",
3722+
ModifiedAt: &now,
3723+
},
3724+
Config: ClusterConfig{
3725+
TLSClientConfig: TLSClientConfig{
3726+
Insecure: true,
3727+
},
3728+
},
3729+
}, cluster.Sanitized())
3730+
}

server/cluster/cluster.go

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

460460
func (s *Server) toAPIResponse(clust *appv1.Cluster) *appv1.Cluster {
461+
clust = clust.Sanitized()
461462
_ = s.cache.GetClusterInfo(clust.Server, &clust.Info)
462-
463-
clust.Config.Password = ""
464-
clust.Config.BearerToken = ""
465-
clust.Config.TLSClientConfig.KeyData = nil
466-
if clust.Config.ExecProviderConfig != nil {
467-
// We can't know what the user has put into args or
468-
// env vars on the exec provider that might be sensitive
469-
// (e.g. --private-key=XXX, PASSWORD=XXX)
470-
// Implicitly assumes the command executable name is non-sensitive
471-
clust.Config.ExecProviderConfig.Env = make(map[string]string)
472-
clust.Config.ExecProviderConfig.Args = nil
473-
}
474463
// populate deprecated fields for backward compatibility
475464
clust.ServerVersion = clust.Info.ServerVersion
476465
clust.ConnectionState = clust.Info.ConnectionState

server/project/project.go

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

311319
return &project.DetailedProjectsResponse{
312320
GlobalProjects: globalProjects,
313321
Project: proj,
314-
Repositories: repositories,
315-
Clusters: clusters,
322+
Repositories: apiRepos,
323+
Clusters: apiClusters,
316324
}, err
317325
}
318326

server/repository/repository_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ func TestRepositoryServer(t *testing.T) {
309309
testRepo := &appsv1.Repository{
310310
Repo: url,
311311
Type: "git",
312-
Username: "foo",
312+
Username: "",
313313
InheritedCreds: true,
314314
}
315315
db.On("GetRepository", context.TODO(), url).Return(testRepo, nil)

0 commit comments

Comments
 (0)