- Status Closed
-
Assigned To
cbay - Private
Opened by chimerascope - 04.06.2026
Last edited by cbay - 04.06.2026
FS#343 - SSRF: TYPE_URLS scheduled jobs fetch arbitrary URLs, no egress filtering
In-scope asset: https://api.alwaysdata.com — scheduled jobs (POST /v1/job/, type TYPE_URLS)
Qualifying category: Server-Side Request Forgery (SSRF)
Self-assessed severity: Medium (deferring to your worst-case analysis)
Date of discovery: 2026-06-04 (reported within 24h)
## Compliance note (per your SSRF guidance)
Your rules state: "SSRF — Do not go playing around on any internal networks. Report as soon as you believe that you have a potential SSRF issue." I am following that guidance: I confirmed the server-side request primitive against my own external host, observed that the API accepts internal/link-local target URLs at validation time (no execution required to observe this), and then stopped. I did not explore, enumerate, or pivot into any internal network, accessed no data, and used only two test accounts I registered myself. All test artifacts were deleted afterwards.
## Summary
An authenticated customer can create a TYPE_URLS scheduled task via POST /v1/job/. When it runs, the alwaysdata job-runner performs a server-side HTTP(S) request to the customer-supplied URL:
curl --fail --silent --location --max-redirs 5 '<URL>' > /dev/null
Two issues:
1. No egress filtering — the API accepts URLs targeting loopback (127.0.0.1) and link-local / metadata (169.254.169.254) ranges at validation time (HTTP 201), instead of rejecting them.
2. Redirects are followed (–location –max-redirs 5), so an allowed public URL can redirect the server-side request toward an internal destination.
The runner executes on shared infrastructure separate from the customer's own sandbox. Response bodies are discarded (> /dev/null), so this is a blind SSRF. I am reporting the primitive per your guidance rather than demonstrating internal impact.
## Steps to reproduce (standard Linux tools; own test accounts)
1) Confirm server-side fetch (against my own external host only):
curl -s --basic --user "$APIKEY account=$ACCOUNT:" \
-X POST -H 'Content-Type: application/json' \
-d '{"type":"TYPE_URLS","argument":"https://$YOUR_HOST/probe","date_type":"FREQUENCY","frequency":1,"frequency_period":"minute"}' \
https://api.alwaysdata.com/v1/job/
Within ~1 minute my external host received an inbound GET from alwaysdata infrastructure, User-Agent: curl/7.88.1. This confirms the request is performed server-side by alwaysdata, not from my browser.
2) Show that internal/link-local targets are NOT rejected at validation (no execution needed):
curl -s -o /dev/null -w '%{http_code}\n' --basic --user "$APIKEY account=$ACCOUNT:" \
-X POST -H 'Content-Type: application/json' \
-d '{"type":"TYPE_URLS","argument":"http://169.254.169.254/","date_type":"DAILY","daily_time":"23:59"}' \
https://api.alwaysdata.com/v1/job/
⇒ 201 Created. Same for http://127.0.0.1/. Only URL syntax is validated (//host and file:// are rejected as malformed), but the destination address range is not checked.
The execution command (curl –fail –silent –location –max-redirs 5 '<URL>' > /dev/null) is visible in the account's own job log at ~/admin/logs/jobs/<id>-<date>.log, which also records the curl exit code. I observed this for my own jobs only; I did not use it to probe internal services.
## Impact
An authenticated user can cause alwaysdata infrastructure to issue server-side HTTP(S) requests to arbitrary destinations, including internal/loopback/link-local ranges that the API does not filter, with redirects followed. This is a classic SSRF primitive originating from shared infrastructure.
Stated limitations (no overclaim): the SSRF is blind (response body discarded); I did not retrieve any response content, did not access any data, and did not explore internal networks. No metadata credential access is claimed. Per your policy, I leave the worst-case severity assessment to your analysts.
## Security recommendation
- Reject loopback, private (RFC1918), link-local (169.254.0.0/16) and metadata address ranges before executing TYPE_URLS jobs.
- Re-validate the destination after DNS resolution and after each redirect, not only the initial URL (or disable redirects / restrict to public ranges).
- Apply egress filtering at the job-runner network layer so user-controlled fetches cannot reach internal or restricted destinations.
## Scope / safety statement
- Two test accounts I registered myself; no other users involved.
- Server-side fetch confirmed against my own external host only.
- Internal/link-local URLs were only shown to pass API validation; I did not explore internal networks, accessed no data, and did not pivot.
- No automated scanners. Minimal manual requests. All test jobs and resources deleted after testing.
## Duplicate check (performed against the live public tracker)
No existing report covers the TYPE_URLS scheduled-job feature on /v1/job/ or its absent egress filtering. The nearest SSRF/job reports are different:
- FS#307 — SSRF in webmail.alwaysdata.com (third-party Roundcube). Different component.
- FS#327 — claimed email bounce webhook SSRF. Different (and that feature does not exist).
- FS#320 — claimed cron timing oracle on a non-existent /api/v1/cron/ endpoint. Different class.
This report concerns the concrete POST /v1/job/ TYPE_URLS behavior, with observed server-side curl execution and out-of-band confirmation — empirically verified, not speculative.
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
Hello,
None of those are issues. Our customers have an unrestricted SSH access anyway, so they can simply run their own curl command if they want.
Kind regards,
Cyril
Hello Cyril,
Thank you for the quick review.
I understand the point regarding unrestricted SSH access. The reason I reported this was not simply that curl can be executed, but that the TYPE_URLS job appeared to run from a scheduled job-runner context that was separate from my customer SSH session.
In my test, my SSH session was on ssh1 / 2a00:b6e0:1:50:2::1, while the TYPE_URLS job egress I observed was from 2a00:b6e0:1:52:4::1. That made me treat the scheduled job-runner as a potentially separate network/security boundary from the customer SSH sandbox.
I did not retrieve response bodies, access data, or explore internal networks. I reported early as requested by your SSRF guidance.
If the scheduled job-runner has no additional internal reachability or trust compared to what the same customer already has via unrestricted SSH, then I understand your position and am fine with closing this as accepted risk / not applicable.
Kind regards,
BJ
Exactly: jobs are executed from another server, but in the exact same context/permissions as the SSH server.
Understood — thank you for confirming. Agreed, closing as accepted risk / not applicable. I appreciate the quick and clear responses.
Kind regards,
BJ