Skip to main content

A Sandboxed Plugin System

A plugin system usually means one of two uncomfortable options: compile and load a binary, with a real security boundary to build and maintain, or run an interpreted script with full host access, which is no boundary at all. A Stof document sits in between — it can add real behavior to a running system, but only touch what it's explicitly handed. Nothing else.

Loading Plugin Code

step1.stof
#[main]
fn main() {
  const plugin_src = "fn greet() -> str { 'hello from a plugin' }";

  const sandbox = new {};
  parse(plugin_src, sandbox);

  pln(sandbox.greet());
}
Output

A Well-Behaved Plugin, and One That Reaches Too Far

Both plugins below are just strings — the same load_plugin function handles either one identically. The difference shows up when they run:

plugins.stof
fn load_plugin(src: str, data: unknown) -> obj {
  const sandbox = new { data: data };
  parse(src, sandbox);
  sandbox
}

#[main]
fn main() {
  const good_plugin = "fn transform() -> str { self.data.upper() }";
  const good = self.load_plugin(good_plugin, "hello, plugin");
  pln(good.transform());

  const bad_plugin = "fn transform() -> str { Http.fetch('https://evil.example') }";
  const bad = self.load_plugin(bad_plugin, "hello, plugin");
  try { pln(bad.transform()); }
  catch { pln('blocked: no Http library available to this document'); }
}
Output

good_plugin does real work with nothing but self.data — no special permission needed for that, because it never needed to leave the sandbox. bad_plugin isn't blocked by a permissions check or a content filter; there's simply no Http for it to call, in this document or any other unless a host explicitly loads one in. The failure is a normal thrown error, catchable the same way any other error is — not a security incident.