> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aisky.co.za/llms.txt
> Use this file to discover all available pages before exploring further.

# Security Restrictions

> Why we reject some URLs and how to design around it.

The runtime validates your endpoint URL twice, once when you save it, and again on every invocation. The second pass is a defense against **DNS rebinding** (where a hostname resolves to a public IP at save time but flips to a private IP at call time).

## URL shape rules

| Rule                                                | Reason                                                              |
| --------------------------------------------------- | ------------------------------------------------------------------- |
| Must be `https://`                                  | We don't speak plain `http://`. TLS is mandatory.                   |
| Max 2048 chars                                      | Prevents URL-smuggling attacks via overflow.                        |
| No userinfo in authority (`https://user:pass@host`) | Credentials belong in the auth field, not the URL. Auditable trail. |
| Host must resolve to at least one public IP         | DNS failures fail closed.                                           |
| Host must NOT resolve to any private IP             | Prevents server-side request forgery into your own infrastructure.  |
| Host must NOT be on our self-host blocklist         | Blocks reflection into our own systems.                             |
| Schemes other than `https` rejected                 | No `ws://`, `file://`, `data:`, etc.                                |

## Blocked IPv4 ranges

Every range is checked against the **resolved** IP, not just the URL hostname.

| Range            | Why                                                     |
| ---------------- | ------------------------------------------------------- |
| `10.0.0.0/8`     | Private (RFC 1918)                                      |
| `172.16.0.0/12`  | Private (RFC 1918)                                      |
| `192.168.0.0/16` | Private (RFC 1918)                                      |
| `127.0.0.0/8`    | Loopback                                                |
| `169.254.0.0/16` | Link-local (includes AWS metadata at `169.254.169.254`) |
| `100.64.0.0/10`  | Carrier-grade NAT (RFC 6598)                            |
| `0.0.0.0/8`      | Unspecified                                             |
| `224.0.0.0/4`    | Multicast                                               |
| `240.0.0.0/4`    | Reserved                                                |

## Blocked IPv6 ranges

| Range           | Why                                                          |
| --------------- | ------------------------------------------------------------ |
| `::1/128`       | Loopback                                                     |
| `::/128`        | Unspecified                                                  |
| `fc00::/7`      | Unique-local (ULA)                                           |
| `fe80::/10`     | Link-local                                                   |
| `::ffff:0:0/96` | IPv4-mapped (check IPv4 portion against the IPv4 list above) |

## Self-host blocklist

We block URLs pointing at our own infrastructure to prevent reflection attacks:

* `aisky.co.za` and any subdomain
* `*.supabase.co`
* `*.supabase.in`
* `*.amazonaws.com`
* `localhost` and `*.localhost`

## Redirect handling

We **do not follow redirects**. Any 3xx response from your endpoint produces `HTTP_TOOL_TOO_MANY_REDIRECTS` (technically, "any redirect at all", the name is historical).

Why: each hop is a fresh URL that would need re-SSRF-checking, and a malicious endpoint could redirect to a private IP after passing the initial check. Simpler and safer to require direct resolution.

**Fix:** Resolve the final URL on your side and point the tool at that directly.

## Response content-type allowlist

| Accepted                  | Rejected                   |
| ------------------------- | -------------------------- |
| `application/json`        | `application/octet-stream` |
| `text/plain`              | `image/*`                  |
| `text/html`               | `audio/*`                  |
| `text/csv`                | `video/*`                  |
| `text/*` (other subtypes) | Any other binary type      |

A missing `Content-Type` header is tolerated, we treat it as `text/plain`.

## Response size cap

64 KB. We start reading the response stream and abort as soon as we cross the cap. The first 64 KB is passed to the AI, with a `[truncated; full response was N bytes]` footer appended. The full byte count is logged so you can investigate.

This is **not** a 502 error, it's a successful invocation marked with `HTTP_TOOL_RESPONSE_TOO_LARGE` in the invocations log.

## Timeouts

|                                             | Budget                            |
| ------------------------------------------- | --------------------------------- |
| Total call (TLS + DNS + request + response) | 10 seconds                        |
| TLS handshake alone                         | Subset of the 10s, typically \<5s |

Once 10s elapses we abort the request and return `HTTP_TOOL_TIMEOUT`. The AI tells the caller "lookup timed out" and continues.

## What you can't disable

For safety reasons, none of the above can be turned off, not even with a support ticket. If you have a use case that the rules block, [reach out](mailto:hello@aisky.co.za) and we'll work with you on a v2 that solves it without dropping the SSRF guard.

## Best-case scenario

If your endpoint:

* Uses HTTPS with a valid public certificate
* Resolves to a public, non-blocked IP
* Returns 2xx with `Content-Type: application/json` and a body under 4 KB
* Responds in under 2 seconds

...then your tool feels instant from the caller's perspective. That's the bar we recommend designing for.

<Card title="Next: Best practices" href="/guides/http-tools/best-practices">
  Designing endpoints the AI can use well.
</Card>
