CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2025-47933
9.10.03%

GitOops: Stored XSS in Argo CD Leads to Cluster Takeover

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 26, 2026·5 min read·66 visits

PoC Available

Executive Summary (TL;DR)

Argo CD trusted user input when rendering repository URLs. Attackers with 'repo edit' permissions can inject `javascript:` payloads. When an admin views the settings page, the payload executes, allowing the attacker to ride the admin's session to delete apps, steal secrets, or deploy malware.

A critical Stored Cross-Site Scripting (XSS) vulnerability has been discovered in Argo CD, the industry-standard GitOps continuous delivery tool. By injecting a malicious URL protocol into the repository configuration, an attacker can execute arbitrary JavaScript in the browser of any user viewing the repository list—typically a high-privileged administrator. This effectively bridges the gap between low-level configuration access and full Kubernetes cluster compromise.

The Keys to the Kingdom

Argo CD is the darling of the Cloud Native world. It’s the bouncer, the gatekeeper, and the janitor for your Kubernetes clusters. It holds the keys to the castle—literally—managing secrets, deployments, and infrastructure state. If you compromise Argo CD, you don't just get a shell; you get kubectl apply -f ownage.yaml on every cluster it manages.

Usually, we think of XSS as a "medium" severity annoyance—alert boxes and maybe some cookie theft. But context is king. In an administrative dashboard like Argo CD, XSS is the digital equivalent of a Jedi mind trick on the sysadmin. You aren't hacking the server; you are convincing the server that the admin wants to delete the production database. This vulnerability, CVE-2025-47933, turns a simple UI bug into a catastrophic infrastructure collapse.

The Flaw: Trusting the Parser

The road to hell is paved with helpful utility libraries. In this case, the vulnerability lies in how Argo CD's frontend handles Git URLs. To make the UI look pretty, the developers used a library called git-url-parse to break down repository URLs into their component parts (protocol, owner, resource, etc.) and then reassemble them for display.

Here is the logic flaw: The code assumed that if a URL could be parsed, it was safe to display. It took the parsed components and blindly concatenated them back into a string to be used in an href attribute. It failed to ask the most important question in web security: "Is this protocol actually safe?"

By supplying a URL that technically satisfies the parser but utilizes the javascript: pseudo-protocol, an attacker can turn a clickable link into a stored execution trigger. It’s a classic case of sanitization happening in the wrong place—or in this case, not happening at all.

The Code: Anatomy of a Screw-Up

Let's look at the crime scene in ui/src/app/shared/components/urls.ts. The vulnerable function repoUrl takes a string and tries to return a formatted URL.

The Vulnerable Code:

export function repoUrl(url: string): string {
    try {
        const parsed = GitUrlParse(url);
        // The fatal flaw: Blind concatenation without validation
        return `${protocol(parsed.protocol)}://${parsed.resource}/${parsed.owner}/${parsed.name}`;
    } catch {
        return null;
    }
}

See that return statement? It constructs a string using the protocol derived from the input. If I pass in javascript:alert(1), and git-url-parse is lenient enough to treat javascript as the protocol, the function happily returns a valid JS URI.

The Fix:

The patch is simple: validation. The maintainers introduced an isValidURL check that likely whitelists protocols like http, https, ssh, and git.

import {isValidURL} from '../../shared/utils';
 
export function repoUrl(url: string): string {
    try {
        const parsed = GitUrlParse(url);
        const parsedUrl = `${protocol(parsed.protocol)}://${parsed.resource}/${parsed.owner}/${parsed.name}`;
        
        // The Guard Rail
        if (!isValidURL(parsedUrl)) {
            return null;
        }
        return parsedUrl;
    }
}

It’s a three-line fix for a 9.1 CVSS vulnerability. Security is often boring like that.

The Exploit: Weaponizing a Link

So, how do we burn it down? We need two things: access to create/edit a repository, and an admin victim.

Step 1: The Setup

We authenticate as a low-privileged user (perhaps a developer with access to a specific project). We navigate to Settings -> Repositories or use the CLI to register a new repo. Instead of a valid GitHub URL, we provide our payload. The parser might be tricky, so we craft it to look like a valid Git URL structure but with a malicious protocol.

Step 2: The Payload

We inject something nasty. We don't want an alert box; we want persistence.

javascript:fetch('/api/v1/account/password', {method: 'PUT', body: JSON.stringify({currentPassword: '...', newPassword: 'owned'})})

Or perhaps we simply delete the production application:

javascript:fetch('/api/v1/applications/prod-app?cascade=true', {method: 'DELETE'})

Step 3: The Trap

The URL is saved to Kubernetes secrets. Now we wait. An Argo CD administrator logs in to check why a sync failed or to audit the repositories. They navigate to the Repositories page. The UI renders our malicious link. Depending on the browser behavior and the exact rendering, this might trigger on a stray click, or we could style the link to cover the whole screen using CSS injection if the inputs allow it.

Step 4: Game Over

The script executes in the context of the Admin. The browser sends the API request with the Admin's cookies/tokens. The API sees a valid request from a Super Admin. The cluster is yours.

Impact: Why You Should Panic

If you are running a vulnerable version, you are one disgruntled employee or one compromised dev account away from total disaster.

Because Argo CD is declarative, this XSS allows an attacker to rewrite the "truth" of your infrastructure. They could inject a sidecar container into your payment processing pods to skim credit cards. They could modify the OIDC configuration to lock everyone out. They could simply wipe the cluster.

This isn't just a UI bug; it's a privilege escalation tunnel from "I can edit git repos" to "I am Root on the Cluster".

The Fix: Stop the Bleeding

Don't try to get clever with WAF rules here; the payload is stored encrypted in your secrets and rendered by the client. You need to patch the binary.

Update Immediately:

  • If you are on 2.x, go to 2.13.8 or 2.14.13.
  • If you are on 3.x, go to 3.0.4.

If you cannot patch immediately, you must restrict RBAC permissions. Remove repositories, update and repositories, create from all non-admin roles. And for the love of Ops, audit your current repositories:

kubectl get secrets -n argocd -l argocd.argoproj.io/secret-type=repository -o jsonpath="{.items[*].data.url}" | base64 -d

If you see javascript: in there, pull the fire alarm.

Official Patches

Argo ProjectOfficial GitHub Security Advisory
Argo ProjectFix Commit

Fix Analysis (1)

Technical Appendix

CVSS Score
9.1/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H
EPSS Probability
0.03%
Top 93% most exploited

Affected Systems

Argo CD

Affected Versions Detail

Product
Affected Versions
Fixed Version
Argo CD
Argo Project
>= 1.2.0-rc1, < 2.13.82.13.8
Argo CD
Argo Project
>= 2.14.0-rc1, < 2.14.132.14.13
Argo CD
Argo Project
>= 3.0.0-rc1, < 3.0.43.0.4
AttributeDetail
CWE IDCWE-79 (Cross-Site Scripting)
CVSS v3.19.1 (Critical)
Attack VectorNetwork (Stored in Config)
Privileges RequiredLow (Repo Edit)
ImpactRemote Code Execution (via API)
Patch StatusAvailable

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
T1552Unsecured Credentials
Credential Access
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Vulnerability Timeline

Fix committed to master branch
2025-05-28
GHSA-2hj5-g64g-fp6p published
2025-05-29
CVE-2025-47933 assigned
2025-05-29

References & Sources

  • [1]NVD Entry
  • [2]Argo CD Documentation

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.