CDN 403s any query containing localhost/127.0.0.1, which blocks the documented custom-agent local-testing flow
The CDN in front of sphere.unicity.network answers 403 for any request whose query string contains localhost or 127.0.0.1, before the wallet sees it. That blocks the documented way to test a local dApp against the hosted wallet.
Measured (curl, 2026-09-17)
| Request | Status |
|---|---|
GET / |
200 |
GET /connect |
200 |
GET /connect?origin=https%3A%2F%2Fexample.com |
200 |
GET /agents/custom?url=https%3A%2F%2Ffoo.ngrok.app |
200 |
GET /connect?origin=http%3A%2F%2Flocalhost%3A5174 |
403 |
GET /connect?origin=https%3A%2F%2F127.0.0.1%3A5174 |
403 |
GET /agents/custom?url=http%3A%2F%2Flocalhost%3A5174 |
403 |
GET /agents/custom?url=https%3A%2F%2Flocalhost%3A5174 |
403 |
The 403 body is CloudFront's ERROR: The request could not be satisfied, so it is served at the edge. It reproduces with and without browser-like User-Agent / Accept headers, and on every route tried, so it looks like a WAF rule matching the literal strings rather than anything route-specific.
Why it matters
Our docs tell a developer to open https://sphere.unicity.network/agents/custom?url=<their dApp> to run a local dApp inside the wallet. With a localhost URL that request never reaches the app. The developer sees a generic 403 page with no hint about what to change.
A second, independent gate exists in the app: src/components/desktop/DesktopLayout.tsx:80 frames a custom tab only when isHttpsUrl(url) (protocol-only check, added 2026-07-30 in 5f7420f1). So even without the WAF rule, a plain-http local dApp would not be framed.
Questions for whoever owns the CloudFront/WAF config
- Is the
localhost/127.0.0.1rule intentional? If it is a generic managed rule, what does it protect here, given the value is only ever read client-side bysearchParams.get('url')? - If it can be relaxed for
/agents/custom(and/connect), a developer could point the wallet athttps://localhost:PORTdirectly and the https gate alone would be the contract.
Current state of the docs
Until this is decided, the docs now tell developers to serve the dApp over https on a publicly reachable host (an https tunnel is verified reachable: ?url=https%3A%2F%2Ffoo.ngrok.app answers 200). Updated in: sphere-sdk#791, sphere#524, sphere-dev-portal#49, sphere-sdk-connect-example#28 and unicity-claude-marketplace#15.
One path is documented but untested: typing an https URL into the wallet's in-app "Load Custom URL" prompt. It navigates client-side, so no document request carries the query string to the CDN — but a page reload on the resulting URL would, and nobody has run it end to end.
Not investigated here: whether the same rule affects other query parameters or other hosts in the stack.
Source: unicity-sphere/sphere