Deno and Bun audit patterns
TL;DR: Deno’s capability-based permission model (
--allow-net,--allow-read) is a real defence — but only when actually used. Most production Deno runs with--allow-allbecause devs don’t audit permission scope. Bun is permissive by default (Node-compat). Audit: capability flags, npm-compat surface (Bun inherits npm risks), Deno’s URL-based imports (supply chain via attacker-controlled URL), and KV/Deploy specifics.
Deno
Permission model
Deno requires explicit capability flags at runtime. Without them, the program can’t read files, network, env, or spawn subprocesses. This is the strongest production runtime sandbox in mainstream JS.
Bug patterns:
1. --allow-all in production
Most deploys do this because anything less requires devs to enumerate permissions. Audit: deno run invocations, Dockerfile CMD, deno.json tasks.
- Fix: minimum-viable permission flags.
--allow-net=api.example.com --allow-read=./data.
2. Over-broad --allow-net
--allow-net (no value) = all network. --allow-net=8.8.8.8,api.example.com = specific only. Common slip: dev permission level promoted to prod.
3. URL-imported modules
import { x } from "https://deno.land/x/something@v1.2.3/mod.ts". Import URL is the supply chain.
deno.land/xmirrors GitHub but versioning is tag-based; tag could be force-pushed.import_map.jsonlets you alias URLs; if attacker controls the map, supply-chain hijack.deno.lockpins integrity hash — verify it’s committed and CI checks it.
4. JSR (Deno’s package registry) supply chain
jsr:@scope/pkg@version— newer; scoped + 2FA required for top packages.- Still subject to typosquat at the scope level.
5. Env var leak via Deno.env
--allow-env(no value) exposes all env. Use--allow-env=PATH,API_KEYto limit.- Deno KV with
Deno.openKv()requires--unstable-kvhistorically; now stable but still scope-relevant.
6. Subprocess exec
Deno.Commandrequires--allow-run. Without it, blocked. With it (no value), all binaries; with value, specific paths only.--allow-run=git,catis a meaningful restriction.
7. FFI loaded shared libs
Deno.dlopenrequires--allow-ffi. Loading attacker-controlled.so= RCE outside the JS sandbox.
8. Deno Deploy specifics
- KV access scoped by deploy.
- Cron jobs (
Deno.cron) run with the same permissions as the main worker. - Edge runs at Cloudflare-like global presence; cold start similar surface.
Bun
Bun is Node-compatible by default with extra speed. No capability model.
1. Audit npm-compat surface
bun installuses npm registry; same risks as npm-postinstall-and-typosquat-audit.- Bun runs
postinstallscripts;--ignore-scriptsis the opt-out.
2. bun:sqlite and bun:test no isolation
bun:sqliteruns in-process — same trust as the host code.bun:testhas no sandboxing for tested code.
3. Bun.spawn, Bun.write, Bun.serve — Node-equivalent risks
- Same shell-concat, path-traversal, SSRF concerns as Node.
- No additional flags to limit; relies on app-level checks.
4. Native modules
- Bun supports Node-compat native modules. Same supply-chain surface but Bun resolves and builds differently — audit
bun.lockb(binary lock; less human-reviewable thanpackage-lock.json).
5. Bun’s HTTP server
Bun.serve({ fetch })is a clean primitive. Audit handler for same web-app surface as any Node server.
6. Workers via Worker
- Web-Worker compat exists; not full Node-isolate. Cross-worker state via SharedArrayBuffer possible.
Audit checklist
Deno
1
2
3
4
5
6
7
8
# Find every deno invocation
rg -n 'deno (run|task|test|deploy|cache)' .
# Check permission flags
rg -n '\-\-allow-(net|read|write|env|run|ffi|hrtime)' .
# Find URL imports
rg -n 'from\s+["\x27]https?://' .
# Verify lock file present
ls -la deno.lock
Bun
1
2
3
4
5
6
7
8
# Lockfile present and binary
ls -la bun.lockb
# Scripts in package.json
jq '.scripts' package.json
# postinstall enumeration
jq '.dependencies, .devDependencies' package.json
# Check ignore-scripts in CI
grep -n 'bun install' .github/workflows/*.yml
Hardening
Deno
- Lowest-viable permission flags in prod.
deno.lockcommitted; CI enforces.import_map.jsonreviewed; URLs from trusted sources only.- Prefer JSR over
deno.land/xfor new code. Deno.permissions.query()runtime check before sensitive ops.
Bun
bun install --ignore-scriptsin CI for production builds.- Lock to specific Bun version (
bun-versionfile). - Same secret-management discipline as Node.
- Snyk/Socket scan
package.jsondeps.