Safe by design - the permission sandbox
deny by default

Safe by design

Installing a third-party module shouldn't mean handing it your whole filesystem. In Mutka a module receives exactly the capabilities it declares - and a denied permission isn't just refused, it's unreachable.

The problem with plugins

Most extensible apps grant plugins the same power as the app itself. A plugin that should only count words can usually also read your SSH keys, phone home, or delete a folder - because nothing stands between it and the system. Even mainstream platforms acknowledge this: VS Code's own documentation states that extensions run with the full privileges of the editor.

Mutka takes the opposite stance: the classic principle of least privilege, applied to a file explorer. The core ships only infrastructure; every feature is a module, and every module states up-front the precise capabilities it needs. The system grants those and nothing more.

Permissions are a declared contract

A module is a single file that exports defineModule({ id, permissions, … }). The permissions array is the whole story: it's the complete list of what the module is allowed to touch.

When the module calls host.fs.write() or host.net.fetch(), the gateway checks that call against the declared list. If the matching permission isn't there, the call throws before it ever reaches the system.

  • fs:read / fs:write / fs:temp - scoped filesystem access
  • clipboard:read / clipboard:write - the macOS pasteboard
  • navigation, dialog, ui, network, storage, secrets
  • Anything not listed is denied - there is no implicit access

Untrusted code runs in a real sandbox

Trusted built-ins run in-process for speed. Community modules you install run isolated in a Web Worker: no DOM, no invoke, no reference to the core. Their only line to the system is a postMessage channel.

That means a denied capability isn't a polite refusal - the worker has no way to perform it at all. The permission gateway is the single, auditable choke point every privileged call must pass through. You review those permissions in the extension manager before anything installs.

What a blocked call looks like

export default defineModule({
  id: "com.word-count",
  permissions: ["fs:read"],   // the whole allow-list
  setup(host) {
    host.fs.readDir(path);   // ✓ allowed
    host.fs.deleteItem(path);  // ✗ throws: fs:write not granted
  }
});

A module that only declared fs:read cannot write - the gateway throws.

Three layers, one guarantee

Safety in Mutka isn't a setting you can forget to enable - it falls out of the architecture.

1

Declared up front

Permissions live in the manifest, visible before you install. Nothing is requested silently at runtime.

2

Physically isolated

Community modules run in a Web Worker with no system handles - capabilities they lack simply don't exist for them.

3

Centrally gated

One gateway checks every privileged call. To audit what's possible, you read a single file.

Frequently asked

Can a module access files I didn't open?

Only if it declared fs:read or fs:write. Without those permissions the filesystem capabilities are never wired into the module, so the calls don't exist to be made.

Can a module phone home or send my data over the network?

Not unless it declared the network permission, which is shown in the install review. A module without it has no network capability at all.

What stops a malicious module from bypassing the gateway?

Untrusted modules run in an isolated Web Worker with no reference to the core, no DOM and no invoke bridge. The only way out is the postMessage channel, and every message is checked against the declared permissions.

Can I revoke access after installing?

Yes. Disabling a module tears down its worker immediately, and uninstalling removes it from disk. Every change is applied live without restarting the app.

Sources & further reading

The ideas behind Mutka's sandbox aren't invented here. They build on well-documented platform primitives and decades of security research.

  1. 1
    Web Workers APIMDN Web Docs

    The browser isolation primitive Mutka uses to run untrusted modules: no DOM, no shared memory, postMessage only.

  2. 2
    The Protection of Information in Computer SystemsSaltzer & Schroeder, MIT

    The 1975 paper that formalized the principle of least privilege Mutka's permission model follows.

  3. 3
    Declare permissions: Chrome extensionsChrome for Developers

    Prior art: browser extensions also declare permissions in a manifest reviewed at install time.

  4. 4
    Tauri security modelTauri

    The security architecture of the framework Mutka is built on, including its IPC and capability system.

  5. 5
    Content Security Policy (CSP)MDN Web Docs

    The mechanism that blocks all native network egress from modules, making host-proxied HTTP the only way out.

Build something powerful, safely

Read how the permission model works, then write your first sandboxed module.