Security

Plugin Security Model

Mostly Modular’s approach to mod/plugin security. Honest about what we guarantee,

honest about what we can’t.

>

See also: [MOD-CURATION.md](./MOD-CURATION.md) for trust tiers, [DISTRIBUTION.md](./DISTRIBUTION.md) for marketplace.


Design Principle

The sandbox is structural, not behavioral.

Most modding systems rely on trust: “we hope modders don’t do bad things.” MM’s

WASM sandbox doesn’t rely on hope — it physically removes capabilities from the

guest environment. A plugin can’t access the filesystem because no filesystem API

exists in its sandbox. There’s no lock to pick because there’s no door.

That said: no security model is perfect. We document what we protect against,

what we mitigate, and what remains the user’s responsibility.


What WASM Sandboxing Prevents

These are structural guarantees enforced by the wasmtime runtime at the CPU level.

A plugin author cannot work around them regardless of language, cleverness, or intent.

| Threat | Status | Why |

|——–|——–|—–|

| Filesystem access (read or write) | Prevented | No filesystem APIs in sandbox. No WASI FS capability granted below Tier 2. |

| Network access (HTTP, sockets, DNS) | Prevented | No network APIs in sandbox. No WASI net capability granted below Tier 1. |

| OS API calls (registry, processes, services) | Prevented | WASM has no FFI to native code. |

| Access other plugins’ memory | Prevented | Each WASM instance has its own linear memory. Hardware-isolated. |

| Execute arbitrary native code | Prevented | WASM is a bytecode VM. Cannot JIT or exec native instructions. |

| Keylogging / input capture at OS level | Prevented | No access to OS input APIs. Plugin receives only events the kernel explicitly sends. |

| Crypto mining / background computation | Prevented | CPU budget enforced per frame. Kernel kills plugins exceeding cpu_ms_per_frame. |

What We Mitigate (Reduced Risk, Not Eliminated)

| Threat | Mitigation | Residual Risk |

|——–|———–|—————|

| Resource exhaustion (RAM) | memory_mb budget per trust tier. Kernel terminates plugins exceeding allocation. | A plugin at its budget limit may still cause frame drops. |

| Resource exhaustion (CPU) | cpu_ms_per_frame budget. Kernel measures and enforces. | Measurement granularity — plugin could spike briefly between checks. |

| Event bus data observation | Plugins only receive events they declared in manifest (events.consumes). Tier 3+ restricted to declared_only. | A plugin that legitimately subscribes to an event sees all its data. Game developers should avoid putting sensitive data in broadly-consumed events. |

| Malicious updates to trusted plugins | Automated scanning on every publish. Behavioral diff flagged if capabilities change between versions. | Sophisticated attacks that stay within declared capabilities may pass automated scanning. Community reporting is the backstop. |

| Social engineering via in-game UI | UI capability restricted by tier. Tier 5 has no UI access. Tier 3-4 limited. | A plugin with UI permission could display misleading content. This is a moderation problem, not a sandbox problem. |

What Remains the User’s Responsibility

| Risk | Our Position |

|——|————-|

| Choosing to sideload (Tier 5) unvetted WASM | We warn clearly. Sandbox still protects, but no scanning was performed. |

| Granting elevated trust to a plugin | Tier promotion requires action. We document what each tier allows. |

| Game developer exposing sensitive host functions | See “Host Function Audit” below — this is on game devs AND on us for engine-level functions. |


The Host Function Attack Surface

This is our most important ongoing security responsibility.

WASM plugins can only interact with the outside world through host functions —

functions the kernel explicitly exposes to the plugin sandbox. Every host function

is a potential security boundary.

Current Host Functions (Kernel)

Each function listed with its security implications:

| Function | Purpose | Risk Level | Rate-Limited | Notes |

|———-|———|———–|————-|——-|

| kernel_log | Plugin writes to debug log (with prefix) | Low | ✅ 1000/frame | Could spam logs. Silent drop after limit. |

| kernel_print | Plugin writes clean output to stdout | Low | ✅ 1000/frame | Interactive text games use this. Same policy as kernel_log. |

| kernel_read_line | Plugin reads one line from stdin | Medium | ❌ | Blocks kernel thread. Sideloaded plugins trigger security warning. |

| kernel_random | Returns random integer in [min, max] | None | ❌ | Pure function. No side effects. |

