On this page
Security and permissions
Deno is secure by default. Unless you specifically enable it, a program run withDeno has no access to sensitive APIs, such as file system access, networkconnectivity, or environment access. You must explicitly grant access to theseresources with command line flags or with a runtime permission prompt. This is amajor difference from Node, where dependencies are automatically granted fullaccess to all system I/O, potentially introducing hidden vulnerabilities intoyour project.
Before using Deno to run completely untrusted code, read thesection on executing untrusted code below.
Key PrinciplesJump to heading
Before diving into the specifics of permissions, it's important to understandthe key principles of Deno's security model:
- No access to I/O by default: Code executing in a Deno runtime has noaccess to read or write arbitrary files on the file system, to make networkrequests or open network listeners, to access environment variables, or tospawn subprocesses.
- No limits on the execution of code at the same privilege level: Denoallows the execution of any code (JS/TS/Wasm) via multiple means, including
eval
,new Function
, dynamic imports and web workers at the same privilegelevel with little restriction as to where the code originates (network, npm,JSR, etc). - Multiple invocations of the same application can share data: Deno providesa mechanism for multiple invocations of the same application to share data,through built in caching and KV storage APIs. Different applications can notsee each other's data.
- All code executing on the same thread shares the same privilege level: Allcode executing on the same thread shares the same privilege level. It is notpossible for different modules to have different privilege levels within thesame thread.
- Code can not escalate its privileges without user consent: Code executingin a Deno runtime can not escalate its privileges without the user agreeingexplicitly to an escalation via interactive prompt or a invocation time flag.
- The initial static module graph can import local files withoutrestrictions: All files that are imported in the initial static module graphcan be imported without restrictions, so even if an explicit read permissionis not granted for that file. This does not apply to any dynamic moduleimports.
These key principles are designed to provide an environment where a user canexecute code with minimal risk of harm to the host machine or network. Thesecurity model is designed to be simple to understand and to provide a clearseparation of concerns between the runtime and the code executing within it. Thesecurity model is enforced by the Deno runtime, and is not dependent on theunderlying operating system.
PermissionsJump to heading
By default, access to most system I/O is denied. There are some I/O operationsthat are allowed in a limited capacity, even by default. These are describedbelow.
To enable these operations, the user must explicitly grant permission to theDeno runtime. This is done by passing the--allow-read
,--allow-write
,--allow-net
,--allow-env
, and--allow-run
flags to thedeno
command.
During execution of a script, a user can also explicitly grant permission tospecific files, directories, network addresses, environment variables, andsubprocesses when prompted by the runtime. Prompts are not shown ifstdout/stderr are not a TTY, or when the--no-prompt
flag is passed to thedeno
command.
Users can also explicitly disallow access to specific resources by using the--deny-read
,--deny-write
,--deny-net
,--deny-env
, and--deny-run
flags. These flags take precedence over the allow flags. For example, if youallow network access but deny access to a specific domain, the deny flag willtake precedence.
Deno also provides a--allow-all
flag that grants all permissions to thescript. Thisdisables the security sandbox entirely, and should be used withcaution. The--allow-all
has the same security properties as running a scriptin Node.js (ie none).
Definition:-A, --allow-all
deno run-A script.tsdeno run --allow-all script.ts
By default, Deno will not generate a stack trace for permission requests as itcomes with a hit to performance. Users can enable stack traces with theDENO_TRACE_PERMISSIONS
environment variable to1
.
Deno can also generate an audit log of all accessed permissions; this can beachieved using theDENO_AUDIT_PERMISSIONS
environment variable to a path. Thisworks regardless if permissions are allowed or not. The output is in JSONLformat, where each line is an object with the following keys:
v
: the version of the formatdatetime
: when the permission was accessed, in RFC 3339 formatpermission
: the name of the permissionvalue
: the value that the permission was accessed with, ornull
if it wasaccessed with no value
A schema for this can be foundhere.
In addition, this env var can be combined with the above-mentionedDENO_TRACE_PERMISSIONS
, which then adds a newstack
field to the entrieswhich is an array contain all the stack trace frames.
Configuration fileJump to heading
Deno supports storing permissions in the deno.json/deno.jsonc file. Read moreunderconfiguration.
File system accessJump to heading
By default, executing code can not read or write arbitrary files on the filesystem. This includes listing the contents of directories, checking for theexistence of a given file, and opening or connecting to Unix sockets.
Access to read files is granted using the--allow-read
(or-R
) flag, andaccess to write files is granted using the--allow-write
(or-W
) flag. Theseflags can be specified with a list of paths to allow access to specific files ordirectories and any subdirectories in them.
Definition:--allow-read[=<PATH>...]
or-R[=<PATH>...]
# Allow all reads from file systemdeno run-R script.ts# ordeno run --allow-read script.ts# Allow reads from file foo.txt and bar.txt onlydeno run --allow-read=foo.txt,bar.txt script.ts# Allow reads from any file in any subdirectory of ./node_modulesdeno run --allow-read=node_modules script.ts
Definition:--deny-read[=<PATH>...]
# Allow reading files in /etc but disallow reading /etc/hostsdeno run --allow-read=/etc --deny-read=/etc/hosts script.ts# Deny all read access to disk, disabling permission prompts for reads.deno run --deny-read script.ts
Definition:--allow-write[=<PATH>...]
or-W[=<PATH>...]
# Allow all writes to file systemdeno run-W script.ts# ordeno run --allow-write script.ts# Allow writes to file foo.txt and bar.txt onlydeno run --allow-write=foo.txt,bar.txt script.ts
Definition:--deny-write[=<PATH>...]
# Allow reading files in current working directory# but disallow writing to ./secrets directory.deno run --allow-write=./ --deny-write=./secrets script.ts# Deny all write access to disk, disabling permission prompts.deno run --deny-write script.ts
Some APIs in Deno are implemented using file system operations under the hood,even though they do not provide direct read/write access to specific files.These APIs read and write to disk but do not require any explicit read/writepermissions. Some examples of these APIs are:
localStorage
- Deno KV
caches
Blob
Because these APIs are implemented using file system operations, users can usethem to consume file system resources like storage space, even if they do nothave direct access to the file system.
During module loading, Deno can load files from disk. This sometimes requiresexplicit permissions, and sometimes is allowed by default:
- All files that are imported from the entrypoint module in a way that they canbe statically analyzed are allowed to be read by default. This includes static
import
statements and dynamicimport()
calls where the argument is astring literal that points to a specific file or a directory of files. Thefull list of files that are in this list can be printed usingdeno info <entrypoint>
. - Files that are dynamically imported in a way that can not be staticallyanalyzed require runtime read permissions.
- Files inside of a
node_modules/
directory are allowed to be read by default.
When fetching modules from the network, or when transpiling code from TypeScriptto JavaScript, Deno uses the file system as a cache. This means that file systemresources like storage space can be consumed by Deno even if the user has notexplicitly granted read/write permissions.
Network accessJump to heading
By default, executing code can not make network requests, open network listenersor perform DNS resolution. This includes making HTTP requests, opening TCP/UDPsockets, and listening for incoming connections on TCP or UDP.
Network access is granted using the--allow-net
flag. This flag can bespecified with a list of IP addresses or hostnames to allow access to specificnetwork addresses.
Definition:--allow-net[=<IP_OR_HOSTNAME>...]
or-N[=<IP_OR_HOSTNAME>...]
# Allow network accessdeno run-N script.ts# ordeno run --allow-net script.ts# Allow network access to github.com and jsr.iodeno run --allow-net=github.com,jsr.io script.ts# A hostname at port 80:deno run --allow-net=example.com:80 script.ts# An IPv4 address on port 443deno run --allow-net=1.1.1.1:443 script.ts# An IPv6 address, all ports alloweddeno run --allow-net=[2606:4700:4700::1111] script.ts
Definition:--deny-net[=<IP_OR_HOSTNAME>...]
# Allow access to network, but deny access# to github.com and jsr.iodeno run --allow-net --deny-net=github.com,jsr.io script.ts# Deny all network access, disabling permission prompts.deno run --deny-net script.ts
During module loading, Deno can load modules from the network. By default Denoallows loading modules from the following locations using both static anddynamic imports, without requiring explicit network access:
https://deno.land/
https://jsr.io/
https://esm.sh/
https://raw.githubusercontent.com
https://gist.githubusercontent.com
These locations are trusted "public good" registries that are not expected toenable data exfiltration through URL paths. You can add more trusted registriesusing the--allow-import
flag.
In addition Deno allows importing any NPM package throughnpm:
specifiers.
Deno also sends requests tohttps://dl.deno.land/
at most once a day to checkfor updates to the Deno CLI. This can be disabled usingDENO_NO_UPDATE_CHECK=1
environment var.
Environment variablesJump to heading
By default, executing code can not read or write environment variables. Thisincludes reading environment variables, and setting new values.
Access to environment variables is granted using the--allow-env
flag. Thisflag can be specified with a list of environment variables to allow access tospecific environment variables. Starting with Deno v2.1, you can now specifysuffix wildcards to allow “scoped” access to environmental variables.
Definition:--allow-env[=<VARIABLE_NAME>...]
or-E[=<VARIABLE_NAME>...]
# Allow access to all environment variablesdeno run-E script.ts# ordeno run --allow-env script.ts# Allow HOME and FOO environment variablesdeno run --allow-env=HOME,FOO script.ts# Allow access to all environment variables starting with AWS_deno run --allow-env="AWS_*" script.ts
Definition:--deny-env[=<VARIABLE_NAME>...]
# Allow all environment variables except# AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.deno run\ --allow-env\ --deny-env=AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY\ script.ts# Deny all access to env variables, disabling permission prompts.deno run --deny-env script.ts
Note for Windows users: environment variables are case insensitive on Windows,so Deno also matches them case insensitively (on Windows only).
Deno reads certain environment variables on startup, such asDENO_DIR
andNO_COLOR
(see the full list).
The value of theNO_COLOR
environment variable is visible to all code runningin the Deno runtime, regardless of whether the code has been granted permissionto read environment variables.
System InformationJump to heading
By default, executing code can not access system information, such as theoperating system release, system uptime, load average, network interfaces, andsystem memory information.
Access to system information is granted using the--allow-sys
flag. This flagcan be specified with a list of allowed interfaces from the following list:hostname
,osRelease
,osUptime
,loadavg
,networkInterfaces
,systemMemoryInfo
,uid
, andgid
. These strings map to functions in theDeno
namespace that provide OS info, likeDeno.systemMemoryInfo.
Definition:--allow-sys[=<API_NAME>...]
or-S[=<API_NAME>...]
# Allow all system information APIsdeno run-S script.ts# ordeno run --allow-sys script.ts# Allow systemMemoryInfo and osRelease APIsdeno run --allow-sys="systemMemoryInfo,osRelease" script.ts
Definition:--deny-sys[=<API_NAME>...]
# Allow accessing all system information but "networkInterfaces"deno run --allow-sys --deny-sys="networkInterfaces" script.ts# Deny all access to system information, disabling permission prompts.deno run --deny-sys script.ts
SubprocessesJump to heading
Code executing inside of a Deno runtime can not spawn subprocesses by default,as this would constitute a violation of the principle that code can not escalateits privileges without user consent.
Deno provides a mechanism for executing subprocesses, but this requires explicitpermission from the user. This is done using the--allow-run
flag.
Any subprocesses you spawn from your program run independently from thepermissions granted to the parent process. This means the child processes canaccess system resources regardless of the permissions you granted to the Denoprocess that spawned it. This is often referred to as privilege escalation.
Because of this, make sure you carefully consider if you want to grant a program--allow-run
access: it essentially invalidates the Deno security sandbox. Ifyou really need to spawn a specific executable, you can reduce the risk bylimiting which programs a Deno process can start by passing specific executablenames to the--allow-run
flag.
Definition:--allow-run[=<PROGRAM_NAME>...]
# Allow running all subprocessesdeno run --allow-run script.ts# Allow running "curl" and "whoami" subprocessesdeno run --allow-run="curl,whoami" script.ts
You probably don't ever want to use--allow-run=deno
unless the parent processhas--allow-all
, as being able to spawn adeno
process means the script canspawn anotherdeno
process with full permissions.
Definition:--deny-run[=<PROGRAM_NAME>...]
# Allow running running all programs, but "whoami" and "ps".deno run --allow-run --deny-run="whoami,ps" script.ts# Deny all access for spawning subprocessing, disabling# permission prompts.deno run --deny-run script.ts
By defaultnpm
packages will not have their post-install scripts executedduring installation (like withdeno install
), as this would allow arbitrarycode execution. When running with the--allow-scripts
flag, post-installscripts for npm packages will be executed as a subprocess.
FFI (Foreign Function Interface)Jump to heading
Deno provides anFFI mechanism for executing code written in other languages,such as Rust, C, or C++, from within a Deno runtime. This is done using theDeno.dlopen
API, which can load shared libraries and call functions from them.
By default, executing code can not use theDeno.dlopen
API, as this wouldconstitute a violation of the principle that code can not escalate it'sprivileges without user consent.
In addition toDeno.dlopen
, FFI can also be used via Node-API (NAPI) nativeaddons. These are also not allowed by default.
BothDeno.dlopen
and NAPI native addons require explicit permission using the--allow-ffi
flag. This flag can be specified with a list of files ordirectories to allow access to specific dynamic libraries.
Like subprocesses, dynamic libraries are not run in a sandbox and therefore donot have the same security restrictions as the Deno process they are beingloaded into. Therefore, use with extreme caution.
Definition:--allow-ffi[=<PATH>...]
# Allow loading dynamic all librariesdeno run --allow-ffi script.ts# Allow loading dynamic libraries from a specific pathdeno run --allow-ffi=./libfoo.so script.ts
Definition:--deny-ffi[=<PATH>...]
# Allow loading all dynamic libraries, but ./libfoo.sodeno run --allow-ffi --deny-ffi=./libfoo.so script.ts# Deny loading all dynamic libraries, disabling permission prompts.deno run --deny-ffi script.ts
Importing from the WebJump to heading
Allow importing code from the Web. By default Deno limits hosts you can importcode from. This is true for both static and dynamic imports.
If you want to dynamically import code, either using theimport()
or thenew Worker()
APIs, additional permissions need to be granted. Importing fromthe local file systemrequires--allow-read
, butDeno also allows to import fromhttp:
andhttps:
URLs. In such case you willneed to specify an explicit--allow-import
flag:
# allow importing code from `https://example.com`$ deno run --allow-import=example.com main.ts
By default Deno allows importing sources from following hosts:
deno.land
esm.sh
jsr.io
cdn.jsdelivr.net
raw.githubusercontent.com
gist.githubusercontent.com
Imports are only allowed using HTTPS
This allow list is applied by default for static imports, and by default todynamic imports if the--allow-import
flag is specified.
# allow dynamically importing code from `https://deno.land`$ deno run --allow-import main.ts
Note that specifying an allow list for--allow-import
will override the listof default hosts.
Evaluation of codeJump to heading
Deno sets no limits on the execution of code at the same privilege level. Thismeans that code executing in a Deno runtime can useeval
,new Function
, oreven dynamic import or web workers to executearbitrary code with the sameprivilege level as the code that calledeval
,new Function
, or the dynamicimport or web worker.
This code can be hosted on the network, be in a local file (if read permissionsare granted), or be stored as plain text in a string inside of the code thatcalledeval
,new Function
, or the dynamic import or web worker.
Executing untrusted codeJump to heading
While Deno provides security features that are designed to protect the hostmachine and network from harm, untrusted code is still scary. When executinguntrusted code, it is important to have more than one layer of defense. Somesuggestions for executing untrusted code are outlined below, and we recommendusing all of these when executing arbitrary untrusted code:
- Run
deno
with limited permissions and determine upfront what code actuallyneeds to run (and prevent more code being loaded using--frozen
lockfile and--cached-only
). - Use OS provided sandboxing mechanisms like
chroot
,cgroups
,seccomp
,etc. - Use a sandboxed environment like a VM or MicroVM (gVisor, Firecracker, etc).