# Content Security Policy

> The CSP directives a page needs to run the AgentGate SDK: no unsafe-eval or unsafe-inline.

The SDK needs no `unsafe-eval`, no `unsafe-inline` and no inline styles. If
your page sets a Content Security Policy, add your AgentGate endpoint to
`script-src` and `connect-src`, and allow `blob:` workers:

```text
script-src 'self' https://agentgate.example;
connect-src 'self' https://agentgate.example;
worker-src blob:;
```

| Directive | Why |
| --- | --- |
| `script-src` | loads `/sdk/v1/agentgate.js`, and the per-challenge instrumentation program from `/v1/browser/instrument` on the same endpoint |
| `connect-src` | `POST /v1/browser/challenge` and `/v1/browser/verify`, and the fetch of `/sdk/v1/worker.js` |
| `worker-src blob:` | on a page from another origin, the proof of work runs in a worker started from a `blob:` URL |

Without `worker-src blob:` the SDK falls back to solving the proof of work
on the main thread, in time slices. It still works, but it is slower,
especially in background tabs. When AgentGate is served from your own
origin, the worker is loaded directly and `worker-src 'self'` (or the
`script-src` fallback) is enough.

`style-src` needs no change: the widget styles its elements through the
CSSOM, which `style-src` does not restrict.

## Nonces

If your policy uses nonces (`script-src 'nonce-…'`), put the nonce on the
SDK's script tag. The SDK copies it to the instrumentation script it loads,
so no extra allowance is needed for that script:

```html
<script src="https://agentgate.example/sdk/v1/agentgate.js" nonce="r4nd0m"></script>
```

With `'strict-dynamic'` the scripts the SDK adds are trusted through it as
well.

## `base-uri`

Do not set `base-uri 'none'` or `base-uri 'self'` on pages that run the
widget. Part of the browser check parses generated markup whose `<base>`
element points at another (made-up) origin, and a page's CSP also applies to
documents it parses; with a restrictive `base-uri` the check computes the
wrong answer and every submission fails with `instrument_invalid`. Leave
`base-uri` unset: with `script-src` restricted, a `<base>` element cannot
load scripts from elsewhere.

## Checking your policy

Open the browser console on the protected page and submit the form. A CSP
problem shows as a `Refused to load` or `Refused to connect` report naming
the directive. A blocked `connect-src` makes the SDK reject with
`network`; a blocked instrumentation script does not fail the verification
but makes the visible check much more likely (the evidence it would have
added is missing). See [Troubleshooting](/docs/troubleshooting).
