Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-66421-OpenClaw-Dashboard-Stored-XSS-via-lastMessage-Session-Field — Security Advisory: Stored Cross-Site Scripting Via Agent Messages Leading To Session Token Theft (openclaw-dashboard) | Kitploit
Tools/GitHubGitHub/theopaid/cve-2026-66421-openclaw-dashboard-stored-xss-via-lastmessage-session-field
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityAPI SecurityAI Security
GitHubtheopaid/cve-2026-66421-openclaw-dashboard-stored-xss-via-lastmessage-session-field

CVE-2026-66421-OpenClaw-Dashboard-Stored-XSS-via-lastMessage-Session-Field

Security Advisory: Stored Cross-Site Scripting Via Agent Messages Leading To Session Token Theft (openclaw-dashboard)

View Repository
51 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

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 (d6198d0). Not fixed at the time of writing.

main

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:

root@kitploit:~
// 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:

root@kitploit:~
// 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:

root@kitploit:~
// index.html:3758
const lastMsg = s.lastMessage ? s.lastMessage.substring(0, 60) + (s.lastMessage.length > 60 ? '…' : '') : '';
root@kitploit:~
// 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:

    root@kitploit:~

    This is 56 characters and reaches the agent's session transcript like any normal message.

  2. Confirm the server hands the payload back unescaped:

    root@kitploit:~
    curl -H "Authorization: Bearer ADMIN_TOKEN" http://TARGET:7000/api/sessions
    

    The affected session's lastMessage field contains the raw `` 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 `` 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.
Download Tool