惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
S
Secure Thoughts
Attack and Defense Labs
Attack and Defense Labs
人人都是产品经理
人人都是产品经理
Stack Overflow Blog
Stack Overflow Blog
W
WeLiveSecurity
O
OpenAI News
SecWiki News
SecWiki News
博客园 - Franky
NISL@THU
NISL@THU
Microsoft Azure Blog
Microsoft Azure Blog
T
Tor Project blog
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
Security Latest
Security Latest
H
Hacker News: Front Page
Google Online Security Blog
Google Online Security Blog
P
Privacy & Cybersecurity Law Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
D
Darknet – Hacking Tools, Hacker News & Cyber Security
月光博客
月光博客
李成银的技术随笔
Spread Privacy
Spread Privacy
F
Full Disclosure
F
Fortinet All Blogs
T
The Exploit Database - CXSecurity.com
Vercel News
Vercel News
AWS News Blog
AWS News Blog
WordPress大学
WordPress大学
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
V
Visual Studio Blog
J
Java Code Geeks
博客园 - 三生石上(FineUI控件)
G
Google Developers Blog
云风的 BLOG
云风的 BLOG
博客园 - 司徒正美
Engineering at Meta
Engineering at Meta
Last Week in AI
Last Week in AI
P
Palo Alto Networks Blog
宝玉的分享
宝玉的分享
T
True Tiger Recordings
N
News and Events Feed by Topic
酷 壳 – CoolShell
酷 壳 – CoolShell
Cisco Talos Blog
Cisco Talos Blog
N
News | PayPal Newsroom
S
SegmentFault 最新的问题
Jina AI
Jina AI

Aikido Security's Blog

