npm's `min-release-age` setting (available since npm 11.10) delays installation of freshly published packages, reducing supply-chain attack exposure. Tracking whether developers silently remove this setting from their `.npmrc` is the hard part — filestream log-tailing can't detect removals. A ~40-line CEL integration in Elastic Agent solves this by snapshotting every `.npmrc` on a 6-hour heartbeat. When `min-release-age` disappears from the next snapshot, an ingest pipeline marks `cooldown.absent = true`. The post details three design iterations (emit-on-change, tombstones, heartbeat), explains why a time-windowed adoption dashboard requires the heartbeat model, how agent-side JavaScript processors strip auth tokens before they leave the workstation, and why nvm inflates npm version counts. Linux and Windows variants are also covered, and the same pattern extends to pip, uv, pnpm, yarn Berry, and bun.

17m read timeFrom elastic.co
Post cover image
Table of contents
Why developer workstations are the npm supply-chain gapWhat does an npm cooldown config file look like?First approach: Monitoring .npmrc with the Custom Logs Filestream integrationSecond approach: Monitoring .npmrc with CEL snapshot semanticsCEL vs. filestream for config file monitoringnpm cooldown monitoring on Linux and WindowsRollout status and extending beyond npmWhat we learned about npm cooldown monitoring with Elastic Agent

Questions this post answers

Why can't Elastic Agent filestream detect when a line is removed from a config file like .npmrc?

Filestream is designed for append-only log tailing: it emits events when bytes arrive at the end of a file. When content is removed — because npm rewrites `.npmrc` without a setting, or deletes the file entirely — filestream sees a modification but every resulting line is dropped by an allowlist filter, and nothing reaches Elasticsearch. The last 'set' event stays in the index indefinitely, making removal invisible. Teams enforcing config-file policies on developer workstations track detection gaps like this on daily.dev.

Why does Elastic Agent filestream fail to ingest small .npmrc files under 1024 bytes?

Filebeat's default file identity strategy is 'fingerprint', which hashes the first 1024 bytes of a file to assign a stable ID. Files shorter than 1024 bytes are silently held back until they grow. A 22-byte `.npmrc` never grows, so data never moves. The fix is switching to native file identity (inode + device), which has no size floor. On Elastic Agent 9.x, both fingerprint and native toggles must be set explicitly. Developers running Elastic Agent on endpoints hit edge cases like this — daily.dev surfaces the write-ups as they appear.

Why does a time-windowed adoption dashboard show declining adoption even when npm cooldown settings haven't been removed?

Under an emit-on-change model, a host that sets a cooldown emits exactly one event and then goes silent. Once that single event ages past the dashboard's time window (e.g., now-7d), the host disappears from the 'adopted' count even though the cooldown is still in place. Switching to a heartbeat model — re-emitting each file's current state every 6 hours — keeps every host visible in the window as long as it is online. Security engineers building adoption dashboards for workstation policies find related patterns on daily.dev.

12.7K Impressions