How the plugin sandbox protects students and educators, and what the team reviews before a plugin is published
Security in the plugin system operates at two levels: structural protections that are enforced by the browser and the runtime regardless of what a plugin does, and the vetting process that reviews a plugin's code and behaviour before it reaches the marketplace.
These protections require no action from you — they are enforced automatically for every plugin.
Every plugin runs in a sandboxed <iframe> with no same-origin access to the internote page. At the browser level this means:
localStorage, sessionStorage, IndexedDB, or cookiesThe sandbox attribute applied is sandbox="allow-scripts allow-pointer-lock". Everything not in that list is denied by the browser, not by application code.
Plugin storage is enforced at the database level via row-level security. The storage API only ever reads and writes rows matching the current (user_id, internote_id, element_hash) composite key. There is no API surface through which a plugin can read another user's data, access a different internote's stored state, or enumerate stored keys across plugins.
The host only honours a fixed set of message types from the plugin (ready, storage.*, error). Any other message type sent via postMessage is silently discarded. A plugin cannot trigger host-side behaviour by crafting arbitrary messages — the SDK is the only supported channel.
Approved plugins are cryptographically signed by the Internote team before being pushed to the live registry. When the internote runtime fetches a plugin, it verifies the signature against the manifest before loading the iframe. An unsigned or tampered plugin will not load.
Storage and network-adjacent API calls are rate-limited server-side. A plugin that attempts to make excessive storage writes or trigger abnormal call volumes will be throttled and flagged for review.
Understanding the boundaries helps you design appropriately:
fetch and WebSocket connections to external servers. This is intentional (many legitimate plugins need live data), but must be declared in the manifest's permissions field. Undisclosed external requests are grounds for rejection.Before a plugin appears in the marketplace it is reviewed by the Internote team. The review is not automated — a person reads the code, runs the plugin, and tests it against the criteria below.
First submissions typically take two to five business days. Updates to approved plugins are usually reviewed faster.
The team looks for:
postMessage to inject content into the parent page, no attempt to access host-page APIspermissions: ["network"]internote.ready() call complete within two seconds on a mid-range deviceWorkerrequestAnimationFrame loop, frame time stays consistently below 16 ms at 60 FPSdescription accurately represents what the plugin doespostMessage message types, no attempts to reach internote internalsinternote.onUnload() releases all resources — animation frames, timers, observers, open connectionsIf you discover a security vulnerability in the plugin system or in a published plugin, contact the Internote team directly rather than publishing the finding publicly. Do not attempt to exploit a vulnerability beyond what is necessary to confirm it exists.