CVE-2025-59020: The 'Trust Me Bro' Vulnerability in TYPO3 CMS
Jan 14, 2026·7 min read
Executive Summary (TL;DR)
TYPO3's EditDocumentController blindly trusted user-supplied default values (`defVals`) as internal system state. By injecting data into this parameter, low-privilege attackers can bypass the DataHandler's permission checks and modify restricted database fields (like system flags or access controls) during record creation.
A logic flaw in TYPO3's backend controller allows authenticated editors to bypass field-level permissions by disguising malicious input as 'system default values', effectively modifying data they are strictly forbidden from touching.
The Hook: The Helpful Butler Problem
TYPO3 is the enterprise heavy lifter of the CMS world. It’s complex, granular, and usually pretty good about telling you "No." Specifically, the backend uses a massive configuration array (TCA) to decide exactly which fields a user can see or touch. If you are a lowly Editor, you might be allowed to write the bodytext of an article, but absolutely forbidden from touching the hidden flag or the access_group settings. Those are for the adults in the room.
Enter the EditDocumentController. Its job is to render the form for creating or editing records. To be helpful, it accepts a parameter called defVals (Default Values). The idea is innocent enough: if you create a new record, maybe you want to pre-fill the date or a category ID to save time. It's the digital equivalent of a butler saying, "Shall I pre-select the 1982 Bordeaux, sir?"
But here is where things get dark. In cybersecurity, we have a golden rule: Input is the enemy. If you treat user input as trusted system instructions, you are going to have a bad time. The developers of TYPO3 made a classic mistake—they took the user's suggestion for default values and handed it directly to the database engine as a trusted command, effectively letting the user say, "Actually, I'll take the keys to the wine cellar instead."
The Flaw: Bypassing the Bouncer
To understand this exploit, you have to understand the TYPO3 DataHandler. This class is the bouncer. It stands between the HTTP request and the database. When you submit a form, the DataHandler iterates through every field, checks your user group's Access Control List (ACL), and looks at the TCA exclude fields. If you try to submit a value for a field you don't have access to, the DataHandler silently strips it out. Access Denied.
However, the DataHandler has a backdoor for the system itself, a property called $defaultValues. This property is intended for values that the system needs to set automatically—values that shouldn't necessarily trigger permission checks because the system (presumably) knows what it's doing.
The vulnerability lies in how the EditDocumentController connected the two. Before the patch, the controller took the raw $_GET['defVals'] array—controlled entirely by the attacker—and assigned it directly to the $dataHandler->defaultValues property.
[!WARNING] The Logic Gap: The code essentially said: "Here are the values the user submitted (CHECK THESE), and here are the values the user put in
defVals(TRUST THESE BLINDLY)."
Because the DataHandler assumes defaultValues come from a trusted internal source, it applies them to the new record without running the standard checkFieldEditAccess routine. It’s a classic privilege escalation via trusted input channel abuse.
The Code: The Smoking Gun
Let's look at the diff. It's subtle, but it makes all the difference in the world. This is primarily located in EXT:backend/Classes/Controller/EditDocumentController.php.
The Vulnerable Code
Before the fix, the controller simply passed the property along. It didn't care what was inside defVals. It could be innocent data, or it could be a restricted system flag.
// ... inside processRequest or similar logic
// ❌ CRITICAL FAIL: Assigning user input to trusted property
$dataHandler->defaultValues = $this->defVals ?? [];
// Then we start the data processing
$dataHandler->start($dataMap, $cmdMap);
$dataHandler->process_datamap();The Fixed Code
The patch changes the philosophy entirely. Instead of slipping defVals into the trusted defaultValues side door, the patch forces these values into the main $dataMap. This is the "untrusted" bucket. By merging them here, they are forced to walk through the front door—right past the DataHandler bouncer.
// ✅ THE FIX: Merge defVals into the untrusted dataMap
if (is_array($dataMap)) {
foreach ($dataMap as $tableName => $records) {
// Check if we have default values for this table
if (is_array($this->defVals[$tableName] ?? null)) {
foreach ($records as $uid => $_) {
// Only apply to NEW records
if (str_contains((string)$uid, 'NEW')) {
// Merge! Now these values will be subject to
// standard permission checks later in the pipeline.
$dataMap[$tableName][$uid] = array_merge(
$this->defVals[$tableName],
$dataMap[$tableName][$uid]
);
}
}
}
}
}
// The trusted property is no longer used for user input
// $dataHandler->defaultValues = ... (Removed)By moving the data, the developers ensured that if a user tries to set a field they can't access, checkFieldEditAccess will see it in the $dataMap, realize the user is unauthorized, and discard it.
The Exploit: Smuggling Data
Exploiting this requires a valid backend account. You don't need to be an admin; you just need permission to create some record (like a Content Element) and have some fields restricted from you. This is a very common scenario in enterprise TYPO3 setups where editors are locked down tightly.
The Setup:
- Target:
tt_contenttable. - Restricted Field:
subheader(orhidden,starttime,fe_group). Let's say your admin explicitly setexclude=1onsubheaderso you can't touch it. - Goal: Write "HACKED" into the
subheaderfield.
The Attack:
Normally, when you save a record, the POST request sends data like data[tt_content][NEW123][bodytext]=Hello. If you try to send data[tt_content][NEW123][subheader]=HACKED, the backend ignores it because you lack permission.
But, we can abuse the defVals query parameter when opening the creation wizard or submitting the request.
POST /typo3/record/edit?edit[tt_content][NEW123]=new&defVals[tt_content][subheader]=HACKED HTTP/1.1
Host: vulnerable-typo3.com
Cookie: be_typo_user=...
(Standard POST body)The Result:
EditDocumentControllerreadsdefVals.- It sets
$dataHandler->defaultValues['tt_content']['subheader'] = 'HACKED'. DataHandlerprocesses the main data. It checks permissions forbodytext(allowed).DataHandlercreates the SQLINSERTstatement.- It sees the
defaultValuesarray. It assumes these are system mandates. It addssubheader = 'HACKED'to the query. - Record created. Access control bypassed.
The Impact: Why Should We Care?
A CVSS score of 5.3 might make this sound like a "medium" severity snooze-fest, but context is king. In a complex CMS, "Integrity" is everything. This vulnerability allows for horizontal and vertical privilege escalation within the scope of content management.
Scenario 1: Defacement / SEO Poisoning An attacker with limited rights could inject scripts or spam into fields that are normally hidden from them (e.g., raw HTML headers, SEO keywords, or redirects) which the frontend renders blindly because it trusts the CMS data.
Scenario 2: Workflow Bypass
Many TYPO3 installations use the hidden or starttime fields to control publication workflows. A junior editor might draft content, but only a senior editor can "unhide" it. With this exploit, the junior editor can force the hidden=0 flag via defVals during creation, instantly publishing unapproved content to the live site.
Scenario 3: Access Control List Manipulation
If the attacker creates a User Group record (if they have create perms there) and uses defVals to inject specific ACL bits into fields they shouldn't see, they might be able to grant themselves wider access or create backdoors for later use.
It's not a remote root shell, but it creates a chaotic environment where the concept of "Least Privilege" is effectively null and void for record creation.
The Fix: Validation Pipeline Enforcement
The mitigation is straightforward: Update. The patch provided by TYPO3 doesn't just block a specific keyword; it fundamentally refactors the data flow to ensure security consistency.
Remediation Steps:
- Composer Update: Run
composer update typo3/cms-backendimmediately. - Verify Versions: Ensure you are on one of the patched versions:
10.4.55,11.5.49,12.4.41,13.4.23, or14.0.2. - Audit Logs: Check your
sys_logtable for record creations where restricted fields were modified. This is tricky since the logs might just show the record being created, but anomalous data in restricted fields is a red flag.
Developer Lesson:
Never assume that a variable used for "internal logic" (like default values) is safe from external manipulation if there is a direct path from $_GET or $_POST to that variable. Always funnel user input through your most rigorous validation logic, no matter how "helpful" the feature is intended to be.
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:NAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
TYPO3 CMS TYPO3 | >= 10.0.0, <= 10.4.54 | 10.4.55 |
TYPO3 CMS TYPO3 | >= 11.0.0, <= 11.5.48 | 11.5.49 |
TYPO3 CMS TYPO3 | >= 12.0.0, <= 12.4.40 | 12.4.41 |
TYPO3 CMS TYPO3 | >= 13.0.0, <= 13.4.22 | 13.4.23 |
TYPO3 CMS TYPO3 | >= 14.0.0, <= 14.0.1 | 14.0.2 |
| Attribute | Detail |
|---|---|
| Attack Vector | Network (Authenticated) |
| CVSS v4.0 | 5.3 (Medium) |
| CWE | CWE-862 (Missing Authorization) |
| Impact | Integrity Modification / ACL Bypass |
| EPSS Score | 0.00039 |
| Exploit Status | PoC Available |
MITRE ATT&CK Mapping
The software does not perform an authorization check when an actor attempts to access a resource or perform an action.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.