Skip to main content
Ungathered Thoughts

Oversharing with NPM

Last weekend I released @xurizaemon/eleventy-immich. I used Github Actions to trigger an NPM release from a pushed tag, and after making the initial release with an arbitrary version of v0.1.0, I reviewed the @xurizaemon/eleventy-immich@v0.1.0 release page on NPMJS.

The "unpacked size" value was 28.5MB, and I realised I'd made a mistake.

I'm more familiar with Composer releases, and when you release a Composer package the built archive is constrained to the sourcecode of the tagged release. If you wanted to release a Composer package with some generated files - say, translations from an external source, or built/compiled CSS or JS, my understanding is that you need to build those additional files first and commit them to your Composer codebase.

NPM doesn't have this limitation; the release process can include build steps, and the release archive can include build-time results.

My package's build steps included running tests, and the tests performed end-to-end integration tests against an Immich instance I host. That 28.5MB of files included about 5KB of sourcecode, and some additional files. This counts as "oversharing", and I now needed to review whether I'd inadvertently shared anything I shouldn't have.

The test images weren't my concern. I'll document how the tests work in a more appropriate location, but I had good confidence that the images themselves weren't sensitive; the tests retrieve specific images individually and from a specific album. My concern was other details, such as the API keys used for the integration, and any other details I might find in the built archive. Also, I find being interested in problems is a really effective way to approach them, so my inclination was to learn more rather than to panic.

By the time I'd identified my mistake, I could also see that there were 9 downloads of my newly released package. How exciting! Do I think there were nine people that stumbled onto an interesting NPM package and typed npm install @xurizaemon/eleventy-immich straight away? No, I don't. Automated systems are watching new releases (and new Github pushes) for "interesting" details all the time, and in this world "interesting" means "profitable". I have to assume that any details shared will already have been seen by someone with potential for malicious use.

First action

My first action was to correct my mistake by adding some .gitignore entries (which NPM respects) to the project, and releasing v0.1.1 at a much more reasonable ~5KB in place of the previous 28MB.

Assessing the damage

With a replacement release out the door, my next step was to review what I'd shared.

Let's grab a copy of the files I published:

chris@thip: ~$ mkdir /tmp/throwaway && cd /tmp/throwaway
chris@thip:/tmp/throwaway$ npm init -y
# output skipped
chris@thip:/tmp/throwaway$ npm install @xurizaemon/eleventy-immich@v0.1.0

added 1 package, and audited 2 packages in 2s

found 0 vulnerabilities
chris@thip:/tmp/throwaway$ cat package.json
{
"name": "throwaway",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"@xurizaemon/eleventy-immich": "^0.1.0"
}
}

So, what made it into the release?

Firstly: does the downloaded files approximate what I think got released? Yes, it does.

chris@thip:/tmp/throwaway$ du -sh node_modules/@xurizaemon/eleventy-immich/
28M node_modules/@xurizaemon/eleventy-immich/

Initial inspection

Let's have a look at what I need to explore. tree -da will show me the directories of a directory:

chris@thip:/tmp/throwaway/node_modules/@xurizaemon/eleventy-immich$ tree -ad
.
├── .cache
├── .github
│ └── workflows
├── .idea
│ ├── codeStyles
│ └── inspectionProfiles
├── public
│ └── media
│ └── img
└── test

10 directories

Looking at the file contents as well: tree -a

