---
title: Server-side request forgery risk
description: >-
  Investigates server-side requests whose destinations may be controlled by
  request input.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/security/app-security-checks/ssrf-request-forgery
  md: >-
    https://shopify.dev/docs/apps/build/security/app-security-checks/ssrf-request-forgery.md
---

# Server-side request forgery risk

Investigates server-side requests whose destinations may be controlled by request input.

| Detail | Value |
| - | - |
| Check ID | `SSRF_REQUEST_FORGERY` |
| Severity | High |
| How it runs | Agent review |

***

## Vulnerable example

## app/routes/app.import.tsx

```tsx
import type { ActionFunctionArgs } from "react-router";


import { authenticate } from "../shopify.server";


export const action = async ({ request }: ActionFunctionArgs) => {
  await authenticate.admin(request);


  const feedUrl = String((await request.formData()).get("feedUrl"));


  // The server will fetch whatever it is given, including
  // localhost, private ranges, and the cloud metadata endpoint.
  return { feed: await (await fetch(feedUrl)).json() };
};
```

***

## How to fix

Allowlist destinations and reject private, local, and unsafe network targets.

## app/routes/app.import.tsx

```tsx
import type { ActionFunctionArgs } from "react-router";


import { authenticate } from "../shopify.server";


const ALLOWED_HOSTS = new Set(["feeds.example-partner.com"]);


export const action = async ({ request }: ActionFunctionArgs) => {
  await authenticate.admin(request);


  const formData = await request.formData();
  const feedUrl = new URL(String(formData.get("feedUrl")));


  // Allowlist scheme and host, and re-check after redirects: a 302
  // to 169.254.169.254 defeats a check made only on the first URL.
  if (
    feedUrl.protocol !== "https:" ||
    !ALLOWED_HOSTS.has(feedUrl.hostname)
  ) {
    throw new Response("Unsupported feed host", { status: 400 });
  }


  const response = await fetch(feedUrl, { redirect: "error" });


  return { feed: await response.json() };
};
```

***

## Related

* [`shopify app security check`](https://shopify.dev/docs/api/shopify-cli/app/app-security-check), the command that runs this check
* [All app security checks](https://shopify.dev/docs/apps/build/security/app-security-checks)

***
