---
title: "Security & CSP — Vue"
description: "The Content Security Policy the viewer runs under, with no 'unsafe-inline', and what it does with a PDF you can't trust."
integration: "Vue"
source: "https://www.embedpdf.com/docs/viewer/vue/concepts/security"
---

# Security & CSP

The viewer runs under a strict Content Security Policy: no `'unsafe-inline'`, no `'unsafe-eval'`,
and Trusted Types on. This is the policy to start from:

```http
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'wasm-unsafe-eval';
  style-src 'self';
  worker-src 'self';
  img-src 'self' blob: data:;
  connect-src 'self';
  require-trusted-types-for 'script';
  trusted-types embedpdf;
```

| Directive                       | Why the viewer needs it                                                                                                                                                                                                                         |
| :------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `script-src 'wasm-unsafe-eval'` | The engine is WebAssembly, and the browser asks for this to compile any WebAssembly. It allows nothing else: no `eval`, no inline scripts. With CloudPDF it's needed only for Stamps and Signatures, which open their libraries in the browser. |
| `worker-src 'self'`             | The engine runs in a Web Worker, loaded from a file next to the viewer's                                                                                                                                                                        |
| `img-src blob: data:`           | Pages are drawn into images the browser makes, and tool cursors are small inline images                                                                                                                                                         |
| `connect-src 'self'`            | The engine's WebAssembly, your documents, and any fonts or stamps you configure. Add each origin you load from.                                                                                                                                 |
| `trusted-types embedpdf`        | The viewer's one Trusted Types policy, which only allows URLs of its own files and the ones you configure                                                                                                                                       |

`style-src 'self'` is enough, without `'unsafe-inline'` or a nonce: the viewer never adds a
`<style>` tag or a `style` attribute to your page. Its styles go straight into its own shadow DOM,
which the browser doesn't count as inline styles.

## Loading from a CDN

A browser only starts a Web Worker from its own origin. When the viewer's script comes from
jsDelivr, it starts the engine's workers from `blob:` URLs instead. Add the CDN to `script-src` and
`connect-src` (the script, its chunks and the WebAssembly come from there), and allow `blob:`
workers:

```http
script-src 'self' https://cdn.jsdelivr.net 'wasm-unsafe-eval';
connect-src 'self' https://cdn.jsdelivr.net;
worker-src blob:;
```

To keep `worker-src 'self'`, serve the viewer's files from your own site: install it from npm, or
copy its folder. See [Self-hosting](../self-hosting).

## Builds that use `blob:` workers

Most bundlers (Vite, webpack, Rspack, Parcel, Next.js) emit the workers as files of your build,
so `worker-src 'self'` covers them. Two builds can't, and start the workers from `blob:` URLs, so they
need `worker-src blob:`:

- **Angular**, which loads the engine's portable build;
- **plain esbuild**, which needs that build too: see
  [Self-hosting](../self-hosting#the-engines-webassembly).

To keep `worker-src 'self'` there, copy the two worker files to your site and point the viewer at
them: see [Self-hosting](../self-hosting#workers-and-content-security-policy).

## Your bundler's Trusted Types policy

With `require-trusted-types-for 'script'`, the browser also checks how your bundler loads the rest
of your app's code. Vite, esbuild and Angular need nothing more. The others load it through a
Trusted Types policy of their own, which `trusted-types` names next to `embedpdf`:

| Build               | What to add                                                                                  |
| :------------------ | :------------------------------------------------------------------------------------------- |
| webpack 5           | `output: { trustedTypes: 'webpack' }` in your config, and `trusted-types embedpdf webpack;`  |
| Rspack              | `output: { trustedTypes: 'rspack' }` in your config, and `trusted-types embedpdf rspack;`    |
| Next.js (webpack)   | `trusted-types embedpdf nextjs#bundler;`. Next.js's own inline scripts need its nonce setup. |
| Next.js (Turbopack) | Turbopack can't run with `require-trusted-types-for 'script'` yet: leave that line out.      |

## A PDF you can't trust

A PDF can carry links, scripts and forms that send data somewhere. The viewer treats every one as
untrusted:

- **Scripts** in a PDF, for form checks and calculations, run in a sandbox with no access to your
  page, its cookies or the network. Turn them off with `plugins: { actions: { javascript: { enabled: false } } }`.
- **Links** open only after the user clicks them, and only `http`, `https`, `mailto` and `tel`
  links. `javascript:` and `file:` links do nothing, and so does a link relative to the document,
  such as `/account`, which would otherwise open a page of your own app.
- **Form submissions** never send anything by themselves. A form's submit button tells your code,
  and you decide where the data goes. See [Actions & scripts](https://www.embedpdf.com/docs/headless/vue/documents/actions).

## Good to know

### Annotations and comments

Text people type into annotations and comments is shown as text, never as HTML, so a comment can't
run a script in anyone else's viewer.

### Signatures

A signature is checked against the certificates you trust and nothing else: the viewer never
fetches a certificate or a revocation list from a URL inside the PDF.
