Deno's permission system is one of its core security features, adopting a "default deny" security model. This design ensures that code cannot access sensitive resources without explicit authorization.
Permission System Overview
Deno's security model is based on the principle of least privilege. By default, scripts have no permissions, and all resource access requires explicit authorization.
Permission Types
1. File System Permissions
bash# Allow reading all files deno run --allow-read script.ts # Allow reading specific directories deno run --allow-read=/app,/data script.ts # Allow writing all files deno run --allow-write script.ts # Allow writing specific directories deno run --allow-write=/tmp script.ts # Allow both read and write deno run --allow-read --allow-write script.ts
2. Network Permissions
bash# Allow all network access deno run --allow-net script.ts # Allow access to specific domains deno run --allow-net=api.example.com script.ts # Allow access to specific ports deno run --allow-net=:8080 script.ts # Allow access to specific IP and port deno run --allow-net=127.0.0.1:8000 script.ts
3. Environment Variable Permissions
bash# Allow access to all environment variables deno run --allow-env script.ts # Allow access to specific environment variables deno run --allow-env=API_KEY,DATABASE_URL script.ts
4. Subprocess Permissions
bash# Allow creating subprocesses deno run --allow-run script.ts # Allow running specific commands deno run --allow-run=git,npm script.ts
5. System Information Permissions
bash# Allow getting system information deno run --allow-sys script.ts # Allow getting specific system information deno run --allow-sys=hostname,osRelease,osVersion script.ts
6. High-Resolution Time Permissions
bash# Allow access to high-resolution time deno run --allow-hrtime script.ts
7. FFI (Foreign Function Interface) Permissions
bash# Allow loading dynamic libraries deno run --allow-ffi script.ts # Allow loading specific libraries deno run --allow-ffi=/path/to/library.so script.ts
Combining Permissions
bash# Combine multiple permissions deno run --allow-read --allow-write --allow-net --allow-env=API_KEY app.ts # Use --allow-all to grant all permissions (not recommended for production) deno run --allow-all app.ts
Permission Checks in Code
Deno provides APIs to check current permissions:
typescript// Check if read permission is granted const canRead = await Deno.permissions.query({ name: "read", path: "/tmp" }); console.log(canRead.state); // "granted", "prompt", or "denied" // Check if network permission is granted const canAccessNet = await Deno.permissions.query({ name: "net" }); console.log(canAccessNet.state); // Request permission const netPermission = await Deno.permissions.request({ name: "net" }); if (netPermission.state === "granted") { console.log("Network access granted"); }
Permission Prompt Mode
Deno supports interactive permission prompts:
bash# Use --prompt permission flag deno run --prompt=net script.ts
When a script attempts to access resources requiring permissions, Deno will prompt the user for authorization.
Practical Application Examples
1. File Server
typescript// file-server.ts import { serve } from "https://deno.land/std@0.208.0/http/server.ts"; const handler = async (req: Request): Promise<Response> => { const url = new URL(req.url); const filePath = `.${url.pathname}`; try { const content = await Deno.readFile(filePath); return new Response(content); } catch { return new Response("File not found", { status: 404 }); } }; await serve(handler, { port: 8000 });
Run:
bashdeno run --allow-read --allow-net file-server.ts
2. API Client
typescript// api-client.ts const API_KEY = Deno.env.get("API_KEY"); if (!API_KEY) { throw new Error("API_KEY environment variable not set"); } const response = await fetch("https://api.example.com/data", { headers: { "Authorization": `Bearer ${API_KEY}`, }, }); const data = await response.json(); console.log(data);
Run:
bashdeno run --allow-net --allow-env=API_KEY api-client.ts
3. File Processing Tool
typescript// file-processor.ts const inputFile = Deno.args[0]; const outputFile = Deno.args[1]; const content = await Deno.readTextFile(inputFile); const processed = content.toUpperCase(); await Deno.writeTextFile(outputFile, processed); console.log(`Processed ${inputFile} to ${outputFile}`);
Run:
bashdeno run --allow-read --allow-write file-processor.ts input.txt output.txt
Permission Best Practices
- Principle of least privilege: Only grant necessary permissions
- Specify resources explicitly: Use specific paths and domains, not wildcards
- Avoid --allow-all: Never use in production environments
- Document permission requirements: Document required permissions in README
- Use permission checks: Check permissions in code and provide friendly error messages
- Environment isolation: Run untrusted code in containers or sandboxes
Security Advantages
Deno's permission system provides the following security advantages:
- Prevent data leaks: Cannot read sensitive files without authorization
- Prevent system damage: Cannot write or delete files without authorization
- Prevent network attacks: Cannot make network requests without authorization
- Prevent environment leaks: Cannot access environment variables without authorization
- Prevent command injection: Cannot execute system commands without authorization
- Auditable: All permission usage is explicit, facilitating auditing
Comparison with Node.js
| Feature | Deno | Node.js |
|---|---|---|
| Default permissions | No permissions | Full access |
| Permission control | Command line flags | No built-in mechanism |
| Security model | Default deny | Default allow |
| Permission granularity | Fine-grained control | No control |
| Audit capability | Explicit permissions | Implicit permissions |
Deno's permission system provides enterprise-level security for JavaScript/TypeScript runtimes, making it particularly suitable for handling sensitive data and running untrusted code.