Security And Current Limits
An installed Mantis extension runs your code inside the Mantis page. This page explains what it can reach, what constrains it, and what is not supported yet.
Trust model
Only install extensions from sources you trust.
An extension can:
- run JavaScript inside its extension host
- run JavaScript inside its panel
- access Mantis data covered by granted permissions
- create bags if granted
bags:write - open and close panels if granted
panels:write - register and execute commands if granted
commands:execute - store extension state through
workspaceStateandglobalState - invoke its Python backend if granted
backend:invoke - run Python dependencies declared in
requirements - access the network from its backend if
networkistrue
The install dialog shows the declared permissions, contributed panels, backend status, and backend network request.
Browser access
Host and panel code must use mantis / window.mantis to communicate with Mantis. Permissions are checked on SDK calls. If permission is missing, the call fails.
The extension host runs in a Web Worker. Panels run in sandboxed iframes with sandbox="allow-scripts" only (no allow-same-origin). That keeps the panel on an opaque origin so it cannot read the parent’s cookies, localStorage, or DOM. Do not add allow-same-origin for extension panels without a full security review.
For durable UI state, panels should use window.mantis.workspaceState / window.mantis.globalState (see SDK reference). That storage is handled in the parent page over the RPC bridge, like the host worker’s context.workspaceState / globalState.
They are separate browser execution contexts, but they are still trusted extension code.
Hard limits
These are the edges an author actually hits. None of them are configurable from a package.
| Limit | Value | What happens when you exceed it |
|---|---|---|
| RPC timeout, panel and host | 30 s | The promise rejects with Mantis extension RPC timeout: <method>. |
| Command invocation timeout | 30 s | The promise rejects with a command timeout. |
| Python backend execution | 30 s by default | The invocation fails. Combined with the RPC cap, a synchronous long analysis is not possible. |
| Package size | 25 MB | Import is refused. |
| Single file size | 5 MB | Import is refused. |
| File encoding | UTF-8 text only | Import is refused with “Extension file must be UTF-8 text”. No images, fonts, or wasm can be shipped in a package; inline them as data URIs or fetch them at runtime. |
| Versions of one id | Newest only | Older versions stay on the server but the workspace loads only the highest version of each extension id. |
Extension state (workspaceState and globalState) is localStorage in the Mantis page, not account state. It is per-browser-profile, is not synced across devices, and is lost when site data is cleared.
Backend execution
Python backends run with additional safeguards. Mantis:
- validates backend paths
- installs requirements into a per-extension cache
- applies execution timeouts
- defaults backend network mode to no network
These safeguards reduce accidental damage, but they do not make unknown code safe. Treat backend code as trusted.
Permissions are not a marketplace review
Permissions limit access at runtime, but they do not prove an extension is safe. A malicious extension with maps:read can still read map data visible through that permission.
Before installing, check:
- who published it
- why it needs each permission
- whether backend network is requested
- whether requirements are expected
- whether the package source is trusted
Current limits
The current extension system is beta. It now has background activation, durable commands, deactivate hooks, manifest.main, activationEvents, and basic extension state.
Not supported yet:
- writing the point selection.
selection:writeis defined in the frontend permission enum and gatesselection.set(), but the install validator rejects it, so a package declaring it does not install at all. Extensions can read the selection and create bags; they cannot set the selection. - calling native Mantis commands. The native command allowlist is empty (see below).
- menus contribution point
- settings contribution point
- binary assets in a package
- marketplace signing
- verified publishers
- extension dependency graph
- stable SDK compatibility field like
engines.mantis - secret storage
- extension update channels
- CSP-per-extension origin isolation
Command lifetime limit
Commands can be registered from the extension host:
exports.activate = async function activate(context) {
const disposable = await mantis.commands.registerCommand(
'demo.sample-panel.refresh',
refresh,
);
context.subscriptions.push(disposable);
};Host-registered commands survive panel close and are cleaned up when the host deactivates.
Panels may still register commands:
const disposable = await window.mantis.commands.registerCommand(
'demo.sample-panel.refresh',
refresh,
);Panel-registered command handlers live with that panel instance. If the panel closes, those handlers are disposed.
Native command execution
window.mantis.commands.execute can execute commands that an extension registered. Native Mantis commands go through an allowlist, and that allowlist is currently empty, so the effective answer today is that no built-in Mantis action is reachable from an extension. Anything not registered by an extension throws.
commands:execute therefore grants far less than its name suggests. It does not let an extension drive the Mantis UI.
Data handling guidance
Extension authors should:
- request the smallest permission set possible
- avoid sending sensitive data to external services
- keep backend network disabled unless required
- validate payloads before processing
- show clear errors instead of silently swallowing failures
- document what the extension reads and writes
Future direction
The contribution points reserved in the manifest (menus, settings) suggest where the platform is headed, and a native command allowlist exists in code waiting to be populated. Nothing on that list has a ship date, so build against what is documented above rather than what is reserved.