Whitelist Capability Config
- title
- Whitelist Capability Config
- type
- concept
- summary
- Embedded-scripting design where the config language starts with zero capabilities and the host registers each one explicitly, instead of starting from a full language and removing dangerous bits
- tags
- config-languages, embedded-scripting, capability-security
- created
- 2026-05-11
- updated
- 2026-05-11
A pattern for embedded config or scripting where the host application declares, capability by capability, what the config author is allowed to invoke. The contrast is with the blacklist approach common to embedded Lua and Python: load the full language, then try to remove os, io, require, and hope nothing else escalates.
The ryelang-whitelist-config post puts it sharply: "blacklisting is preventing known dangers, but there are always unknown unknowns, and you can't prevent what you don't know you should." The unknown-unknowns argument is the same one that motivates default-deny network policies and capability-based OS designs.
The two failure modes the pattern is reacting to
Bottom-up creep. Configs that started as INI-style key-value end up reinventing a language. YAML grew template engines (Helm, Ansible), Nginx added if, Terraform invented HCL with workarounds like dynamic blocks for missing if. The hidden language is informal, often inconsistent, and acquires a parser-plus-templater-plus-evaluator pipeline nobody designed end-to-end. Greenspun's tenth rule, applied to config.
Top-down embedding. "Just embed Lua." The config can now do everything, including os.execute and io.open. The mitigation is to remove dangerous bindings before evaluating untrusted code. This requires knowing the full surface of what's dangerous, which you don't.
The whitelist alternative is to pick a language that doesn't include those forms in the first place, and to ship the host with a per-feature registration API.
Two ways to implement it
Hard-coded restricted dialect. Starlark is the canonical example: Python-shaped, no recursion, no while, no I/O. The restriction set is fixed at the language level. Modules are gated by import lists. You can refuse to register a module, but you can't refuse just one builtin inside it.
No-reserved-form host language. rye-lang is the example the post is making. The base evaluator can parse syntax and bind names, and that's it. if, fn, +, * are all functions in the standard library that you choose to register. You can grant _+ without _*, or if without loop. The granularity is per-word.
The tradeoff is maturity vs. expressiveness: Starlark is production-tested at Bazel scale; Rye's approach is a research-grade exploration with a smaller blast radius per granted capability.
What you still need on top
Capability whitelisting controls which words exist. It does not control how much work the evaluator does. Both languages also expose execution caps โ call-stack depth, total operation count, wall-clock time โ to turn runaway code into errors instead of hangs.
It also doesn't bound the host-side effects of any builtin you register. The closing warning of ryelang-whitelist-config is explicit: "this is capability control, not a security sandbox." Rye runs in the host process; if you register read-file, the config can read any file the host can read. For untrusted input you need a real boundary on top โ process isolation, seccomp, or a separate VM. See sandboxing-ai-agents for the recurring four-layer model.
Where it shows up
- Config-as-code where the author is friendly but you want to keep the expressive surface small (the Rye article's framing)
- Plugin systems where third-party authors get a fixed set of host primitives and nothing else
- AI-agent action languages where each new capability is a deliberate decision (loose analogue to mcp-vs-skills capability scopes)
- Game scripting where designers get a vocabulary curated by engineers
Related
- ryelang-whitelist-config โ the article that lays out the pattern in six steps
- rye-lang โ the example implementation
- no-silver-bullet โ config-language accidental complexity as a recurring shape
- sandboxing-ai-agents โ the layer above capability control, when input is hostile