| event_register | Register a new event kind by name | Low | ❌ | Could pollute registry but no security boundary crossed. |

| event_subscribe | Subscribe to an event kind | Medium | ❌ | DeclaredOnly enforced for Tier 3+ by Vogon Customs. |

| event_emit | Emit an event to all subscribers | Medium | ❌ | DeclaredOnly enforced for Tier 3+. CPU budget is rate-limiting mechanism. |

| kernel_theme_get | Synchronous theme string lookup (Babel Fish) | Low | ❌ | Read-only. No secrets should be in theme store. |

| kernel_action_pressed | Synchronous input action poll (Babel Map) | Low | ❌ | Read-only. Does not expose OS-level input. |

Host Function Rules

  • Principle of least privilege. Don’t expose a host function unless a plugin genuinely needs it.
  • Every new host function gets a security review. Document: what can a malicious plugin do with this?
  • Tier-gate sensitive functions. Filesystem access → Tier 2+. Network → Tier 1 only.
  • Input validation on every call. Plugin-provided strings, IDs, and indices are untrusted input.
  • Rate limiting where applicable. Logging, UI prompts, event emission — all rate-limited.
  • Game Developer Host Functions

    Game developers can expose their own host functions to plugins. We provide guidelines:

  • Never expose raw file paths. Use asset IDs that resolve server-side.
  • Never expose network primitives. If a plugin needs external data, the game fetches it and provides it via events.
  • Never expose player credentials, tokens, or keys through any host function or event.
  • Document what each function exposes and at what trust tier it’s available.

  • Periodic Security Audits

    “We’re the ones writing the host functions — we’re our own biggest attack surface.”

    Quarterly Self-Audit Checklist

  • [ ] Host function review: List all kernel-exposed host functions. For each: is it still needed? What can a malicious plugin do with it? Can we reduce its scope?
  • [ ] Event schema review: Are any events carrying data that shouldn’t be broadly visible? Should any be restricted to specific trust tiers?
  • [ ] Capability budget review: Are the per-tier limits still appropriate? Have we seen plugins legitimately needing more? Have we seen abuse at current limits?
  • [ ] Dependency audit: Update wasmtime. Check for CVEs in sandbox runtime.
  • [ ] Automated scanner review: Are the publish-time checks catching real issues? Review false positive/negative rates.
  • [ ] Penetration test: Attempt to write a malicious plugin ourselves. Can we exfiltrate data? Crash the host? Escape the sandbox? Document findings.
  • Audit Log

    | Date | Auditor | Findings | Actions |

    |——|———|———-|———|

    | 2026-03-21 | Ada (autonomous) | All 9 host functions cataloged in VogonAuditBureau. kernel_log/kernel_print rate-limited. Sideloaded stdin warns. No High-risk functions found. event_emit/subscribe are Medium — Vogon Customs (DeclaredOnly) already mitigates. | Rate limiting implemented. /api/security/audit route added. Audit checklist baseline established. |


    Messaging Guidelines

    When communicating MM’s security to users, developers, or press:

    Do Say

  • “Plugins run in a hardware-enforced WASM sandbox”
  • “Plugins cannot access your filesystem, network, or OS APIs unless explicitly granted by the game”
  • “MM’s capability budget system limits what each plugin can do based on its trust level”
  • “We perform automated security scanning on all Milliways-published plugins”
  • “We conduct periodic security audits of our own host function surface”
  • Don’t Say

  • ~~”Mods can’t hack you”~~ — too absolute, invites counterexamples
  • ~~”100% secure”~~ — nothing is
  • ~~”Unhackable”~~ — never say this about anything, ever
  • ~~”Zero risk”~~ — there is always residual risk
  • The Honest Pitch

    *”Mostly Modular uses WebAssembly sandboxing to structurally prevent entire classes

    of mod security threats — like filesystem access, network exfiltration, and keylogging —

    that other engines can’t protect against. Combined with tiered trust levels and

    automated scanning, it’s the strongest mod security model in game engines today.

    No security system is perfect, which is why we also conduct regular audits and

    maintain a community reporting pipeline.”*


    *Planned for: Implementation alongside Spikes 9 (Milliways) and 11 (Steam Workshop).

    Audit process begins when host function API stabilizes (post-Spike 6).*