Plugin Security

The plugin system provides several security features to harden plugins in production environments. All security settings are off by default for backward compatibility.

Fuel Limits

Fuel limits restrict how many WASM instructions a single plugin call can execute. This prevents infinite loops or excessive computation from blocking the server:

plugins:
  enabled: true
  fuel_limit: 1000000    # ~100ms of execution per call

When a plugin exceeds its fuel budget, the call returns an error and the plugin’s output is discarded. The server continues normally using the original content.

To calibrate the limit, run with debug logging enabled:

RUST_LOG=accent=debug accent serve

Each plugin call logs its fuel consumption:

DEBUG Plugin 'syntax-highlight' on_render consumed 42317 fuel units

Compilation Caching

Compilation caching stores compiled WASM modules on disk, reducing startup time on subsequent runs:

plugins:
  compilation_cache: .cache/plugins

The directory is created automatically. If creation fails, the server continues without caching.

Pre-compilation

AOT (ahead-of-time) pre-compilation compiles plugins to native code at startup rather than JIT-compiling on first use:

plugins:
  precompile: true

This trades slower startup for faster first-call latency. Best combined with compilation_cache so the compiled module is cached for subsequent startups.

API Version Compatibility

Each plugin declares the host api_version it targets in its plugin.toml. At load time the host checks that version against the supported range it advertises: a minimum supported version and the newest version it implements. Advertising a range, rather than a single pinned version, lets a plugin built against an older-but-still-supported API keep loading — the previous API generation keeps working until support for it is explicitly retired.

A plugin is accepted when its api_version falls within the supported range, using the semver 0.x convention (below 1.0 the minor is the breaking unit; at and above 1.0 the major is). A plugin outside the range is skipped with an actionable warning:

  • Newer than the host implements — upgrade Accent to a build that provides the required API.
  • Older than the supported floor — rebuild the plugin against a still-supported API.
  • Not valid semver — fix the api_version string (for example, "0.1.0").

Skipping incompatible plugins prevents a plugin built for a newer API from loading and producing incorrect results, while keeping older-but-supported plugins working.

Filesystem Access

By default, plugins run in a fully sandboxed WASI environment with no access to the host filesystem. Plugins that need to read files (e.g., EXIF metadata extraction, content indexing) can opt in to filesystem access.

This requires two things:

  1. The plugin declares requires_fs = true in its plugin.toml
  2. The site operator configures which paths are available in config.yaml

Plugin Side

Add requires_fs = true to the [plugin] section:

[plugin]
name = "exif-reader"
version = "0.1.0"
api_version = "0.1.0"
requires_fs = true

Plugins without this field (or with requires_fs = false) receive no filesystem paths, regardless of what the site operator configures.

Site Operator Side

Define allowed_paths in config.yaml to map virtual paths (as seen inside the WASM module) to host filesystem paths:

plugins:
  enabled: true
  allowed_paths:
    /content: "ro:./site/content"
    /media: "ro:./site/media"
    /data: ./site/data
  • Keys are virtual paths visible inside the plugin (e.g., /content)
  • Values are host filesystem paths (e.g., ./site/content)
  • Prefix a host path with ro: to grant read-only access (recommended for content and media directories)
  • Paths without the ro: prefix grant read-write access

If a plugin declares requires_fs but no allowed_paths are configured, a warning is logged and the plugin runs without filesystem access.

Behavior Summary

requires_fsallowed_paths configuredResult
false or omittedanyNo paths granted (fully sandboxed)
truenon-emptyPaths granted to the plugin
trueempty or missingWarning logged, no paths granted