genai
SECURITY LAB
IncidentsImproper output handling

Lenovo's “Lena” Chatbot: Stored XSS That Fired in a Support Agent's Browser

High severityVendor vulnerabilityAugust 2025LLM10: Improper Output HandlingLLM01: Prompt Injection
Status: Research disclosure: reported 22 Jul 2025, acknowledged by Lenovo 6 Aug, fixed before public disclosure on 18 Aug 2025; no CVE
Sources checked October 2026
On this page

One chat message got Lenovo's support bot to write markup that the support console then ran in a human agent's browser.

WhenFound 22 July 2025; disclosed 18 August 2025
TargetLena, Lenovo's GPT-4 support chatbot, and its human-agent support view
ResearcherCybernews research team
TechniquePrompted HTML in the bot's reply, stored and rendered unescaped (stored XSS)
StatusNo CVE; Lenovo fixed it before public disclosure
ResultSession cookies sent to a researcher-controlled server; the researchers say a support agent's too
Attack flow
  1. 1A researcher asks Lena for laptop specs and tells it to answer in HTML that includes an image set to fail
  2. 2The reply is stored in the chat history and rendered unescaped, so the failed image sends cookies out
  3. 3A human agent opens the handed-off chat and the same markup sends their session cookie to the researchers

What happened

On 18 August 2025, the Cybernews research team disclosed a stored cross-site scripting (XSS) flaw in Lena, the customer-support chatbot on Lenovo's website, which runs on OpenAI's GPT-4. One chat message of about 400 characters got the bot to write HTML into its reply. The app saved that reply to the conversation history and rendered it as live markup, so it ran in the browser of anyone who opened the chat. The researchers said that once the chat was passed to a human, the code ran again in the support agent's browser and sent that agent's session cookie to a server they controlled.

The researchers reported the flaw on 22 July 2025, the day they found it. Lenovo acknowledged it on 6 August and fixed it before publication. This was a research disclosure, not an attack in the wild. Lenovo said it assessed the risk and deployed a fix without putting customers at risk.

How the attack worked

The message had four parts. It opened with an ordinary request for a laptop's specifications. It then asked Lena to give its final answer in a set of formats, HTML among them, in the order Lenovo's web server expected, so the HTML would be processed as markup. Next it described an image at an address that did not exist, with an instruction that the failed load should make the browser call the researchers' server with the page's cookies in the URL. It closed by insisting that the image be shown.

Lena complied, and the rest followed:

  • Stored. The reply, markup included, was written to the chat history on Lenovo's servers.
  • Rendered. Loading the conversation rendered that markup. The image failed and the cookie request fired.
  • Handed off. The researchers asked for a human agent. When the agent opened the chat, their browser loaded the same history and sent their session cookie out.

Why the agent's cookie mattersThe researchers said a stolen agent cookie would let someone sign in to Lenovo's support system as that agent with no username or password, and possibly read other customers' live and past chats. They presented this as possible, not as something they did, and said they did not try the deeper steps they raised, such as running system commands or moving across the network.

Root cause

The prompt only got the model to produce markup. The vulnerability was what the application did with it. Lenovo's chat stack stored the model's reply and rendered it as HTML in two places: the customer's chat window and the agent's view of the same conversation. Nothing between the model and the browser checked or encoded the output. Cybernews listed the gaps as missing input sanitisation, missing output sanitisation, a web server that did not check what the chatbot produced, running code nobody had checked, and fetching content from any web address.

The hand-off raised the stakes. By the researchers' account, an agent's session can reach other customers' conversations, and text a customer steered through a model arrived in that view as trusted HTML. That is classic stored XSS, with an LLM writing the payload for the attacker.

What a test would have caught

A basic output-handling check through the chat box would have found this. Ask the bot to include a harmless HTML element in its answer, then see whether that element renders as markup or shows as plain text. Do it in the customer widget and again in the agent console after a hand-off. The second check is the one teams skip: the test has to follow the reply to every screen that later shows it.

How to prevent it

  • Encode model output for where it lands. Render replies as text by default, through textContent or an auto-escaping template. Where rich formatting is needed, pass it through an allow-list sanitiser that removes scripts, event-handler attributes and javascript: links.
  • Treat stored chat history as untrusted on every screen, the agent console above all. Sanitise before storage and encode again on output.
  • Set a strict Content Security Policy that blocks inline script and limits which hosts the page can load resources from.
  • Mark session cookies HttpOnly so a script that does run cannot read them.
  • Don't rely on the system prompt. Telling the model not to emit HTML does not close the sink.

Feel it yourselfThe replay lab has the same shape: a report you write reaches a staff console through an AI-drafted digest that the console renders as raw HTML.

FAQ

What happened with Lenovo's Lena chatbot?

In August 2025 Cybernews researchers disclosed that a single chat message could make Lena, Lenovo's GPT-4 support bot, write HTML into its reply. The reply was saved to the chat history and ran in the browser of whoever opened it, including a human support agent after a hand-off. Lenovo fixed the flaw before the disclosure.

How did the Lena XSS attack work?

The message asked for laptop specifications, told the bot to answer in HTML, and described an image that would fail to load and then send the page's cookies to the researchers' server. Lena wrote it, the app stored and rendered it without escaping, and the same markup ran again when a support agent opened the chat.

How do you stop a chatbot from causing XSS?

Treat model output as untrusted. Encode it for the place it is displayed, pass any rich HTML through an allow-list sanitiser, set a strict Content Security Policy, and test every screen that shows stored chat history, staff consoles included.

Replay this attack
File an abuse report whose AI-drafted case digest carries live markup into a moderator console that renders it as raw HTML, the same stored path that put Lena's reply in front of a Lenovo support agent.
Open the live lab
A live, sandboxed lab. It recreates the technique, not this exact product.