Google API keys keep working after you delete them The Wild West of VS Code extensions and how a poisoned extension breached GitHub GitHub breached via a malicious VS Code extension: why developer devices are the real target Microsoft's durabletask package on PyPi Compromised. Mini Shai Hulud attacks again... again! Supply Chain Security: The Ultimate Guide to Software Composition Analysis (SCA) Tools Cloud Security Architecture: Principles, Frameworks, and Best Practices Cloud Security for DevOps: Securing CI/CD and IaC Compliance in the Cloud: Frameworks You Can’t Ignore Using Generative AI for Pentesting: What It Can (and Can’t) Do Top Cloud Security Tools for Modern Teams Top 8 Checkmarx Alternatives for SAST and Application Security Mini Shai-Hulud strikes again: npm worm compromises hundreds of @antv packages The Top 6 Best AI Tools for Coding in 2025 Top XBOW Alternatives In 2026 Top SonarQube Alternatives in 2025 Top 7 CodeRabbit Alternatives for AI Code Review in 2026 Best Orca Security Alternatives for Cloud & CNAPP Security 2026 Top 6 Wiz.io Alternatives for Cloud & Application Security in 2026 Top DevSecOps Tools to Replace GitLab Ultimate’s Security Features Top 5 GitHub Advanced Security Alternatives for DevSecOps Teams in 2026 Best 6 Veracode Alternatives for Application Security (Dev-First Tools to Consider) Top 10 Software Composition Analysis (SCA) tools in 2026 Top 10 AI-powered SAST tools in 2026 Top 12 Dynamic Application Security Testing (DAST) Tools in 2026 Penetration testing vs. red teaming: what’s the difference? Pentest GPT: How LLMs Are Reshaping Penetration Testing One year of Opengrep: What we built and what’s next Shadow AI is a fear response, and banning it makes it worse Mini Shai-Hulud Is Back: npm Worm Hits over 160 Packages, including Mistral and Tanstack Security Checklist for GitHub Actions Coinbase's layoffs signal a dangerous move into a vibe-coding security mess Securing Legacy Dependencies with Aikido and TuxCare Top OWASP scanners in 2026 for web application security Rolling out developer security in a 5,000+ engineer organization Security metamorphosis: a Mythos-ready architecture checklist for autonomous AI attacks Why browser extensions are a major security risk and what you can do about it Popular PyTorch Lightning Package Compromised by Mini Shai-Hulud Aikido integrates with AWS Kiro: Catching in review doesn't scale anymore Top CVE scanners in 2026 to identify known vulnerabilities A practical CTO security checklist to be Mythos-ready Mini Shai-Hulud Targets SAP npm Packages With a Bun-Based Secret Stealer Someone published four versions of a fake "tanstack" package in 27 minutes to steal your .env files It's time to treat browser extensions like supply chain attack vectors Introducing Safe Chain: Stopping Malicious npm Packages Before They Wreck Your Project What is a CVE? Is Shai-Hulud Back? Compromised Bitwarden CLI Contains a Self-Propagating npm Worm GPT-Proxy Backdoor in npm and PyPI turns Servers into Chinese LLM Relays Introducing Endpoint Protection: Security for Developer Devices Multiple Cross-Site Scripting (XSS) Vulnerabilities in Mailcow Reliable CVE sources in the age of NIST NVD cutbacks Ship Fast, Stay Secure: Better Alternatives to Jit.io Axios CVE-2026-40175: a critical bug that’s… not exploitable Bug bounty isn’t dead, but the old model is breaking GlassWorm goes native: New Zig dropper infects every IDE on your machine Aikido Attack finds multiple 0-days in Hoppscotch The cybersecurity doomerism around Mythos doesn't match what we see on the ground Top Vibe Coding Tools for a Seamless Workflow in 2026 Top Software Security Testing Tools Top Security Monitoring Tools Top Runtime Security Tools Top IAST Tools For Interactive Application Security Testing Top GCP Security Tools For Safeguarding Google Cloud Top Docker Security Tools Top Azure Security Tools Top AI Coding Assistants Top AI Code Generators Top 8 AWS Security Tools in 2026 Top 12 ASPM Tools in 2026 Top Secret Scanning Tools Top 12 Software Supply Chain Security Tools in 2026 axios compromised on npm: maintainer account hijacked, RAT deployed Popular telnyx package compromised on PyPI by TeamPCP Top RSAC 2026 Parties, Side-Events & Security Meetups Aikido × Lovable: Vibe, Fix, Ship CanisterWorm Gets Teeth: TeamPCP's Kubernetes Wiper Targets Iran TeamPCP deploys CanisterWorm on NPM following Trivy compromise Security testing is validating software that no longer exists Aikido Recognized by Frost & Sullivan with the 2026 Customer Value Leadership Award in ASPM GlassWorm Hides a RAT Inside a Malicious Chrome Extension fast-draft Open VSX Extension Compromised by BlokTrooper npm debug and chalk packages compromised Best 6 AI Pentesting Tools in 2026 Top 9 Best AI Code Review Tools in 2026 The 6 Best Code Quality Tools for 2026 Top 18 Automated Pentesting Tools Every DevSecOps Team Should Know Glassworm Strikes Popular React Native Phone Number Packages Glassworm Is Back: A New Wave of Invisible Unicode Attacks Hits Hundreds of Repositories How Security Teams Fight Back Against AI-Powered Hackers Introducing Betterleaks, an open source secrets scanner by the author of Gitleaks Trump’s 2026 cybersecurity strategy: From compliance to consequence How does AI pentesting work with compliance? What continuous pentesting actually requires Rare Not Random: Using Token Efficiency for Secrets Scanning Persistent XSS/RCE using WebSockets in Storybook’s dev server Why Determinism Is Still a Necessity in Security WAF vs. RASP vs. ADR Introducing Aikido Infinite: A new model of self-securing software How Aikido secures AI pentesting agents by design Astro Full-Read SSRF via Host Header Injection How to Get Your Board to Care About Security (Before a Breach Forces the Issue)
Roundcube XSS chained with cookie tossing for full inbox access
2026-04-22 · via Aikido Security's Blog

Roundcube is the most widely deployed open-source webmail client in the world. We recently found a dangerous vulnerability in the application! It’s a stored XSS that, chained with a cookie tossing technique, gives an attacker full access to a victim's inbox and, from there, any account that uses that email address for authentication or password recovery.

