Skip to content

BuildNot yet confirmed elsewhere1 publisher2 min readPublished

One skipped escape call left Telegram Desktop's HTML export open to stored XSS for 28 months

Telegram patched a stored XSS in Telegram Desktop's HTML chat export in July, after the flaw shipped in stable releases for about 28 months. No CVE or advisory came with the fix, so teams that track exposure by CVE ID had nothing to match against.

The Engineer · Build desk

How we use AISend a correction

What happened

  • Denis Rostilov and Aleksander Rostilov of ExPatch Vulnerability Research found the flaw and disclosed it on September 12, 2026.
  • The export's SerializeString() function escaped message text, sender names and other user fields, but inline keyboard button text went into the file raw.
  • The fixing commit also closed a second injection, where copy-button content went into a JavaScript string in an onclick handler with backslashes and single quotes unescaped.
  • According to the write-up, opening the exported file runs the script with no further click and can send the page's messages, sender names, timestamps and local file path to a remote server.

Why it matters

  • exposure The script runs for whoever needed the record, a compliance officer or lawyer in the write-up's example, so it executes on the machine that holds the exported archive.
  • constraint Testing inside the Telegram client could not surface the bug, since its renderer showed the payload as inert text; only the generated HTML, opened in a browser, would expose it.
  • decision Teams whose exports, report generators, HTML-to-PDF steps or on-disk test dashboards take user strings have to check every append into HTML, labels included, and not only the escaping helper.

According to the dev.to write-up of the findings, Telegram Desktop draws messages with its own UI framework, not a browser engine, so a literal `<script>` tag in a bot's button text appeared as plain characters [9]. The researchers padded the payload with invisible Unicode, and in the client they tested the button looked empty [10]. The HTML export does interpret that string as markup. It writes the string into a file, a browser opens the file, and the characters run as code [11].

One string had two consumers with different rules. The client was safe because of how it draws text, and nothing had cleaned the data itself [9][6]. The write-up says this split also removed the usual precondition for stored XSS: write access to the place the payload lands [13]. In its example, a bot message carrying the payload sits in a chat for months until someone exports it [17].

The escaping function itself was sound. SerializeString() in export_output_html.cpp escapes the five HTML-significant characters, converts newlines to `<br>` and hex-encodes ASCII control characters [4]. The failure was one call site. The vulnerable line was `block.append(button.text.toUtf8())` [6]. Commit 8457d13a, by Telegram Desktop developer John Preston, changed it to `block.append(SerializeString(button.text.toUtf8()))` [7]. Bug and fix differ by one function name and a pair of parentheses [6][7].

We would study the second injection hardest. Its context was a JavaScript string inside an HTML attribute [8]. Backslash is not among the characters SerializeString() handles [4], so that context needed escaping of its own.

The write-up describes the general failure this way: a template has eleven fields, ten get escaped, and the eleventh is a string treated as just a label [14]. For the Telegram lesson to apply to another app, three things have to hold. User-controlled strings reach an HTML writer. The primary display renders those strings safely by some other route. Someone opens the output in a browser. The Telegram export met all three [9][11].

In our view the fix that lasts is structural. An HTML writer should escape on every append by default and allow raw output only through a separately named call. Then an unescaped field has to be written on purpose, and a reviewer can see it.

What to watch

  • Whether a CVE is assigned retroactively, or Telegram publishes an advisory naming the first Telegram Desktop release that carries commit 8457d13a.
  • Whether other messaging clients with HTML export turn out to skip bot-controlled fields such as button labels in the same way.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence55
Adoption
Insufficient
Hype gap+25
Incentives
Insufficient
Confidence50
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    Security researchers Denis Rostilov and Aleksander Rostilov of ExPatch Vulnerability Research found a stored XSS in Telegram Desktop's HTML export feature, disclosed on September 12, 2026, after Telegram patched it in July.

    ReportedSupportedSource: dev.to write-upView cited source
  2. [2]

    No CVE number was ever assigned, and Telegram published no dedicated security advisory.

    ReportedSupportedSource: dev.to write-upView cited source
  3. [3]

    The vulnerable line of code sat in stable releases for roughly two years and four months.

    ReportedSupportedSource: dev.to write-upView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · October 10, 2026

    The Telegram Export XSS Is Not About Telegram. It Is About Every App That Generates HTML.

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Entities

Loading related stories