The Flying Scripts plugin for WordPress is vulnerable to stored cross-site scripting in every version up to and including 1.2.4, and the National Vulnerability Database entry rates it CVSS 7.2, high severity. An unauthenticated attacker can inject arbitrary web scripts through the comment parameter. The scripts run whenever a visitor loads an injected page. That much is a familiar shape: a WordPress plugin mishandles input, and stored XSS follows.

What makes CVE-2026-109990 worth a second look is the bypass. The payload never smuggles a <script> tag past WordPress core’s save-time kses sanitization. It uses only elements kses already allows, an <abbr title> attribute and <code> text content, and lets the plugin’s own output-buffer rewriter assemble the dangerous markup after the save. The flaw is not a missing filter at the door. It is a rewriter that trusts its own placeholders.

How the bypass works

Here is the mechanism, per the NVD description. The plugin’s output-buffer rewriter swaps content in and out using placeholder keys of the form ___noise___. Those keys are predictable and unsalted. When a saved comment contains an <abbr title> attribute and a <code> body, the rewriter substitutes the <code> text, which can carry a double quote, into the <abbr title> attribute. A double quote inside an attribute value is enough to break out of the attribute and start a new one. That is where the script lands. The XSS is introduced post-save, after kses has already run and passed the content.

Read that sequence again. WordPress core does its job. The sanitizer sees only allowed elements and waves the input through. The plugin then takes that sanitized content and, at render time, performs a string substitution that reconstitutes a payload the sanitizer never had a chance to inspect. The predictable, unsalted placeholder keys are the hinge. If the keys were unpredictable, an attacker could not reliably target the substitution. If they were salted per request, the rewriter could not be steered. Neither protection is present.

Why this is a kses lesson, not just a plugin bug

The WordPress ecosystem has spent years teaching developers that wp_kses and its save-time cousins are the line of defense. That framing is incomplete, and this CVE is the proof. Sanitization at save time is a snapshot. Any code that later transforms stored content, especially an output-buffer rewriter that runs on the way to the browser, operates on a different string than the one the sanitizer approved. The gap between those two strings is the attack surface.

The plugin’s rewriter is doing something legitimate in principle: delaying JavaScript, deferring script execution to improve page speed. That is the whole product. But the implementation treats stored content as a template to be edited, and it edits it with placeholders an outsider can predict. The result is a stored XSS that requires no account, no privilege, and no clever encoding. Just a comment.

What this means for AI builders

Tessera reads this through an AI lens, and the lens is uncomfortable. A growing share of AI-adjacent software is exactly this kind of pipeline: content goes in, a model or a template engine transforms it, and the transformed output goes to a user. The pattern is everywhere in AI tooling. Retrieval systems stitch retrieved text into prompts. Agent frameworks substitute tool outputs into templates. RAG pipelines concatenate untrusted documents with instructions. Content-generation plugins rewrite stored text on the way out. Each of these is a rewriter, and each inherits the same question this CVE asks: does the transformation preserve the trust boundary the sanitizer established, or does it dissolve it?

In the Flying Scripts case the answer was dissolve. The sanitizer approved one string; the rewriter emitted another. An AI pipeline that pulls a retrieved document into a prompt and then renders model output into a page has the same two-step structure, with the same opportunity for a trusted-looking intermediate to become an untrusted final. The specific payload differs. The structural mistake does not.

There is a second lesson, about placeholders. The ___noise___ keys are predictable and unsalted, which is what makes the substitution steerable. AI systems are full of analogous seams: fixed prompt delimiters, predictable tool-call wrappers, template tokens a user can guess and inject around. A delimiter that a model treats as a boundary but an attacker can reproduce is the same class of error. Predictability is the vulnerability, whether the predictable string is a placeholder key or a system-prompt fence.

The practical read

For anyone running WordPress with The Flying Scripts at 1.2.4 or below, the fix is the usual: update, and treat the comment parameter as hostile until you have. The NVD entry is the authoritative record, and it is worth reading in full rather than skimming the CVSS number. A 7.2 is high but not catastrophic on its own; the reason to care is the unauthenticated path and the stored persistence. One injected comment, many visitors.

For AI builders, the takeaway is narrower and more useful than “sanitize your inputs.” Sanitize your transformations. Every stage that rewrites stored or retrieved content between the trust check and the browser is a place where the check can be undone. The Flying Scripts rewriter undid kses with a double quote and a predictable key. An agent pipeline can undo a prompt boundary with a stray delimiter and a retrieved paragraph. The mechanism rhymes. The fix rhymes too: make the seams unpredictable, and re-validate after the rewrite, not only before it.

The outstanding question for the plugin’s maintainers is whether 1.2.5 salts the placeholder keys or abandons the substitution approach entirely. The NVD entry documents the flaw in 1.2.4 and below. It does not yet describe the patch. That is the line to watch.