Lucene search
+L

📄 OpenClaw Dashboard Cross Site Scripting

🗓️ 03 Aug 2026 00:00:00Reported by Theodosis PaidakisType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 14 Views

OpenClaw Dashboard stores unescaped transcripts enabling stored cross site scripting and session token theft.

Related
Code
ReporterTitlePublishedViews
Family
attackerkb
ATTACKERKB
CVE-2026-66421
30 Jul 202622:16
attackerkb
circl
Circl
CVE-2026-66421
30 Jul 202623:00
circl
cve
CVE
CVE-2026-66421
30 Jul 202622:16
cve
cvelist
Cvelist
CVE-2026-66421 OpenClaw Dashboard Stored XSS via lastMessage Session Field
30 Jul 202622:16
cvelist
euvd
EUVD
EUVD-2026-51337
31 Jul 202600:30
euvd
nvd
NVD
CVE-2026-66421
30 Jul 202623:16
nvd
ptsecurity
Positive Technologies
PT-2026-66628
30 Jul 202600:00
ptsecurity
vulnrichment
Vulnrichment
CVE-2026-66421 OpenClaw Dashboard Stored XSS via lastMessage Session Field
30 Jul 202622:16
vulnrichment
# Security Advisory: Stored Cross-Site Scripting Via Agent Messages Leading To Session Token Theft (openclaw-dashboard)
    
    Title: OpenClaw Dashboard Stored XSS via lastMessage Session Field
    CVE ID: CVE-2026-66421
    
    https://github.com/tugcantopaloglu/openclaw-dashboard
    
    ## Summary
    
    The sessions table on the dashboard's landing page shows the last message of each agent
    session. That text is taken from the agent's conversation transcript and written into
    the page with `innerHTML` and no escaping. OpenClaw is a multi-channel agent gateway, so
    the message text can come from anyone who is able to talk to the agent, such as a chat
    group or a webhook. A message containing an HTML payload runs as script in the
    administrator's browser as soon as they open the dashboard.
    
    - CWE-79: Improper Neutralization of Input During Web Page Generation (Cross-site Scripting)
    - CVSS 4.0: 8.8 (High). Vector: `CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N`
    
    ## Affected versions
    
    Present since the first public release. The vulnerable render exists in the earliest
    tag (v1.1.0) and in every later commit up to and including the current `main`
    (d6198d0). Not fixed at the time of writing.
    
    ## Threat model
    
    The attacker is a party who can send a message that lands in the agent's session
    transcript. They do not need a dashboard account. In a typical OpenClaw deployment this
    includes members of connected chat channels and any source that reaches the agent
    through a webhook, so the attacker is often outside the operator's trust boundary.
    
    The payload is stored in the transcript and rendered whenever the administrator views
    the sessions page. That page is the default landing view and refreshes on a timer, so
    the only interaction required is the administrator loading the dashboard they normally
    use. `AT:P` reflects the one condition the attacker relies on: that the deployment
    routes their messages into a session the dashboard displays.
    
    ## Root cause
    
    **Step 1. The message text is extracted from the transcript.** The server reads the
    most recent message and returns its text, cut to 80 characters, with no sanitization:
    
    ```js
    // server.js:474-481
    if (typeof msg.content === 'string') {
      text = msg.content;
    } else if (Array.isArray(msg.content)) {
      for (const b of msg.content) {
        if (b.type === 'text' && b.text) { text = b.text; break; }
      }
    }
    if (text) return text.replace(/\n/g, ' ').substring(0, 80);
    ```
    
    **Step 2. It is exposed through the sessions API.** `getSessionsJson` puts the text on
    the `lastMessage` field of each session:
    
    ```js
    // server.js:538
    lastMessage: getLastMessage(s.sessionId || key),
    ```
    
    `GET /api/sessions` returns this array to the browser.
    
    **Step 3. It is written into the DOM without escaping.** The sessions table builds each
    row by string concatenation and assigns it with `innerHTML`:
    
    ```js
    // index.html:3758
    const lastMsg = s.lastMessage ? s.lastMessage.substring(0, 60) + (s.lastMessage.length > 60 ? '…' : '') : '';
    ```
    
    ```js
    // index.html:3773
    <div class="table-cell" style="..." onclick="toggleSessionExpand('${escapedKey}', event)">${lastMsg}</div>
    ```
    
    `lastMsg` is placed straight into the HTML string. There is no encoding step anywhere on
    this path.
    
    The same table interpolates `s.label` (index.html:3770) and `s.key` (index.html:3767)
    into the row markup the same way. Those fields have no 60-character cap, so they give an
    attacker who can influence them more room for a payload.
    
    The Content-Security-Policy at server.js:298 allows inline event handlers
    (`script-src 'self' 'unsafe-inline'`), so an `onerror` handler runs.
    
    ## Proof of concept
    
    1. As a party who can message the agent, send a message whose text is a short payload
       that fits the 60-character budget, for example:
    
       ```
       <img src=x onerror=console.log('xss',getStoredToken())>
       ```
    
       This is 56 characters and reaches the agent's session transcript like any normal
       message.
    
    2. Confirm the server hands the payload back unescaped:
    
       ```bash
       curl -H "Authorization: Bearer ADMIN_TOKEN" http://TARGET:7000/api/sessions
       ```
    
       The affected session's `lastMessage` field contains the raw `<img ...>` string.
    
    3. The administrator opens the dashboard. The sessions page is the default view, so no
       extra navigation is needed. The row renders, the browser parses the `<img>` tag, the
       `onerror` handler runs, and the administrator's session token is read by the payload.
    
    Replacing the `console.log` body with a `fetch` to a same-origin authenticated endpoint lets the payload act
    with the logged in user's privileges.
    
    ## Impact
    
    Script execution in the dashboard origin as the logged in user, reachable by someone who
    only needs to send the agent a message. The payload can read the session token and call
    authenticated endpoints, including those that edit the agent's own instruction files and
    the OpenClaw configuration. Because it fires on the default page, the administrator does
    not have to take any unusual action.
    
    ## Remediation
    
    - HTML-encode `lastMessage`, `label`, and `key` before inserting them into the row
      markup, or construct the cells with `textContent` rather than an HTML string.
    - Apply the same encoding to the other session fields rendered through `innerHTML`.
    - Remove `'unsafe-inline'` from `script-src` so injected markup cannot execute even if an
      encoding step is missed.

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

03 Aug 2026 00:00Current
4.8Medium risk
Vulners AI Score4.8
CVSS 48.8
CVSS 3.19.3
EPSS0.00363
SSVC
14