Seatbelt Deno for macOS

Divy Srivastava

7 February 2025

Introduction

https://github.com/littledivy/sh-deno

Overcome the technical limitations of Deno permission system by wrapping it with macOS’s native sanboxing primitives.

Design

On macOS versions 10.5 (Leopard) and later, Apple introduced a sandboxing mechanism called Seatbelt. Individual applications can restrict the resources they can access by specifying a set of rules in a configuration file. This is similar to Deno’s permission system, but with more fine-grained control.

Example seatbelt configuration:

; Run as `sandbox-exec -f script.sb <exe>`
(version 1)
; deny everything by default
(deny default)

(debug deny)

(import "bsd.sb")

(allow file-read*
  ; allow reading files in Downloads folder
  (subpath "/Users/divy/Downloads")
)

sh-deno works by mapping Deno’s permission configuration to Apple’s seatbelt sandboxing mechanism. This allows you to run Deno scripts with fine-grained control over the resources they can access.

The deno equivalent of the above seatbelt configuration would be:

deno run --allow-read=/Users/divy/Downloads script.ts

sh-deno automatically generates the seatbelt configuration from permission flags passed to it, essentially wrapping the Deno invocation with seatbelt.

sh-deno --allow-read=/Users/divy/Downloads script.ts

Enhanced security

Deno’s permission system by default doesn’t protect against unauthorized access in native code like FFI libraries, child processes, etc. This is where seatbelt shines as it can restrict access to system calls and other low-level resources that Deno can’t.

Here’s an example with FFI:

// sample FFI dylib

static void __attribute__((constructor)) 
initialize(void)
{
  fopen("/etc/passwd", "r"); // blocked by sh-deno
}
sh-deno --allow-read=. --allow-ffi main.ts

Custom profiles

You can also emit the profile generated by sh-deno and run it manually via sandbox-exec.

sh-deno --emit-profile \
  --allow-read=. --allow-ffi > sandbox.sb

sandbox-exec -f sandbox.sb \
  deno run --allow-read=. --allow-ffi main.ts

Limitations

Additional resources

https://reverse.put.as/wp-content/uploads/2011/09/Apple-Sandbox-Guide-v1.0.pdf

https://www.chromium.org/developers/design-documents/sandbox/osx-sandboxing-design/

ls /System/Library/Sandbox/Profiles