Elastic has developed a new detection engineering method to track the removal of the `min-release-age` setting from `.npmrc` files on developer workstations. This setting, available since npm version 11.10, is designed to prevent the installation of recently published package versions, mitigating supply chain attacks such as Compromise Software Dependencies and Development Tools (T1195.001).
The `min-release-age` setting specifies a number of days, and npm will ignore any package version published more recently than that duration. While enterprise-level CI/CD pipelines often have their own supply chain guardrails, developer workstations represent a common gap where a compromised package could be installed. Elastic enforces this setting by using Jamf to write `min-release-age=7` to user-level and machine-global `.npmrc` files daily.
The challenge lies in detecting when this setting is removed, as traditional log-tailing inputs only trigger on file appends, not content removal or file deletion. To address this, Elastic built a Common Expression Language (CEL) integration within Elastic Agent. This integration snapshots all `.npmrc` files every six hours. If the `min-release-age` setting is absent from a subsequent snapshot, the pipeline marks it as `cooldown.absent = true`. This allows Elastic to identify hosts where the setting has been removed during the window before Jamf re-applies it.
The target `.npmrc` files are small, typically 10 to 50 bytes, and contain the `min-release-age` setting along with sensitive data like private registry authentication tokens. Any monitoring solution must filter out these tokens before data leaves the host.
Elastic initially attempted to use the Custom Logs Filestream integration, which wraps Filebeat's modern filestream input. This approach involved configuring path globs for user-level and system-global `.npmrc` files on macOS, and an ingest pipeline to extract the `min-release-age` value while dropping other lines to prevent sensitive data exfiltration.
However, three issues arose with the filestream approach. First, Filebeat's default `fingerprint` file identity strategy, which hashes the first 1024 bytes, caused small `.npmrc` files to be held back from ingestion. Switching to `native` file identity (inode plus device) resolved this, as it has no size floor. Second, the `clean_inactive` setting, necessary for periodic re-emission of config files, required `ignore_older` to also be set, which is unsuitable for static configuration files. Consequently, `clean_inactive` was disabled.
The third and most significant limitation was that filestream emits events only on appends. When `min-release-age` was removed from an `.npmrc` file, filestream recognized a modification, but the allowlist filter dropped all resulting lines, preventing the removal signal from reaching Elasticsearch. This structural limitation led to the adoption of the CEL snapshot approach.
It was also noted that machines often report multiple npm versions due to Node Version Manager (nvm) installations, each with its own npm binary. While `npm config set min-release-age 7` writes to the user-level `.npmrc` that all npm installations read, only npm versions 11.10 and newer respect the setting. Therefore, a count of machines with any capable npm version overstates the actual protection, reinforcing the need to track the configuration directly.






