Choosing Deno Permission Flags for Secure Script Execution
A decision guide for granting Deno runtime permissions with granular allow‑lists, comparing them to --allow-all, and validating the chosen setup.
14 May 2026, 11:13 UTC

Decision: controlling Deno script permissions
When you need to run third‑party scripts or internal tools with Deno, the default sandbox blocks file, network, environment, and subprocess access. You must decide which capabilities to grant and how narrowly to scope them, balancing security with operational convenience.
Options comparison
| Option | What it grants | Typical use‑case |
|---|---|---|
| --allow-all (-A) | Full access to file system, network, environment, subprocesses, etc. | Local development or quick prototyping where security is not a concern. |
| Granular flags (e.g. --allow-read=/data, --allow-net=api.example.com) | Specific capabilities limited to the supplied allow‑list; omitted flags remain denied. | Production, CI, or any scenario where least‑privilege execution is required. |
| Runtime permission API (Deno.permissions.query/request) | Allows a script to check or request a permission at execution time, enabling graceful degradation or interactive prompts. | Tools that need to adapt when a permission is missing, but not suitable for unattended CI runs. |
Trade‑offs
- Security vs. convenience: --allow-all removes the sandbox entirely, eliminating Deno’s primary security benefit. Granular flags preserve the sandbox while still letting you enable only what is needed.
- CI suitability: Prompt‑based permission granting fails in non‑interactive environments; CI pipelines must declare flags explicitly or the script will abort with a PermissionDenied error.
- Subprocess inheritance: Spawned child processes via Deno.Command do not automatically inherit the parent’s granted permissions; they require their own --allow-run (or equivalent) and are otherwise outside Deno’s sandbox.
- Version sensitivity: The syntax for allow‑lists and the set of permission kinds have changed between Deno 1.x and 2.x. Verify flags against the exact Deno version you deploy.
Concrete implementation and validation
Example script
// check-permission.ts
import { readTextFile } from "https://deno.land/std@0.224.0/fs/read_text_file.ts";
async function main() {
try {
const content = await readTextFile("/data/message.txt");
console.log("File read successfully:", content);
} catch (err) {
if (err instanceof Deno.errors.PermissionDenied) {
console.error("Permission denied while reading file.");
} else {
console.error("Unexpected error:", err);
}
Deno.exit(1);
}
}
main();
This script attempts to read a file at /data/message.txt. Without the proper flag it will fail with a PermissionDenied error.
Declaring permissions via deno.json
{
"tasks": {
"start": {
"command": "run check-permission.ts",
"permissions": {
"read": "/data",
"env": false,
"net": false,
"run": false
}
}
}
}
Running deno task start will invoke the script with exactly the permissions declared in the task: read access limited to the /data directory, and no network, environment, or subprocess privileges.
Validation steps
- Confirm denial without the flag:
deno run check-permission.ts
Expect output similar toPermission denied while reading file.and a non‑zero exit code. - Confirm success with the scoped flag:
deno run --allow-read=/data check-permission.ts
Expect the script to print the file’s contents and exit with code 0. - Inspect effective permissions at runtime:
Create a small helper:
// perm-check.ts
console.log(Deno.permissions.querySync({ name: "read" }));
console.log(Deno.permissions.querySync({ name: "net" }));
Run it under different flag sets and observe the returned state ("granted", "prompt", or "denied"). This verifies that the CLI flags translate into the expected runtime permission state.
Limitations and practical checks
- Granular allow‑lists are version‑specific; consult the Deno release notes for the version you use (e.g., Deno 2.0 uses
--allow-read=/pathwhile older 1.x releases accepted--allow-readwithout a value for full access). - The
--allow-runflag effectively bypasses much of the sandbox because spawned processes are not constrained by Deno’s permission system; review any script that shells out carefully. - Prompt‑based permission granting (
Deno.permissions.request) should be avoided in CI or containerized builds; instead, rely on explicit flags or task configurations. - To verify that a deno.json task reproduces the raw CLI behavior, compare the output of
deno task startwith the manually constructeddeno runcommand that includes the same flags.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.