Kirby is a flexible, file-based content management system (CMS) loved by developers for its simplicity and customization options. But in early 2024, a new vulnerability was discovered that affected Kirby’s then-new *link field* feature. Tracked as CVE-2024-27087, this bug opened a door for attackers to inject arbitrary JavaScript via certain custom links — potentially leading to Cross-Site Scripting (XSS) attacks.
In this deep dive, we’ll look at how this vulnerability works, how to exploit it, and what you should do to stay safe.
What is CVE-2024-27087?
In Kirby 4, the development team introduced a new link field type. This enhancement allowed different types of links, each with strict validation for valid URLs. Out-of-the-box, Kirby provided pre-defined formats for email, phone, page, and external URLs.
The Problem: "Custom" Link Type
To make the field extra flexible, Kirby also added a Custom link type. As designed, this would catch use cases not covered by the pre-defined types. However, the "Custom" type’s flexibility created a trap: it accepted pretty much any format, including dangerous javascript: URLs.
Why is this a big deal?
If bad actors can insert a javascript: scheme URL into content, and if this link is rendered on a page and clicked, arbitrary JavaScript will be executed in the user’s browser. This could steal cookies, hijack accounts, or deface the site.
The link field accepts javascript: URLs (e.g., javascript:alert('XSS')).
3. If you display these links in your templates without sanitization, the malicious JavaScript code is executed in the visitor’s browser.
Exploit Example
Suppose you have a page "About Us" in Kirby. An attacker, or even an unintentional admin, enters the following in a "Custom" link field:
javascript:alert('XSS')
If your template generates HTML for that link like this
<a href="<?= $page->link()->value() ?>">Click me!</a>
Here’s what the rendered HTML might look like
<a href="javascript:alert('XSS')">Click me!</a>
If a user clicks "Click me!", the browser will run JavaScript and display an alert. Of course, an attacker might do something much worse than popping an alert box.
Add a "Custom" link to a page via the Kirby Panel

*Screenshot: Adding a malicious link using the Custom link type.*
Now, let’s assume your Kirby template shows the link as
<?php if ($page->link()->isNotEmpty()): ?>
<a href="<?= $page->link()->value() ?>">
Go!
</a>
<?php endif ?>
Here's the malicious content inserted
javascript:alert('This is an XSS attack!');
When "Go!" is clicked, the browser launches the JavaScript alert.
Who is affected?
- *Any Kirby 4.x site with the new link field, when using the Custom type and rendering links unsanitized on the front end.*
How Was It Fixed?
Kirby’s team quickly responded with version 4.1.1, released in March 2024.
After the patch, the Custom link type rejects dangerous URL schemes by default, unless you explicitly allow them.
> *If you’re using Kirby 4 and haven’t updated to 4.1.1 or newer, you are at risk!*
Update to Kirby 4.1.1+:
Get the patch from the official releases page.
Audit Your Templates:
Always sanitize or validate any data used as link targets, especially for anything coming from content fields.
Sample fix in your field definition (blueprints)
fields:
mylink:
type: link
allowed:
- url
- email
- page
# Don't include "custom" if you don't need it!
Or, if you must use "Custom", add sanitization in your templates
<?php
$url = $page->link()->value();
if (preg_match('/^javascript:/i', $url)) {
$url = '#'; // neutralize
}
?>
<a href="<?= esc($url) ?>">Safe link</a>
References
- Kirby Security Advisory
- Kirby 4.1.1 Release Notes
- NIST CVE Record
- Kirby Documentation - Link Field
Conclusion
The CVE-2024-27087 bug is a classic case of flexibility gone wrong. While Kirby’s "Custom" link type is a great feature for power users, any opening for javascript: URLs in user-controlled fields is asking for trouble. Check your Kirby version, use only the link types you truly need, and always validate your data!
Timeline
Published on: 02/26/2024 17:15:10 UTC
Last modified on: 02/26/2024 22:10:40 UTC