CVE-2025-59022

Trash Can Fire: How the TYPO3 Recycler Turned into a Data Shredder

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 13, 2026·7 min read

Executive Summary (TL;DR)

The 'Recycler' (trash bin) in TYPO3 didn't check if you had permission to modify a specific table before letting you permanently delete records from it. It also got confused by records that were already 'soft-deleted,' effectively failing open on permission checks. Result: Low-privileged backend users could wipe out the entire site's database, including admin accounts and root pages.

A broken access control vulnerability in the TYPO3 CMS Recycler module allowed authenticated backend users to bypass table-level permissions and permanently delete arbitrary data. By exploiting logic flaws in how 'soft-deleted' records were handled, attackers could purge critical system tables, resulting in a catastrophic Denial of Service.

The Hook: The Janitor With the Nuclear Codes

In the world of Content Management Systems (CMS), the "Recycler" or "Trash Bin" is usually a boring, safe corner of the backend. It's the digital safety net where content editors go to retrieve that blog post they accidentally deleted before their morning coffee kicked in. It's supposed to be forgiving. It's supposed to be low-risk.

But in TYPO3, a framework known for its rigorous permission granularity, the Recycler turned out to be the ultimate weapon. CVE-2025-59022 isn't a complex buffer overflow or a fancy deserialization chain. It's a logic failure that gave the digital janitor the keys to the incinerator.

Here is the setup: You grant a junior editor access to the Recycler so they can manage their own mistakes. You restrict them so they can only edit blog posts (tx_news). You explicitly forbid them from touching system users (be_users) or core configurations. You sleep soundly, thinking your ACLs (Access Control Lists) are bulletproof.

Then, that junior editor sends a single AJAX request and permanently purges your Administrator account. Oops.

The Flaw: Logic Rot in the Trash Heap

To understand this vulnerability, you have to understand how TYPO3 handles deletion. Like many enterprise systems, TYPO3 uses "soft deletion." When you delete a page, it doesn't vanish; the database column deleted is set to 1. The Recycler module's job is to show these deleted=1 records and offer two choices: Restore (undelete) or Purge (hard delete).

The vulnerability stems from a catastrophic misalignment of two systems: Authorization and Context.

First, the DataHandler—the central engine for database writes—was asleep at the wheel. When receiving a command to permanently delete a record, it blindly assumed that if you reached that point, you must be allowed to do it. It neglected to call checkModifyAccessList($table), which is the specific function that checks if the current user group is actually allowed to modify the target table.

Second, and arguably funnier, was the "Ghost Problem." When TYPO3 checks permissions (e.g., "Is this user allowed to edit this page?"), it traverses the "Rootline" (the page tree). But standard permission checks filter out deleted records. So, when the Recycler asked, "Can User X manage this deleted record?", the permission system couldn't find the record in the active tree because... well, it was deleted.

Instead of failing secure (blocking access), the logic essentially shrugged. The traversal failed to validate the path, and the operation proceeded. It's the security equivalent of a guard saying, "I can't find your ID in the system because you're listed as 'fired', so go right ahead and enter the server room."

The Code: Diff or It Didn't Happen

The fix required patching the DataHandler to stop trusting the caller. Let's look at the critical logic gap in typo3/sysext/core/Classes/DataHandling/DataHandler.php.

The Vulnerable Logic (Conceptual):

public function deleteAction(string $table, int $uid, ...): void
{
    // Proceed to delete without checking if the user owns this table
    $this->deleteRecord($table, $uid);
}

The Fix (v12/v13): In the patch, the maintainers force a hard stop if the user lacks table-specific modification rights. They also updated the permission checkers to handle the "Ghost Problem" by allowing traversal of deleted nodes.

// File: typo3/sysext/core/Classes/DataHandling/DataHandler.php
 
public function deleteAction(string $table, int|array $uidOrRow, bool $noRecordCheck = false, bool $forceHardDelete = false): void
{
    // ... (snip) ...
    
    // THE FIX: Explicitly verify the user has access to modify this specific table.
    // If $noRecordCheck is false (default for Recycler), this gate drops.
    if (!$noRecordCheck && !$this->checkModifyAccessList($table)) {
        $this->log(
            $table, 
            0, 
            SystemLogDatabaseAction::DELETE, 
            null, 
            SystemLogErrorClassification::USER_ERROR, 
            'Cannot delete "{table}:{uid}" without permission', 
            null, 
            ['table' => $table, 'uid' => $uid]
        );
        return;
    }
    
    // ... (proceed to delete)
}

They also had to patch BackendUtility::BEgetRootLine and BackendUserAuthentication::isInWebMount to accept a new flag that says, "Yes, I know it's deleted, check the permissions anyway." Without this, the system literally couldn't "see" the deleted items to verify ownership.

