> For the complete documentation index, see [llms.txt](https://docs.getvenora.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.getvenora.tech/plugin-api/plugin-network-account-review.md).

# Network and account APIs: security review

Part of the [Community Plugin API specification](/plugin-api.md). This is a review, not a specification: **nothing described here is implemented.** It records why Phase 3.6 did not add a network or account API to version 1, the narrowest designs that could be considered later, and what would have to be true before either is added.

## Current state

* Plugin code has no network access of its own. The sandbox's content security policy is `default-src 'none'`, and the plugin runs in a worker inside that sandbox ([plugin-security.md](/plugin-api/plugin-security.md), SEC-2). The browser test checks that no request from plugin code reaches another server.
* The `network` and `account` permissions exist, but only as **consent markers** ([plugin-permissions.md](/plugin-api/plugin-permissions.md)). The only capability that needs them is `mentions.showAvatar`. There, Venora makes one fixed request (a Fermo profile lookup) with the signed-in account inside the trusted boundary, and the plugin learns only `{shown: boolean}`.
* No capability returns account data. The session-token guard blocks any message to a plugin that contains a token (SEC-1).

## Who would need these APIs

No plugin in this repository needs either API. The useful cases that have been suggested are reading public data from a service the plugin is built for (for example, a status page or a public API), and personalizing a plugin for the signed-in user (for example, greeting them by display name). Neither is needed for any current or planned bundled plugin.

## Threat model

Plugins are untrusted, including after the user has installed them: a plugin can be malicious from the start, be updated to become malicious, or be tricked by data it processes. Today a plugin that turns hostile can affect only the Fermo page (through `ui`) and its own storage. It **cannot send anything off the device**, which is the property that makes everything else it can see (mention IDs, user IDs, its own settings) low-risk. Any network capability removes that property for the plugin that holds it.

## Network API

### Risks, item by item

| Concern                             | Analysis                                                                                                                                                                                                                                                                                                                                                                                                 |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Permission and enforcement          | Enforceable: a capability gated by `network`, checked by the dispatcher like every other. Enforcement is not the hard part; what the capability allows is.                                                                                                                                                                                                                                               |
| Data exfiltration and tracking      | Any request carries data in its URL, headers, or body, and its timing. A plugin with `ui` sees mention user IDs, and with `storage` its settings. With network access it can send them, and the time the user is active, to its server. A host allowlist limits where data goes, not whether it goes. This is the main reason not to add it.                                                             |
| Host allowlist and URL validation   | The allowlist would have to be declared in `plugin.json`, shown to the user at install with the sensitive-permission warning, and fixed per installed version (as permissions are). URLs would have to be parsed by Venora and matched by exact scheme and host (no wildcards over public suffixes, no IP literals, no `localhost` or private addresses, no user-info, default port only).               |
| HTTPS                               | Required. Plain HTTP would let a network attacker change responses, and would leak request data.                                                                                                                                                                                                                                                                                                         |
| Redirects                           | Redirects would have to be refused (`redirect: "error"`), or every hop re-checked against the allowlist by Venora. Following them automatically turns any allowlisted host with an open redirect into a way around the allowlist.                                                                                                                                                                        |
| Methods, headers, body              | Narrowest useful form: `GET` only, no plugin-supplied headers, no body. Every widening (POST, custom headers) adds ways to reach APIs that change state on the user's behalf.                                                                                                                                                                                                                            |
| Credentials                         | Requests would have to be made with `credentials: "omit"` from the content script. Otherwise the browser attaches the user's cookies for that site, which turns the plugin into a confused deputy acting as the user on any allowlisted site. Fermo's own origin would have to be excluded outright, so no request could use the Fermo session. No `Authorization` header from Venora, ever.             |
| Cross-origin and the content script | Requests made by Venora's content script are made as Fermo's page origin. A request to Fermo would therefore be same-origin and carry the user's Fermo cookies, and requests to other sites are subject to CORS as Fermo's page sees it. Fermo must be excluded, and whether the page's own content security policy applies to such requests differs between browsers and must be verified, not assumed. |
| Response size and type              | A bounded response (for example at most 256 KiB, text or JSON only), read through a stream that stops at the limit, as plugin ZIPs are read. The response must pass the session-token guard like any result, and must be returned as plain data.                                                                                                                                                         |
| Timeout and rate limits             | A per-capability rate limit (for example 10 at once, then 1 per second), the existing 30-second capability timeout, and in-flight limits. These bound load on Venora, not exfiltration: even 1 request per second carries plenty of data.                                                                                                                                                                |
| Safe failure                        | Every failure (blocked host, redirect, oversize, non-2xx, timeout) must be one error code with a fixed message, never the server's response text (plugin-api.md §8.3).                                                                                                                                                                                                                                   |
| Firefox                             | Unverified. How content-script requests and CORS behave in Firefox must be checked in the Phase 3.5 spike before any such capability is designed in detail.                                                                                                                                                                                                                                              |

### The narrowest design worth considering

If a real plugin needs it later, the smallest form is:

* `venora.network.fetchJson({url})` → `{status, data}`, gated by `network`;
* `url` must match an `allowedHosts` list in `plugin.json` (exact HTTPS hosts, Fermo's host never allowed), shown at install and update;
* `GET` only, no plugin headers, `credentials: "omit"`, `redirect: "error"`;
* JSON responses only, at most 256 KiB, passed through the token guard;
* a low per-capability rate limit, and the normal timeout.

### Recommendation

**Do not add a network API in version 1 now.** It removes the "nothing leaves the device" property, and no plugin in this repository needs it. Revisit only with a concrete plugin that needs it, after the Phase 3.5 Firefox spike, and with an install-time disclosure of the allowed hosts reviewed as a product decision. Adding it later is an API addition (plugin-api.md §9.3), so deferring it costs no compatibility.

## Account API

### Minimum fields and sensitivity

The narrowest account API would return only the signed-in user's **id** and **display name**:

| Field                                                     | Sensitivity                                                                                                                                             |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| user id                                                   | Public within Fermo, but it identifies the person using this browser. Together with any way to send data out, it links the person to the plugin author. |
| display name / username                                   | Public within Fermo, same linking concern.                                                                                                              |
| email, phone, settings, tokens, server URLs, account list | Private or secret. Never exposed.                                                                                                                       |

### Analysis

* **Can it be done without exposing internal objects?** Yes: a capability would copy two fields from Fermo's account store in the content script and return `{id, displayName}`. The account record, token, and server URLs would never cross the bridge, and the session-token guard would still check the result.
* **Consent.** It would need the existing sensitive `account` permission, and the permission text would have to change from "the plugin never receives account data" to describing exactly the two fields. That makes it a new permission meaning, so it should be a new permission (for example `profile`), not a silent widening of `account`.
* **Token guarantee.** Unaffected: the guard blocks any message containing a session token, and the capability would never read the token.
* **Value without network.** Without a network API, the data cannot leave the device, and a plugin can already show text (`ui.toast`). The only gain is personalization, which the user can supply as a setting today.

### Recommendation

**Do not add an account API now.** Its only benefit is personalization, which a plugin setting already provides, and it would weaken the permission model's "the plugin never receives account data" promise. If it is added later, it should be a new, sensitive permission that returns exactly `{id, displayName}`, and it must not be combined with a network API without a new security review of the two together.

## Conditions for revisiting

Before either API is added:

1. A concrete plugin needs it, and a setting or an existing capability cannot meet that need.
2. The Firefox feasibility spike (Phase 3.5) has run, so the design is checked in both browsers.
3. The install-time disclosure (allowed hosts, or account fields) is designed and reviewed as a product decision.
4. The capability follows plugin-api.md §10 "Adding a capability", including tests for `permission_denied`, `invalid_payload`, the session-token guard, and, for network, a browser test that a request outside the allowlist, a redirect, and a credentialed request are all refused.


---

# 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.getvenora.tech/plugin-api/plugin-network-account-review.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.
