My expense report resulted in an SSRF on Lyft
A receipt/expense feature fetched a user-supplied URL server-side. By pointing it at internal addresses, a researcher turned an innocuous 'upload your receipt' flow into a window onto Lyft's internal network - proving how everyday URL-fetching features become SSRF.
Read the original HackerOne reportLyft's expense and receipt feature handed attackers a direct line into the company's internal network - because the server dutifully fetched whatever URL a user provided, no questions asked.
Stay Legal
This breakdown is for educational purposes and understanding real-world vulnerabilities. Only test techniques like these on systems you own or have explicit written authorization to assess.
The Target
Lyft is a ride-sharing platform that processes large volumes of financial transactions - fares, tips, expense reimbursements. As part of the expense or receipt workflow, the application accepted a user-supplied URL and fetched it server-side to retrieve a resource (such as a receipt image or document). That server-side fetch, performed without validation, was the attack surface.
The Vulnerability
The bug was a Server-Side Request Forgery (SSRF). When the Lyft application server fetched the URL provided by the user, it applied no filtering to block requests targeting private IP ranges, loopback addresses, or cloud metadata endpoints. Because the fetch originated from inside Lyft's own infrastructure, the attacker's machine effectively gained the network privileges of Lyft's backend - able to reach internal services that are not exposed to the public internet at all.
SSRF vulnerabilities in expense and receipt features are a recurring pattern: product teams focus on the business logic (did the URL return a valid file?) and overlook the security implication (what else can that URL reach?). Any endpoint that accepts a URL and fetches it server-side is a potential SSRF vector.
How It Was Found
The researcher identified the expense/receipt URL submission as a server-controlled fetch. The standard SSRF discovery workflow applies: first confirm the server actually makes an outbound request by supplying an out-of-band callback URL (using a service like Burp Collaborator or interact.sh), then pivot to internal targets once the callback is received.
An illustrative request - the researcher would have replaced a legitimate receipt URL with an internal address:
POST /api/v1/expense/receipt HTTP/1.1
Host: api.lyft.com
Authorization: Bearer <user_token>
Content-Type: application/json
{
"receipt_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
}With the SSRF confirmed, the next step was enumerating the internal network: scanning common internal addresses, reaching administrative interfaces (e.g., internal dashboards, service discovery endpoints), and targeting the cloud metadata service to retrieve IAM credentials.
Impact
- The server-side fetch reached internal Lyft network addresses that are entirely inaccessible from the public internet.
- Depending on what the internal network exposed, the researcher could probe internal services, administrative endpoints, and CI/CD infrastructure.
- Access to the cloud metadata service would yield temporary IAM credentials, enabling further lateral movement across Lyft's cloud environment.
- Any internal service that trusted requests from within the Lyft network was potentially reachable without authentication.
In cloud-hosted environments, SSRF is frequently rated critical because internal network access translates directly into credential theft and privilege escalation.
The Fix
Effective SSRF remediation requires defence at multiple layers:
- Allowlist outbound destinations - the expense feature should only be permitted to fetch URLs from known receipt-hosting domains, not arbitrary addresses.
- Resolve and validate the destination IP before making the fetch; reject requests whose resolved IP falls in RFC 1918 ranges (
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16), loopback (127.0.0.0/8), or link-local (169.254.0.0/16). - Enforce IMDSv2 on all cloud instances - the token-based metadata service version prevents simple GET-based SSRF from reaching
169.254.169.254. - Perform user-initiated fetches in an isolated network segment with no route to internal services or the metadata endpoint.
- Apply egress filtering at the network level so application servers cannot reach internal ranges regardless of what the application code does.
What You Can Learn
- Any "fetch from URL" feature is an SSRF candidate. Expense reports, receipt imports, webhook configurations, link previews - wherever users supply a URL that the server fetches, SSRF must be in scope.
- Out-of-band confirmation is the first step. If the response doesn't echo the fetched content, use a callback host to prove the server is making the request before targeting internal addresses.
- Cloud metadata is the highest-value SSRF target. The
169.254.169.254endpoint is reachable only from within the cloud instance, making it an ideal pivot for privilege escalation. - SSRF bypasses perimeter defences entirely. Firewalls that protect internal services from external access do nothing to stop a request that originates from inside the network.
- Allowlists beat denylists. Blocking known-bad IP ranges can be circumverted with DNS rebinding or alternative IP representations; allowing only known-good destinations is fundamentally more robust.
Canonical Report
Full technical details are in the original HackerOne disclosure: HackerOne #885975 - SSRF on Lyft's expense/receipt feature
Learn the skill behind it
Server-Side Request Forgery