We discovered this by running our AI pentesting agents against a local Roundcube instance. All findings were reported responsibly to Nextcloud, the maintainers of Roundcube, via HackerOne (XSS disclosed at #3594137) and patched in version 1.6.14. 

In this piece, we'll go through what we did, how our agents found the vulnerability, and how a simple HTML injection could fully compromise a user's inbox.

The injection point

Every attack has a starting point. Let’s look at one that one of our agents picked up to audit.

Roundcube handles user-controlled content in a few different ways. Email bodies are the most scrutinized surface. These are heavily sanitized because they are displayed inline with the rest of the application.

HTML attachments are rendered via a separate endpoint in mail/get.php, with a Content Security Policy set to script-src 'none' to block JavaScript execution.

A third, more hidden endpoint handles inline attachments that have yet to be sent, temporarily viewable while composing an email. This is the endpoint we’ll be looking at. The display-attachment action handles this kind of requests:

class rcmail_action_mail_attachment_display extends rcmail_action_mail_attachment_upload {
    ...
    public function run($args = []) {
        self::init();

        $rcmail = rcmail::get_instance();
        $file = $rcmail->get_uploaded_file(self::$file_id);

        self::display_uploaded_file($file);

The function self::display_uploaded_file() is where the magic happens. As rcube_uploads.php shows, these kinds of attachments are returned directly with their original content type and body, with no sanitization, sandboxing and no Content Security Policy applied.

header('Content-Type: ' . $file['mimetype']);
header('Content-Length: ' . $file['size']);

if (isset($file['data']) && is_string($file['data'])) {
    echo $file['data'];
} elseif (!empty($file['path'])) {
    readfile($file['path']);
}

How do we reach this endpoint, you may ask? While composing a new email inside Roundcube, you can attach a file to the temporary email, specifically an HTML file. We'll give it some malicious content:

<script>alert(origin)</script>

After uploading, clicking the attachment opens a pop-up that renders it using the get action, protected by a strong CSP. This is the safe path. The interesting part is what happens when you swap _action=get for _action=display-attachment:

Screenshot of Roundcube's compose window with an attached xss.html file. A popup shows the attachment rendered via the get action, with a blank white area where the script would execute, blocked by the Content Security Policy.

Viewing the attachment via the get action renders it in a sandboxed popup with a strong CSP, blocking script execution.

Take the original URL for this display:

/?_task=mail&_frame=1&_file=rcmfile21774532162043767100&_id=193102765369c53621200f8&_action=get&_extwin=1

Swapping _action=get for _action=display-attachment and dropping some unnecessary parameters gives you:

/?_task=mail&_file=rcmfile21774532162043767100&_id=193102765369c53621200f8&_action=display-attachment

This URL renders the same content, but without the CSP! So, the JavaScript inside our HTML executes, alerting the current origin and confirming XSS:

Screenshot shows pop-up with the attack, with the text "mail.target.local:19002 says http://mail.target.local:19002"

The attack works!

This is an interesting Self-XSS, but is this really a problem? If we're being realistic, a regular user isn't going to upload our XSS payload by themselves and continue to view it in this special way…

Looking at attachment_upload.php, you'll find that a compose_data_ session key must be set for your current user, and only that user can retrieve the attachment.

public static function init()
{
    self::$COMPOSE_ID = rcube_utils::get_input_string('_id', rcube_utils::INPUT_GPC);
    self::$COMPOSE = null;
    self::$SESSION_KEY = 'compose_data_' . self::$COMPOSE_ID;

    if (self::$COMPOSE_ID && !empty($_SESSION[self::$SESSION_KEY])) {
        self::$COMPOSE = &$_SESSION[self::$SESSION_KEY];
    }

    if (!self::$COMPOSE) {
        exit('Invalid session var!');

Since this is a temporary attachment tied to your current session only, there's no way to prepare a payload and have a victim trigger it by logging into the attacker's account, as we saw with Mailcow. The attacker's entire roundcube_sessid cookie would need to be copied over to the victim. Another impossible-sounding task.

Exploiting Self-XSS with Cookie Tossing

The Self-XSS we found looks unexploitable at first glance. The attachment is session-bound, so there's no way to prepare a payload for a victim without also handing them the attacker's session cookie. But the trouble actually isn’t over yet. That's where cookie tossing comes in.

In browsers, cookies have some interesting quirks, one of which is the Domain=attribute.

> Only the current domain can be set as the value, or a domain of a higher order, unless it is a public suffix. Setting the domain will make the cookie available to it, as well as to all its subdomains.

Cookies can be set not just for the current domain, but for a parent domain as well. A cookie set by sub.example.com with Domain=example.com becomes available to every subdomain under example.com, including ones like other.example.com that had nothing to do with setting it. This attack type is called Cookie Tossing, where one subdomain writes cookies that another subdomain will read.

This means all we need to exploit our vulnerability is control over a subdomain on the same domain as the target Roundcube domain. From there, a separate XSS vulnerability on something like xss.target.local can set the document.cookie property to write cookies with the Domain=target.local attribute. Once those cookies are set, the victim's browser will send them along to mail.target.local, where Roundcube loads the attacker's session instead of the victim's.

That session has the malicious HTML attachment ready and waiting. Navigating the victim to the attachment URL triggers the XSS payload inside Roundcube's origin, on the victim's browser, with no further interaction required.

In summary, what an attacker has to do to exploit it is:

  1. Log in to their own account, create a new email, and attach a malicious HTML file
  2. Copy the link to view (render) the attachment and the cookies
  3. From a subdomain vulnerable to XSS, set the cookie values using document.cookie with the Domain=attribute pointing to the target domain.
  4. Redirect the victim to the attachment link. The XSS triggers in the Roundcube origin.

Here's what the subdomain XSS payload looks like in practice, setting the session cookies and redirecting the victim to the attachment URL

document.cookie='roundcube_sessid=1798cbb4c1d7c7f9ca26069b52aac1aa; Domain=target.local'
document.cookie='roundcube_sessauth=GfNmiyX5brPm4l814QUx62l5gsJKBXfU-1773063000; Domain=target.local'
location.href = 'http://mail.target.local/?_task=mail&_action=display-attachment&_id=183727919869aecb6499f76&_file=rcmfile11773063013009066400';

From the subdomain XSS, the rest of the Roundcube exploit requires no further user interaction. All the security of Roundcube now relies on every same-site subdomain.

Screenshot of the local instance and the pop up, which is from the attack code

The alert popup in the screenshot above confirms XSS is executing on Roundcube's origin, but it doesn't demonstrate real impact on its own. There's still a problem. At this point we've loaded the attacker's session into the victim's browser, so any action taken will be on the attacker's account rather than the victim's. Great to deliver our payload, not so great for accessing things we wouldn't normally be able to.

If you look at the browser, cookies don't actually get replaced when we set a different Domain=. They're both sent!

Cookie: roundcube_sessauth=VICTIM; roundcube_sessauth=ATTACKER

When both cookies are present, the server picks the attacker's, since it appears last in the header. On the XSS payload, we want the attacker's cookies to be picked, while on all other endpoints afterward, we want the victim's cookies. Luckily, cookies have another attribute that perfectly solves this problem: Path=.

By setting a unique path like Path=/index.php/xss, which still points to the homepage, the cookies will only be sent when that path matches the request target. So for our requests:

  1. /index.php/xss sends roundcube_sessauth=VICTIM; roundcube_sessauth=ATTACKER -> attacker's payload is returned
  2. / sends roundcube_sessauth=VICTIM -> victim's emails are returned

We just have to change the JavaScript exploit to set this new attribute, and navigate to /index.php/xss afterward to ensure the attacker's cookies are sent in this request for our payload, but after that our XSS is free to access the victim's account.

document.cookie='roundcube_sessid=1798cbb4c1d7c7f9ca26069b52aac1aa; Domain=target.local; Path=/index.php/xss'
document.cookie='roundcube_sessauth=GfNmiyX5brPm4l814QUx62l5gsJKBXfU-1773063000; Domain=target.local; Path=/index.php/xss'
location.href = 'http://mail.target.local/index.php/xss?_task=mail&_action=display-attachment&_id=183727919869aecb6499f76&_file=rcmfile11773063013009066400';

In the DevTools, we can see how the duplicate cookies are set up now:

Screenshot of Chrome DevTools Application tab showing four cookies for mail.target.local. Two are scoped to the path /index.php/xss on .target.local (the attacker's cookies), and two are scoped to the root path on mail.target.local (the victim's cookies).

While the conditions required to exploit this (account on Roundcube + Subdomain XSS) are a little tricky, the potential impact of a successful exploit is huge.

Email is the most widely trusted form of authentication, as many websites rely on "magic links" for sign-in or password recovery. When an attacker has access to your emails, they can trigger these kinds of password resets on all websites you have the email connected to. Then, they can read the email that this service sends to confirm and gain access to many more accounts.

Remediation

Update Roundcube to version 1.6.14 or later (1.6.x), or 1.5.14 or later (1.5.x LTS). All reported vulnerabilities are patched in this release. If you use Aikido, vulnerable Roundcube instances are automatically flagged in your surface monitoring feed as a medium finding.

Not on Aikido yet? Create a free account to get started, no credit card required.

Conclusion

While initially looking like a trivial XSS vulnerability, exploiting this required a bit more knowledge of cookies and sessions. Same-site subdomains are often given slightly more permissions than completely separate websites by the browser, another reason to ensure all your assets are secure.

This is a hard task, but as shown here, Aikido Attack can autonomously pentest web applications to find such vulnerabilities across your entire infrastructure.

The maintainers of Roundcube patched this vulnerability in version 1.6.14 by adding a script-src 'none' Content Security Policy, just like the rest of the attachments already had. This makes it impossible to execute JavaScript when returning arbitrary HTML.

Bonus: IMAP CRLF Injection via CSRF

During the same pentest, another agent found a second vulnerability that we found particularly interesting. After reporting this, it ended up being a duplicate that the Martila Security Research Team also found. Still, we found it interesting enough to briefly explain the details of this vulnerability here.

The /?_task=mail&_action=search endpoint passes the client-supplied _filter parameter directly into the IMAP SEARCH command in rcube_imap_generic.php:

if (!empty($criteria)) {
    $params .= ($params ? ' ' : '') . $criteria;
} else {
    $params .= 'ALL';
}
[$code, $response] = $this->execute($return_uid ? 'UID SEARCH' : 'SEARCH', [$params]);

While the function seems to separate the command from its arguments, the implementation of execute() simply concatenates them without sanitization:

foreach ($arguments as $arg) {
    $query .= ' ' . self::r_implode($arg);
}

By injecting a Carriage Return & Line Feed (CRLF, %0D%0A) characters, an attacker can break out of the SEARCH parameters and inject additional IMAP commands within the authenticated user's IMAP session.

With this, you can not only search emails but also add folders, move emails, or delete the entire inbox, since these are all raw IMAP commands.

Below is an example filter set to ALL%0D%0AX007%20CREATE%20EvilFolder:

http://mail.target.tld/?_task=mail&_action=search&_interval=&_q=imap-inject-test&_headers=subject%2Cfrom&_layout=widescreen&_filter=ALL%0D%0AX007%20CREATE%20EvilFolder&_scope=base&_mbox=INBOX&_remote=1 

Visiting it sends the following data to IMAP, with the injected CREATE command that executes after the search:

X006 SEARCH ALL
X007 CREATE EvilFolder

The effect of this can then be seen in the Roundcube UI:

The Roundcube UI on the Folders tab, with "EvilFolder" at the bottom

Because this is a simple GET request, visiting the above link is all that's needed to execute the commands. With it, a single click of a link could permanently delete all emails (X001 UID STORE 1:* FLAGS \Deleted followed by X002 EXPUNGE), resulting in a big loss of data.

This vulnerability is now patched by removing \r\n characters from search queries.