> For the complete documentation index, see [llms.txt](https://docs.roboflow.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.roboflow.com/deployment/self-hosted/inference-server/configuration/input-formats.md).

# Accepted Input Formats

Input formats accepted by a self-hosted Roboflow Inference server, and how to disable the less secure ones such as pickled numpy payloads and URL image fetching.

## Why this matters

The Inference server is designed to be straightforward to integrate, which is why some convenient but potentially less secure data loading methods are available. For production deployments, configuration options let you disable those behaviors.

This page explains how to configure the server to either harden it or enable more flexible behavior, depending on your needs.

## Deserialization of pickled numpy objects

One way to send requests to the Inference server is with serialized numpy objects:

```python
import cv2
import pickle
import requests

image = cv2.imread("...")
img_str = pickle.dumps(image)

infer_payload = {
    "model_id": "{project_id}/{model_version}",
    "image": {
        "type": "numpy",
        "value": img_str,
    },
}

res = requests.post(
    "http://localhost:9001/infer/{task}",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json=infer_payload,
)
```

Starting with version `v0.14.0`, deserialization of this payload type is disabled by default. You can enable it by setting `ALLOW_NUMPY_INPUT=True`. See the [Inference CLI](https://docs.roboflow.com/reference/inference/inference-cli/server) docs for how to run the server with that flag. This option is not available in Roboflow's hosted APIs.

{% hint style="warning" %}
Do not enable this option in production if the server is open to requests from the open internet, or is not locked down to accept only authenticated requests from your workspace's API key.
{% endhint %}

## Sending URLs to inference images

Fetching images from URLs is convenient, but it can expose the server to [server-side request forgery (SSRF) attacks](https://en.wikipedia.org/wiki/Server-side_request_forgery):

```python
import requests

infer_payload = {
    "model_id": "{project_id}/{model_version}",
    "image": {
        "type": "url",
        "value": "https://some.com/image.jpg",
    },
}

res = requests.post(
    "http://localhost:9001/infer/{task}",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json=infer_payload,
)
```

Inference can load images straight from a URL supplied in the request (`{"image": {"type": "url", "value": "https://..."}}`). Any time a server fetches a URL that a caller controls, the caller can try to steer it into making requests on their behalf, a class of attack called server-side request forgery (SSRF). Someone who cannot reach your internal network directly can ask your server to fetch, for example:

* `http://169.254.169.254/latest/meta-data/`, the cloud metadata service (AWS, GCP, Azure), which can hand back instance credentials.
* `http://127.0.0.1:9001/...` and other localhost services: admin panels, databases, or the Inference server's own unauthenticated endpoints.
* `http://10.0.0.5/`, `http://192.168.1.1/`, and other private (RFC1918), link-local, CGNAT, or IPv6 ULA hosts that sit behind your perimeter.

A public-looking hostname is not proof of a public target: it may resolve to a private IP, redirect to one, or use DNS rebinding (resolve to a public IP for the validation check, then a private IP for the actual connection). Inference ships controls for all of these.

### Turn URL input off if you don't need it

The strongest control is to not accept URL images at all. If your clients always send images as base64 or file uploads, disable URL fetching outright:

```bash
docker run --rm -p 127.0.0.1:9001:9001 \
  -e ALLOW_URL_INPUT=false \
  roboflow/roboflow-inference-server-cpu:latest
```

### Harden URL input when you do need it

When URL images are required, these flags narrow what the server is allowed to fetch. Together they reject internal targets, pin the connection to the validated IP (defeating DNS rebinding), and re-check every redirect hop.

<table data-search="false"><thead><tr><th>Variable</th><th>Default</th><th>Effect</th></tr></thead><tbody><tr><td>ALLOW_URL_INPUT</td><td>True</td><td>Master switch for URL image input. False rejects all URL images.</td></tr><tr><td>ALLOW_LOADING_IMAGES_FROM_LOCAL_FILESYSTEM</td><td>True</td><td>Set to False to disable local filesystem image loading.</td></tr><tr><td>ALLOW_URL_TO_NON_GLOBAL_ADDRESSES</td><td>True</td><td>When False, a URL whose host resolves to a non-global address (loopback, private, link-local/metadata, CGNAT, IPv6 ULA, and so on) is rejected, and the connection is pinned to the validated IP so a second DNS answer cannot swap the target.</td></tr><tr><td>VALIDATE_IMAGE_URL_REDIRECTS</td><td>False</td><td>When True, redirects are followed one hop at a time and each hop URL is re-validated, instead of being followed blindly.</td></tr><tr><td>MAX_IMAGE_URL_REDIRECTS</td><td>30</td><td>Hard cap on redirect hops, enforced regardless of the flag above.</td></tr><tr><td>ALLOW_NON_HTTPS_URL_INPUT</td><td>False</td><td>When False, only https:// URLs are accepted.</td></tr><tr><td>ALLOW_URL_INPUT_WITHOUT_FQDN</td><td>False</td><td>When False, URLs whose host is a bare IP or has no public suffix are rejected, so callers must use a real domain name.</td></tr><tr><td>WHITELISTED_DESTINATIONS_FOR_URL_INPUT</td><td>unset</td><td>Comma-separated allow-list of destinations (subdomain.domain.suffix). When set, only these are permitted.</td></tr><tr><td>BLACKLISTED_DESTINATIONS_FOR_URL_INPUT</td><td>unset</td><td>Comma-separated block-list of destinations that are always rejected.</td></tr></tbody></table>

A hardened configuration that still allows public HTTPS image URLs:

```bash
docker run --rm -p 127.0.0.1:9001:9001 \
  -e ALLOW_URL_TO_NON_GLOBAL_ADDRESSES=false \
  -e VALIDATE_IMAGE_URL_REDIRECTS=true \
  roboflow/roboflow-inference-server-cpu:latest
```

For the tightest control, add an allow-list so the server can only reach the exact hosts you serve images from:

```bash
docker run --rm -p 127.0.0.1:9001:9001 \
  -e ALLOW_URL_TO_NON_GLOBAL_ADDRESSES=false \
  -e VALIDATE_IMAGE_URL_REDIRECTS=true \
  -e WHITELISTED_DESTINATIONS_FOR_URL_INPUT=images.example.com,cdn.example.com \
  roboflow/roboflow-inference-server-cpu:latest
```

{% hint style="warning" %}
Two defaults are changing in Q4 2026. `ALLOW_URL_TO_NON_GLOBAL_ADDRESSES` (to `False`) and `VALIDATE_IMAGE_URL_REDIRECTS` (to `True`) currently default to the legacy, permissive behavior for backward compatibility. Both defaults are scheduled to flip to the secure values in Q4 2026. Set them explicitly now, to the secure values to opt in early or to the legacy values if a Workflow genuinely depends on fetching internal URLs, so the change does not surprise you.
{% endhint %}

{% hint style="info" %}
Proxies bypass this protection. If an HTTP(S) proxy is configured for the server, the proxy (not Inference) resolves the destination, so non-global blocking and connection pinning cannot be enforced. The server emits a warning when it detects this. Restrict what the proxy itself can reach if you rely on these controls.
{% endhint %}

{% hint style="info" %}
Same controls in the Python SDK. The `inference-sdk` client applies the same URL policy and SSRF protections, and reads the same environment variables, when it loads images from URLs, so a client that hydrates URL images before sending them is covered too.
{% endhint %}

For server-side video sources, see [Video Configuration](/deployment/self-hosted/inference-server/configuration/video-configuration.md#server-side-video-references). Return to [server security](/deployment/self-hosted/inference-server/configuration/security.md) for network access and authentication.
