> For the complete documentation index, see [llms.txt](https://docs.tatakai.me/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tatakai.me/extensions/security.md).

# Security

The extension system enforces a layered security model balancing extensibility with user safety.

***

## Trust Tiers

| Tier                     | Extensions                                          | Capabilities      | Validation                    |
| ------------------------ | --------------------------------------------------- | ----------------- | ----------------------------- |
| **Bundled**              | Shipped with app (`extensions/*/dist/`)             | All (data + code) | Pre-audited, signed by build  |
| **Trusted Sideloaded**   | User-installed `.kai` with valid signature (legacy) | All (data + code) | Signature verified at install |
| **Untrusted Sideloaded** | User-installed `.kai` without signature             | Data-driven only  | Manifest validation only      |

{% hint style="info" %}
**Current state:** Legacy signing fields are ignored. Trust is determined by whether an extension is bundled or explicitly marked trusted in the registry.
{% endhint %}

## Execution Privileges

| Component                           | Process                                     | Privileges                                                          |
| ----------------------------------- | ------------------------------------------- | ------------------------------------------------------------------- |
| **Main bundle (`bundle.js`)**       | Node (main process, in-process `require()`) | Full Node APIs, network (per manifest), file system (sandboxed dir) |
| **Renderer bundle (`renderer.js`)** | Browser (renderer process)                  | App React instance, DOM, network via `ctx.fetch` (proxied)          |
| **Stremio addons**                  | HTTP/JSON only                              | No code execution                                                   |
| **Seanime/Mihon/Aniyomi**           | Compatibility layer                         | Sandboxed per ecosystem                                             |

## Permission System

### Manifest Permissions

```json
{
  "permissions": [
    "network:domain:nyaa.si",
    "network:domain:*.animepahe.ru",
    "torrent:search",
    "torrent:download",
    "parse:html",
    "parse:json",
    "storage:unlimited"
  ]
}
```

| Permission              | Scope                          | Enforcement                  |
| ----------------------- | ------------------------------ | ---------------------------- |
| `network:domain:<host>` | HTTP requests to domain        | Main process proxy validates |
| `torrent:search`        | Torrent engine search          | TorrentCore checks           |
| `torrent:download`      | Torrent engine download        | TorrentCore checks           |
| `parse:<parser>`        | Specific parser access         | Bundle sandbox checks        |
| `storage:unlimited`     | Bypass extension storage quota | Registry enforces            |

### Network Enforcement

All extension `fetch` calls route through the **main process proxy**:

```
Extension fetch(url)
        │
        ▼
Main process: validate domain against manifest.permissions
        │
        ├── Allowed → Proxy request (with header replay, Cloudflare bypass)
        │
        └── Denied → Throw network error
```

**Code:** `desktop/runtime/extension-api-host/host-server.cjs` → `installInProcessFetchShim()`

## Payload & Timeout Guards

**File:** `desktop/runtime/security/`

| Guard             | File                | Limit                      |
| ----------------- | ------------------- | -------------------------- |
| **Payload limit** | `payload-guard.cjs` | 10 MB on IPC responses     |
| **Call timeout**  | `timeout-guard.cjs` | Configurable (default 30s) |

```js
// payload-guard.cjs
function enforcePayloadLimit(data, limit = 10 * 1024 * 1024) {
  const size = Buffer.byteLength(JSON.stringify(data));
  if (size > limit) throw new Error(`Payload exceeds ${limit} bytes`);
}

// timeout-guard.cjs
function withCallTimeout(promise, ms = 30000) {
  return Promise.race([
    promise,
    new Promise((_, reject) => setTimeout(() => reject(new Error('Call timeout')), ms)),
  ]);
}
```

## Kill Switches

**Server-side kill list** checked at runtime:

```ts
// desktop/ipc/ipc-runtime.cjs
ipcMain.handle('runtime:health', async () => {
  for (const id of registry.listLoaded()) {
    if (registry.isKillSwitched(id)) {
      workerPool.terminate(id);
      registry.unregister(id);
      logger.warn(`[Extension] Kill-switched extension unloaded: ${id}`);
    }
  }
  return { status: 'ok', loadedExtensions: registry.listLoaded() };
});
```

* Fetched from TatakaiAPI on boot
* Can disable specific extensions globally
* Immediate termination on detection

## Manifest Validation (`kai-format.cjs`)

**File:** `desktop/runtime/extension/kai-format.cjs`

### Structural Validation

1. **ZIP archive** — Valid `.kai` file
2. **Required files** — `manifest.json`, `bundle.js`
3. **Manifest schema** — All required fields, valid types
4. **ID safety** — `^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$`, no `..`
5. **Size limits** — `bundle.js` ≤ 10 MB, `icon.png` ≤ 512 KB
6. **Custom sources** — Validated if `custom-source` capability declared

### Stripped Fields (Legacy)

```js
// Legacy signing metadata ignored
delete manifest.signature;
delete manifest.signedBy;
delete manifest.sideloaded;
```

## Installation Security

### Path Traversal Prevention

```js
// kai-format.cjs
function installKaiExtension(parsed, extensionsDir, fs, path) {
  const extId = parsed.manifest.id;
  if (!isValidExtensionId(extId)) throw new Error('Unsafe id');
  
  const extDir = path.join(extensionsDir, extId);
  const resolvedDir = path.resolve(extDir);
  const resolvedBase = path.resolve(extensionsDir);
  
  // Defence in depth
  if (resolvedDir !== resolvedBase && !resolvedDir.startsWith(resolvedBase + path.sep)) {
    throw new Error('Refusing to install outside extensions directory');
  }
}
```

### Auto-load Safety

Bundled extensions are auto-loaded from `extension/*/dist/` — only first-party code.

## Runtime Isolation

### Extension Worker Pool (Main Process)

**File:** `desktop/runtime/extension/extension-worker-pool.cjs`

* Each extension bundle runs in an isolated worker thread.
* Communication occurs via message passing.
* Workers suspend and resume based on activity.
* Resource limits apply per worker.

### Renderer Process

* Code-driven contributions run in the **app's React runtime**.
* No direct Node.js access.
* Network access uses `ctx.fetch` (proxied).
* Storage uses `ctx.storage` (namespaced localStorage).

## Data Isolation

| Data Type                  | Isolation                                                         |
| -------------------------- | ----------------------------------------------------------------- |
| **Extension storage**      | Namespaced: `ext:${id}:${key}` in localStorage                    |
| **Custom source progress** | Separate React Query keys: `['custom', namespace, sourceId, ...]` |
| **Download tracking**      | `downloads` table with `source_id = "${namespace}::${sourceId}"`  |
| **Analytics**              | Per-provider, namespaced IDs                                      |

## Compatibility Layer Security

| Ecosystem         | Isolation                                      |
| ----------------- | ---------------------------------------------- |
| **Stremio**       | HTTP/JSON only — no code execution             |
| **Seanime**       | JS/TS providers run in compatibility VM (Sora) |
| **Mihon/Aniyomi** | Source mapping only — no extension code        |
| **CloudStream**   | Source mapping only                            |
| **Sora**          | Interpreter VM (isolated)                      |
| **MangaYomi**     | VM-based execution                             |

## Best Practices for Extension Authors

{% columns %}
{% column %}

### Do

* Declare minimal permissions
* Use `ctx.fetch` for network (auto-proxied)
* Use `ctx.storage` for persistence
* Handle errors gracefully
* Clean up in `dispose()`
  {% endcolumn %}

{% column %}

### Don't

* Bundle Node.js polyfills in renderer
* Use `eval()` or `new Function()`
* Access `window.electron` directly (use `ctx` APIs)
* Store sensitive data in localStorage
* Make assumptions about app internals
  {% endcolumn %}
  {% endcolumns %}

## Audit Checklist

* [ ] Manifest validates against schema
* [ ] Permissions minimal and specific
* [ ] No `eval`/`Function` in bundles
* [ ] Network calls use `ctx.fetch`
* [ ] Storage uses `ctx.storage`
* [ ] Renderer uses `ctx.React`
* [ ] `dispose` cleans up all resources
* [ ] No hardcoded secrets in bundle
* [ ] Error handling doesn't leak internals
* [ ] Works without trusted status (data-driven only)

## Related

* [Extension Overview](/extensions/extension-overview.md)
* [Manifest Reference](/extensions/extension-manifest.md)
* [Renderer Loader](/extensions/renderer-loader.md)
* [Build First Extension](/extensions/build-your-first-extension.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.tatakai.me/extensions/security.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
