---
title: Request input selects Admin API shop context
description: >-
  Detects request-derived shop values passed into `unauthenticated.admin(...)`,
  allowing callers to select another shop's Admin API context.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/security/app-security-checks/request-controlled-admin-context
  md: >-
    https://shopify.dev/docs/apps/build/security/app-security-checks/request-controlled-admin-context.md
---

# Request input selects Admin API shop context

Detects request-derived shop values passed into `unauthenticated.admin(...)`, allowing callers to select another shop's Admin API context.

| Detail | Value |
| - | - |
| Check ID | `REQUEST_CONTROLLED_ADMIN_CONTEXT` |
| Severity | High |
| How it runs | Deterministic scan and agent review |

***

## Vulnerable example

## app/routes/app.sync.tsx

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


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


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


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


  // Authenticating and then handing a request value to
  // unauthenticated.admin lets the caller pick which shop's Admin
  // API context they get.
  const { admin } = await unauthenticated.admin(requestedShop);


  const response = await admin.graphql(
    `{ products(first: 10) { nodes { id } } }`,
  );
  const { data } = await response.json();


  return { products: data.products.nodes };
};
```

***

## How to fix

Use the Admin API context returned by `authenticate.admin(request)`. Never pass form, JSON, query, or route input into `unauthenticated.admin(...)`.

For more detail, see [Online access tokens](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens#online-access-tokens).

## app/routes/app.sync.tsx

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


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


export const action = async ({ request }: ActionFunctionArgs) => {
  // The Admin context comes back bound to the authenticated
  // session's shop, so no request value can redirect it.
  const { admin } = await authenticate.admin(request);


  const response = await admin.graphql(
    `{ products(first: 10) { nodes { id } } }`,
  );
  const { data } = await response.json();


  return { products: data.products.nodes };
};
```

***

## 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)

***
