You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The RFC2369`List-Unsubscribe` header embeds attacker-controlled URIs that many webmail and mail clients automatically convert into "Unsubscribe"buttons. When those URIs are rendered or fetched without validation, the header becomes an injection point for both stored XSS (if the unsubscribe link is placed in the DOM) and SSRF (if the server performs the unsubscribe request on behalf of the user).
1786
+
1787
+
#### Stored XSS via `javascript:` URIs
1788
+
1789
+
1.**Send yourself an email** where the header points to a `javascript:`URIwhile keeping the rest of the message benign so that spam filters do not drop it.
1790
+
2.**Ensure the UI renders the value** (many clients show it in a "List Info" pane) and check whether the resulting `<a>` tag inherits attacker-controlled attributes such as `href` or `target`.
1791
+
3.**Trigger execution** (e.g., CTRL+click, middle-click, or "open in new tab") when the link uses `target="_blank"`; browsers will evaluate the supplied JavaScript in the origin of the webmail application.
1792
+
4. Observe the stored-XSS primitive: the payload persists with the email and only requires a click to execute.
The newline byte (`%0a`) in the URI shows that even unusual characters survive the rendering pipeline in vulnerable clients such as Horde IMPH5, which will output the string verbatim inside the anchor tag.
1800
+
1801
+
<details>
1802
+
<summary>Minimal SMTP PoC that delivers a malicious List-Unsubscribe header</summary>
with smtplib.SMTP(smtp_server, smtp_port) as smtp:
1825
+
smtp.starttls()
1826
+
smtp.login(smtp_user, smtp_password)
1827
+
smtp.send_message(msg)
1828
+
```
1829
+
1830
+
</details>
1831
+
1832
+
#### Server-side unsubscribe proxies ->SSRF
1833
+
1834
+
Some clients, such as the Nextcloud Mail app, proxy the unsubscribe action server-side: clicking the button instructs the server to fetch the supplied URLitself. That turns the header into an SSRF primitive, especially when administrators set `'allow_local_remote_servers' => true` (documented in [HackerOne report 2902856](https://hackerone.com/reports/2902856)), which allows requests toward loopback and RFC1918 ranges.
1835
+
1836
+
1.**Craft an email** where `List-Unsubscribe` targets an attacker-controlled endpoint (for blind SSRF use Burp Collaborator /OAST).
1837
+
2.**Keep `List-Unsubscribe-Post: List-Unsubscribe=One-Click`** so the UI shows a single-click unsubscribe button.
1838
+
3.**Satisfy trust requirements**: Nextcloud, for example, only performs HTTPS unsubscribe requests when the message passes DKIM, so the attacker must sign the email using a domain they control.
1839
+
4.**Deliver the message to a mailbox processed by the target server** and wait until a user clicks the unsubscribe button.
1840
+
5.**Observe the server-side callback** at the collaborator endpoint, then pivot to internal addresses once the primitive is confirmed.
with smtplib.SMTP(smtp_server, smtp_port) as smtp:
1883
+
smtp.starttls()
1884
+
smtp.login(smtp_user, smtp_password)
1885
+
smtp.send_message(msg)
1886
+
```
1887
+
1888
+
</details>
1889
+
1890
+
**Testing notes**
1891
+
1892
+
- Use an OAST endpoint to collect blind SSRF hits, then adapt the `List-Unsubscribe`URL to target `http://127.0.0.1:PORT`, metadata services, or other internal hosts once the primitive is confirmed.
1893
+
- Because the unsubscribe helper often reuses the same HTTP stack as the application, you inherit its proxy settings, HTTP verbs, and header rewrites, enabling further traversal tricks described in the [SSRF methodology](../ssrf-server-side-request-forgery/README.md).
1894
+
1783
1895
### XSS uploading files (svg)
1784
1896
1785
1897
Upload as an image a file like the following one (from [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)):
@@ -1860,6 +1972,8 @@ other-js-tricks.md
1860
1972
1861
1973
## References
1862
1974
1975
+
- [XSS and SSRF via the List-Unsubscribe SMTP Header in Horde Webmail and Nextcloud Mail](https://security.lauritz-holtmann.de/post/xss-ssrf-list-unsubscribe/)
1976
+
- [HackerOne Report #2902856- Nextcloud Mail List-Unsubscribe SSRF](https://hackerone.com/reports/2902856)
1863
1977
- [From "Low-Impact"RXSS to Credential Stealer:AJS-in-JS Walkthrough](https://r3verii.github.io/bugbounty/2025/08/25/rxss-credential-stealer.html)
0 commit comments