Click to see output
chris@thip:/tmp/throwaway/node_modules/@xurizaemon/eleventy-immich$ tree -a
.
├── .cache
│ ├── eleventy-fetch-13d629a2fb0ab7cea5b05589667f7e
│ ├── eleventy-fetch-13d629a2fb0ab7cea5b05589667f7e.buffer
│ ├── eleventy-fetch-317aeed09661ed23b93071dff930bd
│ ├── eleventy-fetch-317aeed09661ed23b93071dff930bd.json
│ ├── eleventy-fetch-67adde77a89e4672d3ac77c7313615
│ ├── eleventy-fetch-67adde77a89e4672d3ac77c7313615.json
│ ├── eleventy-fetch-77be3b5f8c2ec56bb3890fa6619ba6
│ ├── eleventy-fetch-77be3b5f8c2ec56bb3890fa6619ba6.json
│ ├── eleventy-fetch-7c85f08df0509d9d7825bf367d12d3
│ ├── eleventy-fetch-7c85f08df0509d9d7825bf367d12d3.json
│ ├── eleventy-fetch-a1fb53576fce4640adb4176510b7af
│ ├── eleventy-fetch-a1fb53576fce4640adb4176510b7af.buffer
│ ├── eleventy-fetch-a4f2ce9274ea106198f56d6355e3cc
│ ├── eleventy-fetch-a4f2ce9274ea106198f56d6355e3cc.json
│ ├── eleventy-fetch-ab5c0e42fecc55d7316494c515354d
│ ├── eleventy-fetch-ab5c0e42fecc55d7316494c515354d.buffer
│ ├── eleventy-fetch-b2e62be056ad837dbc96ebca8fb4ac
│ ├── eleventy-fetch-b2e62be056ad837dbc96ebca8fb4ac.buffer
│ ├── eleventy-fetch-b486d1283d68c1996d39e5c71be87f
│ ├── eleventy-fetch-b486d1283d68c1996d39e5c71be87f.json
│ ├── eleventy-fetch-c4f8f26c84ede2b465b604152680b1
│ ├── eleventy-fetch-c4f8f26c84ede2b465b604152680b1.buffer
│ ├── eleventy-fetch-c8a1319796be03a4a3a8fb0f82bd02
│ ├── eleventy-fetch-c8a1319796be03a4a3a8fb0f82bd02.json
│ ├── eleventy-fetch-f37c2de21a89f407822b63fbaa5f95
│ ├── eleventy-fetch-f37c2de21a89f407822b63fbaa5f95.json
│ ├── eleventy-fetch-f85c0fb9f6a0fd9713efd6f89f2eee
│ └── eleventy-fetch-f85c0fb9f6a0fd9713efd6f89f2eee.buffer
├── eslint.config.mjs
├── .github
│ └── workflows
│ ├── nodejs.yml
│ └── npm-publish.yml
├── .idea
│ ├── codeStyles
│ │ ├── codeStyleConfig.xml
│ │ └── Project.xml
│ ├── eleventy-immich.iml
│ ├── GitLink.xml
│ ├── inspectionProfiles
│ │ └── Project_Default.xml
│ ├── modules.xml
│ ├── php.xml
│ └── vcs.xml
├── immich.js
├── LICENSE
├── package.json
├── public
│ └── media
│ └── img
│ ├── 6F6xc8RT4F-300.jpeg
│ ├── 6F6xc8RT4F-600.jpeg
│ ├── 8wDxzJOqow-300.jpeg
│ ├── 8wDxzJOqow-600.jpeg
│ ├── AitV6V6-2X-300.jpeg
│ ├── AitV6V6-2X-600.jpeg
│ ├── heH3xr0I7G-300.jpeg
│ ├── heH3xr0I7G-600.jpeg
│ ├── oupuEcpEIs-300.jpeg
│ ├── oupuEcpEIs-600.jpeg
│ ├── rDX8xf_N04-300.jpeg
│ └── rDX8xf_N04-600.jpeg
├── README.md
└── test
└── test.js

10 directories, 56 files

Reviewing the files on the surface

What can I see from filenames alone?

Inspecting file contents

And inspecting the files, what else can I see?

Is any of this a worry to me?

Is there any of that I'm concerned about? Not really. There's a little extra sharing, but very little of concern. It has got me wondering whether using different emails to sign into a service would add any additional security to my accounts, but not the best return for effort versus other account protection strategies.

What other options did I have?

I could have unpublished the release (npm unpublish @xurizaemon/eleventy-immich@v0.1.0) from the registry. If I had been seriously concerned, I would have looked to that. However: at the time I knew of the error, I had already seen there were nine downloads. Unpublishing the release would not have addressed those, along with the fact that I'd supplied the release tarball to a couple of organisations along the way: Github and npm, Inc. I assumed seven of the nine downloads were malicious actors and moved on to threat assessment.

Shared, not redacted

Instead, I figure I should add a copy of the released files here as a reference: eleventy-immich-0.1.0.tgz

Or, you can get the original URL via npm view @xurizaemon/eleventy-immich@v0.1.0, or browse the v0.1.0 source files on npmjs.com