## Introduction

Before v0.104.0, code executed at renderer level (e.g. front-end scripts) could directly require `@electron/remote` or even Node.js APIs (e.g. `process` or `fs`). While this makes them powerful, it also exposes a significant attack surface — any XSS or untrusted script in a note becomes remote code execution on the host.

To mitigate this, the client-side no longer has access to these APIs and everything must go through the Electron API instead.

If this API change is causing issues with some of your front-end scripts, consider:

- Interacting with Backend scripts which have a greater degree of freedom.
- Reporting it as a feature request.

## Overview of the API

The Frontend and Backend APIs reside in a global variable, `api`, that can be used anywhere in the script. For example, to display a message to the user the following front-end script can be used:

    api.showMessage("Hello world.");

The Electron API is different: it lives on `window.electronApi` (exposed by the desktop preload script), not on `api`, and is only available in the Electron desktop build. Frontend scripts that use it should guard with `if (window.electronApi)` so they degrade cleanly in the browser and standalone (WASM) builds.

    window.electronApi?.window.setZoomFactor(1.2);

## Additional protection

Some of the APIs have additional safe-guards built in which prevent unauthorized access.

The `shell` group is the most heavily validated: `openExternal`is restricted to an allowlisted set of URL schemes (blocking `file:`, `smb:`, Follina-class schemes, etc.), `openPath` must resolve under the Trilium data directory or temporary directory, and `downloadURL`is locked to the app's own origin. Invalid input throws on the main side rather than being silently passed through.