← All breakdowns
SSRFhighLyft

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 report

Lyft'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.

researcher@kali: ~
 

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:

  1. Allowlist outbound destinations - the expense feature should only be permitted to fetch URLs from known receipt-hosting domains, not arbitrary addresses.
  2. 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).
  3. Enforce IMDSv2 on all cloud instances - the token-based metadata service version prevents simple GET-based SSRF from reaching 169.254.169.254.
  4. Perform user-initiated fetches in an isolated network segment with no route to internal services or the metadata endpoint.
  5. 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.254 endpoint 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

Open lesson