Hacker News new | ask | show | jobs
by goldsteinq 1620 days ago
Deno’s permission system is broken, you shouldn’t rely on it. Deno developers consistently ignore security issues, high priority bugs take months to fix.

https://github.com/denoland/deno/issues/11964

https://github.com/denoland/deno/issues/9750

API-based access control can’t possibly work because it’s nearly impossible to predict the effect of any single permission. For example, “permission to run specific command” makes no sense without checking the integrity of the binary, controlling the environment for LD_PRELOAD-like hacks and evaluating the code of this command for possible escape hatches. If you want to isolate a program, you need to do it on the OS level.

5 comments

I'm not overly concerned that allow-run leads to possible elevation, I'm more interested if:

  > deno run --allow-read=./assets
works as intended - preventing most execution of local code, and prevents writing to disk. I think it's a useful real-world use-case, that is complicated to copy with nodejs.

That said, I think one should still be wary of running random code - but at least deno makes it a little easier for honest authors to adhere to principle of least privilege?

Read permission for a specific (non-system) directory is probably fine.
So, If I understand it correctly the security issues are at architectural level and not simply bugs?

Is there an alternative tool you can suggest, to allow us securely run arbitrary JS? I was looking at Apple's JavaScriptCore to run JS and and if it happens that I need any level of access to the system(i.e. files) simply handle that in Swift and pass the file to the JS. Would that be a secure approach?

Yep, trying to restrict the access to a system on the API level instead of the OS level will inevitably lead to problems like these (Deno is doing worse than it could though).

If you want to isolate your program, you should use an OS-level sandbox like bubblewrap or a lightweight VM like Firecracker. I’m not familiar with Apple’s JavaScriptCore, but if it doesn’t provide any access to the system (and instead relies on passing arguments from Swift code), it might also be a viable approach.

> if it doesn’t provide any access to the system

Yes, my understanding is that it's the pure language interpreter without anything about filesystems or web browser. You need to create an interface in Swift/Objective-C or C to put in and get data out of the execution context.

Re: the first linked issue, does it only affect scripts that require the --allow-run permission in some form? Are the other permission types (--allow-read/write/net/etc) also affect by this or similar issues somehow?

The 2nd issue does seem concerning to have taken so long to resolve.

Yes, it exploits `--allow-run=whatever` + `--allow-write=whatever` to execute arbitrary code outside of the sandbox.

The problem with the Deno security model is that it’s hard to predict how granting any specific permission would affect overall security. For example, it may seem to be kinda reasonable for an application to ask for `--allow-write=~/.config` to create config directories & files, but it’s probably exploitable to escape the sandbox. Is `--allow-env` + `--allow-write=whatever` dangerous? I don’t know. If Deno runtime spawns a subprocess at some point, it could be used to execute arbitrary code via `LD_PRELOAD`. Is there a guarantee that Deno runtime will never spawn subprocesses? There is no way to know.

Lots of weasel words here and you don't answer directly.

It still seems to me that a Deno script running with necessary permissions will be a huge hurdle compared to running a Node script which by default has al permissions.

Edit : Also I'm seriously fed up with tech community cr#pping at everything good because it isn't perfect.

Today with Node any random package can download any DLL as long as it is novel enough to pass antivirus (hint: last I checked a 17 year old could make a trojan that flew straight past, no questions asked.)

Even Node is usable with the right precautions.

But trying to get people away from thinking about Deno is not ok.

Painting any criticism of deno as simply the work of haters is much more a tactic of stopping thought.

Whether or not ideas and discussion are negative or positive is not relevant at all. When they're presented in some detail and in good faith, we should tackle them in turn. This encourages thought, discussion, and understanding among all.

GP's comment is in a thread that starts with "Deno’s permission system is broken, you shouldn’t rely on it".

Not relying on Deno's permission system will, in practice, mean just allowing everything or using Node instead of Deno. I can't for the love of god understand why that's better than using a permission system that provides some more protection than just about any other currently-commonly-used backend dev platform. Nobody at Deno is suggesting that their permission system solves all your security risk.

I bet "just allow everything" is not what the top poster intended but that's the takeaway. How many Node deployments do you know that use OS-level protections to eg disallow Node from spawning child processes?

Root comment literally ended with

> If you want to isolate a program, you need to do it on the OS level.

Commenter further suggested bubblewrap and firecracker elsewhere in the thread.

“Just allow everything” is a straw man you pulled out of nowhere.

Because illusory protection is worse than no protection. if it doesn't actually provide any protection against malicious code in practice then the only thing it can give you is a false sense of security.
I did answer directly: this exploit requires run permission with any argument and write permission to any directory. It allows malicious script to escape sandbox and execute arbitrary code outside of it.
> this exploit requires run permission with any argument and write permission to any directory. It allows malicious script to escape sandbox and execute arbitrary code outside of it.

I suppose you wrote something wrong here and I'm interested in knowing what.

Because as it stands now I read it falls down to: "If you open the permission system up extremely wide you can get exploited."

Alternatively, after thinking for a couple of minutes I can read it as "if you simultaneously allow run permission with anything and write permission with anything".

In the last case it is slightly more problematic, but if one allows a script to execute anything that is itself a huge red flag.

... and on Node this red flag is always flying by default.

So, I have a highly upvoted answer below but I'm going to humble myself a bit (smart anyways when I'm wrong and definitely better than having others do it).

I read through your bug reports now.

These are sound and very very useful.

I must admit I pattern matched on your language and answered based on that below and therefore my answer even if it is maybe somewhat(?) correct is extremely wrong in tone and what it implies.

Sorry.

I still think that it would be better if you were somewhat more specific. All in this thread seems to be related to subprocesses, which is a scary thing anyways for anything internet facing, isn't it.

As a non-js dev, is it better than Node?
It’s arguably worse than Node because Node doesn’t pretend to provide any security. With Deno you may be tempted to think that permission to run specific command actually means that program can’t run some other command (it can, and doing this doesn’t even require _clever_ hacks: Deno uses binary name instead of the full path in it’s permission system, so you only need to change $PATH for the child process).
The Deno docs say:

> make sure you carefully consider if you want to grant a program --allow-run access: it essentially invalidates the Deno security sandbox

Saying Deno shouldn't "pretend" (or attempt) to provide more security because a non-default flag invalidates the sandbox (as stated clearly in the docs for that flag) seems slight hyperbole.

It would admittedly be cool if we could use this flag securely (though I'm sure the implementation complexity would be significant, and more code surface area is never nice to audit).