denoland/deno
The blast radius concentrates in three places: the permission system (an 11.7k-line file that every capability check funnels through), the extension ordering list in `runtime/worker.rs` (silently snapshot-coupled across four files), and the many `unsafe { std::env::set_var(...) }` calls in startup that are only sound because they run before any thread is spawned. Security-sensitive paths include FFI `dlopen`, subprocess spawn with LD_PRELOAD-style env filtering, the permission broker's IPC socket, the Deno Deploy keyring token, the runtime-fetched deploy CLI executed with `allow_all`, and the `node` shim that mutates the process `PATH`. Several performance-motivated lazy-loading decisions (lazy node polyfills, hoisted `registerDeclarativeServer` guard) are fragile in the sense that they encode non-obvious invariants in comments rather than tests.
- `deno deploy` executes code fetched from JSR at runtime with `PermissionsContainer::allow_all` — the version is chosen by `resolve_deploy_cli_version` from `@deno/deploy/meta.json`, so a compromised or unexpected JSR publish would run fully privileged on the user's machine.
- Subprocess spawn blocks a real privilege-escalation vector: `check_run_permission` refuses to spawn with any `LD_*`/`DYLD_*` env var set unless `--allow-run` is granted for all, because those allow arbitrary code execution via LD_PRELOAD.
- `op_ffi_load` gates on `check_ffi_partial_with_path` and then calls `Library::open` on the (possibly denort-remapped) path — once loaded, the dynamic library runs with full process privileges outside the permission model.
- The permission prompter defends against terminal spoofing by escaping bidi and zero-width Unicode formatting controls (U+202E RTL Override, U+2066 isolates, U+200B ZWSP, …) that would otherwise let a malicious path forge the prompt label — the Trojan-Source vector.
- `DENO_PERMISSION_BROKER_PATH` connects permission decisions to an external process over an IPC pipe; a connection failure calls `std::process::exit(87)` with a TODO noting the exit code was randomly chosen and undocumented.
- The Deno Deploy token is stored in the OS keyring under service 'Deno Deploy Token' / user 'Deno Deploy' and is read during tunnel setup; on an `Unauthorized` response the code deletes the credential and re-runs interactive auth.
- Startup performs multiple `unsafe { std::env::set_var(...) }` calls — `DENO_CONNECTED`, `DENO_COVERAGE_DIR`, `DENO_DEPLOY_CLI_SANDBOX`, `PATH`, and every key/value the tunnel server returns in its metadata — each justified only by a comment asserting single-threadedness; adding a thread earlier in startup would make these unsound.
- The tunnel injects arbitrary server-supplied environment variables into the process: `for (k, v) in metadata.env { std::env::set_var(k, v) }` with no allowlist, so the tunnel endpoint is effectively trusted to configure the local process.
- The `node` PATH shim writes a symlink (Unix) or `.exe`-named shim (Windows) into DENO_DIR and prepends that directory to `PATH`, meaning any process spawned by user code — not just Deno — resolves `node` to the Deno binary; correctness depends on the scan finding no real Node first.
- The extension registration order in `common_extensions` is a cross-file invariant with no automated check: a comment says it must be kept in sync with `runtime/worker.rs`, `runtime/web_worker.rs`, `runtime/snapshot_info.rs`, and `runtime/snapshot.rs`, and a mismatch surfaces as snapshot corruption rather than a compile error.
- `ext/node`'s lazy/eager split is a hand-maintained list with a documented trap: an explicit `esm` entry that no eager module imports 'would land in the module map unevaluated and fail snapshot validation with NonEvaluatedModules'.
- `runtime/permissions/lib.rs` is a single 11,756-line module owning every descriptor type, the allow/deny/prompt state machine, and `PermissionsContainer` — the highest-blast-radius file in the repo for security regressions.
- Dead/legacy surfaces still occupy the dispatch table: `DenoSubcommand::Vendor` exists solely to print a removal message and exit 1, and `--unstable` is accepted but warns it was removed in Deno 2.0 with a TODO to hard-error in v2.5.
- The `registerDeclarativeServer` fast path in `99_main.js` encodes a performance optimisation as a behavioural guard — it skips loading ~430 KB of serve/streams modules unless the default export has an own `fetch` — and the comment explicitly notes `dflt == null` must still call through to preserve the existing TypeError.
- `deno test --coverage` does `let _ = std::fs::remove_dir_all(coverage_dir)` on a user-supplied path before creating it; the deletion is unconditional (outside the raw-data-only case) and silently ignores errors.
- The `NodeCommand` shell command silently rewrites `node script.js` inside `deno task` to `deno run -A --unstable-bare-node-builtins --unstable-detect-cjs --unstable-sloppy-imports --unstable-unsafe-proto script.js` — granting all permissions and four unstable flags that the task author never wrote.