The Exploit: Taking Out the Trash (Permanently)

Exploiting this is trivially easy if you have a compromised or malicious low-level account. The Recycler module operates via AJAX controllers. We don't need a complex binary payload; we just need a valid session cookie and a browser developer console (or Burp Suite).

The Attack Scenario:

  1. Recon: Log in as LowPrivUser. Confirm you have access to the Recycler module. You don't need admin rights; you just need the module enabled.
  2. Target Selection: You want to cause maximum chaos. The be_users table (backend admins) or sys_template (TypoScript site configuration) are prime targets. Let's say we want to delete the main Administrator (UID 1).
  3. The Payload: The Recycler expects a command to delete records. It should only work for stuff you deleted, but thanks to the missing table check, we can feed it anything.

[!WARNING] This is a hypothetical attack chain for educational purposes. Do not execute this on live environments.

POST /typo3/ajax/recycler/delete HTTP/1.1
Host: target-typo3-site.com
Cookie: be_typo_user=...
Content-Type: application/json
 
{
    "table": "be_users",
    "uid": 1
}

The Result: The DataHandler receives the request.

  • Check 1: "Is the user authenticated?" Yes.
  • Check 2: "Is be_users in their allowed modify list?" SKIPPED (The vulnerability).
  • Check 3: "Is the record deleted?" If the admin account wasn't already soft-deleted, the exploit might require a two-step process (soft-delete first via another vector, or relying on forceHardDelete parameters if exposed), but in many vulnerable versions, the validation logic simply collapses.

The database executes DELETE FROM be_users WHERE uid=1. The main admin is gone. The site is effectively headless.

The Impact: Scorched Earth

Why is this a High severity (7.1) and not Critical (9.0+)? Mostly because it requires an authenticated account. However, inside an organization, the impact is devastating. This is an Availability nightmare.

An insider threat or a compromised editor account can:

  1. Wipe Administrative Access: Delete all be_users except their own (or even their own, for pure nihilism).
  2. Brick the Frontend: Delete sys_template (root TypoScript records) or pages (root page tree). The public website will immediately throw 500 errors or 404s.
  3. Destroy Business Data: Purge tt_address, fe_users (customer data), or shop orders if extensions like ext:cart or ext:news are used.

Because this is a Hard Delete (SQL DELETE), there is no "Undo" button in the CMS. Unless you have recent, cold offline database backups, the data is gone forever. It is the digital equivalent of setting the archives on fire.

The Fix: Patch or Perish

The TYPO3 security team released a coordinated patch across five major versions on January 13, 2026. This is not a configuration fix; you must update the core code.

Remediation Steps:

  1. Composer Update: If you are running a modern TYPO3 setup, run:
    composer update "typo3/cms-*" --with-all-dependencies
  2. Verify Version: Ensure your typo3/cms-core package matches the fixed versions below.

Fixed Versions:

  • v14.0.2
  • v13.4.23
  • v12.4.41
  • v11.5.49 (ELTS)
  • v10.4.55 (ELTS)

Emergency Mitigation: If you cannot deploy the patch immediately, you must revoke access to the Recycler module for everyone except the most trusted Super Admins. Go to Backend Groups -> Access Lists -> Modules and uncheck Recycler.

Fix Analysis (2)

Technical Appendix

CVSS Score
7.1/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
EPSS Probability
0.04%
Top 89% most exploited

Affected Systems

TYPO3 CMS v14.0.0 - 14.0.1TYPO3 CMS v13.0.0 - 13.4.22TYPO3 CMS v12.0.0 - 12.4.40TYPO3 CMS v11.0.0 - 11.5.48TYPO3 CMS v10.0.0 - 10.4.54

Affected Versions Detail

Product
Affected Versions
Fixed Version
TYPO3 CMS
TYPO3
14.0.0 - 14.0.114.0.2
TYPO3 CMS
TYPO3
13.0.0 - 13.4.2213.4.23
TYPO3 CMS
TYPO3
12.0.0 - 12.4.4012.4.41
AttributeDetail
CWE IDCWE-862
Attack VectorNetwork (Ajax)
CVSS v4.07.1 (High)
ImpactHigh Availability Loss (Data Destruction)
Privileges RequiredLow (Authenticated Backend User)
Exploit StatusLogic Flaw (Trivial to Script)
VendorTYPO3
CWE-862
Missing Authorization

The software does not perform an authorization check when an actor attempts to access a resource or perform an action.

Vulnerability Timeline

Vendor Advisory Published
2026-01-13
Patches Released for v10-v14
2026-01-13
CVE-2025-59022 Assigned
2026-01-13

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.