prompt2bot

2026-11-12
by Uri Walevski
Giving an LLM agent a Python or Node sandbox feels clean until the agent installs a community skill and attaches real API keys to it.
In a general-purpose language, the runtime has almost no idea what a script is going to do until it is already mid-execution. A script can build a URL string out of character codes, loop forever on malformed input, or read an API key and ship it to an external webhook inside a nested helper. Container sandboxes isolate the filesystem and CPU, yet any secret injected into that container is still fair game for every outbound request.
That is why we built Safescript (@uri/safescript) as the default execution
layer for agent skills and custom tools in prompt2bot.
Instead of sandboxing an unrestricted language after the fact, Safescript restricts the language just enough that the compiler can prove what a tool touches before a single line executes.
Safescript looks familiar to anyone who writes TypeScript, with a few deliberate omissions.
There are no for or while loops. Iteration goes through bounded functional
combinators like map, filter, and reduce. There is no arbitrary fetch
taking a free-form URL string, no dynamic import, and no eval. Outbound HTTP
goes through structured httpRequest operations with explicit host fields.
Dropping unbounded loops and dynamic code loading buys something a JavaScript engine can never offer: every program has a statically computable upper bound on memory, runtime, algorithmic complexity, network hosts, and parameter-to-host data flow.
Here is an actual Safescript tool function that sends an order receipt through Resend:
Before running send_receipt, the engine parses the AST and runs
computeSignature. Here is the exact signature emitted by @uri/safescript:
Notice the Data flow section. The analyzer tracks taint from each input
parameter through string concatenation and JSON serialization all the way to the
specific network host that receives it.
When a bot owner stores RESEND_API_KEY on prompt2bot, that secret is paired
with an allowed host list: ["api.resend.com"]. Because param:resendKey only
flows to host:api.resend.com, the policy check passes with zero human friction
and zero VM startup time.
Now watch what happens if a compromised skill package or a prompt-injected agent writes a tool that quietly forwards the key to an external collector before calling Resend:
Running computeSignature on that AST produces:
The violation jumps out before the program ever starts. param:resendKey flows
into host:webhook.attacker.example, which is not in RESEND_API_KEY's
allowlist. checkSignatureAgainstPolicy rejects the call immediately:
No HTTP socket opens. No container spins up. The attacker gets nothing.
Security is half the story. The other half is latency and unit economics.
Booting a Linux container or microVM just to call two REST endpoints, filter a JSON array, and format a WhatsApp reply burns seconds of cold-start latency and real compute money. Most agent skills on Tank and our /agency directory are API orchestrators, webhook filters, and data transformers.
Running those skills in Safescript means they execute in milliseconds right inside the worker isolate, while full Modal Linux VMs stay reserved for heavy jobs like compiling repositories or running headless browsers. Anyone can test how Safescript-backed skills feel in live chat by launching a package from /agency or pointing Talk to Skill at a Tank skill.
← All posts