> ## Documentation Index
> Fetch the complete documentation index at: https://knitkit.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Security: SRI, CSP, and CORS for knitkit

> Pin and verify remote modules with Subresource Integrity, configure CSP for federated pages, and set correct CORS headers on remote servers.

Module federation is powerful precisely because it executes code from another origin inside
your page at runtime. That power comes with real risk: if an attacker can tamper with a remote
module or its manifest, they run arbitrary JavaScript with your page's full privileges. knitkit
addresses this through three complementary layers — Subresource Integrity (SRI) for hash
pinning, Content Security Policy (CSP) for origin allowlisting, and CORS for controlling which
hosts can fetch your remote assets. Using all three together gives you defense in depth; using
none is the default footgun of naive module federation setups.

***

## Subresource Integrity (SRI)

`knitkit build` computes a `sha384` hash for each shared asset and records it in the manifest's
`integrity` field:

```json theme={null}
{
  "shared": {
    "react": {
      "version": "18.3.1",
      "requiredVersion": "^18.0.0",
      "singleton": true,
      "url": "./shared/react-18.3.1.js",
      "integrity": "sha384-..."
    }
  }
}
```

How the hash is enforced depends on the environment:

<Tabs>
  <Tab title="Browser (shared deps)">
    knitkit injects shared dependencies into the page's import map using the [`integrity`
    key](https://github.com/WICG/import-maps#subresource-integrity), so the browser natively
    refuses to execute a tampered shared module. This is available in **Chrome 127 / Firefox
    138 / Safari 18.4** — verify support for your target browsers at ship time.

    ```json theme={null}
    {
      "imports": {
        "react": "https://cdn.example.com/shared/react-18.3.1.js"
      },
      "integrity": {
        "https://cdn.example.com/shared/react-18.3.1.js": "sha384-..."
      }
    }
    ```
  </Tab>

  <Tab title="Node SSR">
    `@knitkit/node` verifies the `sha384` hash itself **before executing** any fetched remote
    module. A mismatch throws a coded `KNIT_ERR_SRI_MISMATCH` error and the module is never
    evaluated. This check runs unconditionally on every module fetch, regardless of the browser
    support matrix.
  </Tab>
</Tabs>

### Limitation: exposed modules in the browser

<Warning>
  The browser platform provides no `integrity` option on a dynamic `import()`. This means an
  exposed module loaded by `loadRemote` in the browser **cannot** be hash-verified by the
  platform alone.

  Your options:

  1. **Put exposed modules in the import map with integrity** — the browser enforces the hash
     at the import-map level before the module runs.
  2. **Rely on `@knitkit/node`'s server-side verification** — which always runs and blocks
     mismatches before they reach the client.
  3. **Serve remotes from origins you control** over HTTPS — reducing the attack surface to
     your own infrastructure rather than a third-party CDN.

  Manifest signing (verifying the manifest file itself, not just individual assets) is on the
  knitkit roadmap.
</Warning>

***

## Content Security Policy (CSP)

A federated page fetches modules and manifests from one or more remote origins. Your CSP must
allow those origins explicitly. Here is a starting-point header — tighten the origin lists to
exactly the CDN hostnames you use:

```
Content-Security-Policy:
  default-src 'self';
  script-src  'self' https://cdn.example.com 'nonce-{RANDOM}';
  connect-src 'self' https://cdn.example.com;
  require-trusted-types-for 'script';
```

Key points:

* **Import map nonce** — the import map is a `<script type="importmap">` inline tag. Under a
  strict CSP, allow it with a per-request `nonce` attribute (e.g. `<script
  type="importmap" nonce="abc123">`). This is strongly preferred over `'unsafe-inline'`, which
  would defeat inline-script protection for your entire page.
* **`connect-src`** — must include every origin from which you `fetch` a manifest or a module.
  `registerRemotes` and `loadRemote` both use `fetch` internally; a missing `connect-src` entry
  silently blocks the request.
* **Prefer an allowlist over wildcards** — `script-src 'self' https://cdn.example.com` is
  significantly safer than `script-src *`. Each remote origin you add to `script-src` is a
  trust decision; make it explicit.

<Tip>
  Generate your CSP nonce server-side on each request and inject it into both the HTTP header
  and every inline `<script>` tag. Most meta-framework adapters (Next.js, Nuxt, SvelteKit)
  have middleware hooks for this.
</Tip>

***

## CORS

Remote servers must send `Access-Control-Allow-Origin` headers for three categories of
resources: manifests (`knit.manifest.json`), exposed module files, and shared asset files.
Without CORS headers, cross-origin `fetch` calls fail silently in the browser.

Configure your remote's static host (CDN, object storage, or web server) to return:

```
Access-Control-Allow-Origin: https://your-host.example.com
```

For fully public assets intended to be used by any host, `*` is acceptable:

```
Access-Control-Allow-Origin: *
```

<CodeGroup>
  ```nginx nginx.conf theme={null}
  location /knit/ {
    add_header Access-Control-Allow-Origin "https://your-host.example.com";
    add_header Access-Control-Allow-Methods "GET, OPTIONS";
  }
  ```

  ```yaml AWS S3 / CloudFront (CORS rule) theme={null}
  CORSRules:
    - AllowedOrigins:
        - "https://your-host.example.com"
      AllowedMethods:
        - GET
      AllowedHeaders:
        - "*"
  ```
</CodeGroup>

If a remote returns a 404, is unreachable, or does not include the required CORS headers,
`registerRemotes` and `loadRemote` fail with a coded `KNIT_ERR_LOAD_FAILED` error. The error
message includes a suggestion pointing at CORS configuration and reachability as the likely
cause.

<Note>
  CORS errors in the browser are opaque — the browser's network tab shows a failed request but
  does not expose the response body. If you see `KNIT_ERR_LOAD_FAILED`, open the browser
  console and check for a CORS policy message alongside the knitkit error.
</Note>

***

## Trust model

Every remote origin you federate into your host executes JavaScript with your page's full
privileges — the same cookies, storage, DOM access, and CSP context as your own first-party
code. Keep that in mind when making trust decisions:

* **Use HTTPS for all remote assets.** HTTP origins are trivially intercepted; never federate
  over unencrypted connections.
* **Pin hashes wherever the platform supports it.** SRI on the import map catches CDN
  compromises and supply-chain attacks for shared dependencies.
* **Scope your CSP to the smallest set of origins necessary.** Each entry in `script-src` is
  an explicit grant of code-execution trust.
* **Only federate origins you control or have a contractual relationship with.** A third-party
  CDN that serves one of your remotes is part of your trusted computing base. Vet it
  accordingly.

VM-based or ShadowRealm-based SSR isolation (to limit a compromised remote's blast radius on
the server) is a roadmap item for `@knitkit/node`.
