elastic / elastic/detection-rules

[New hunt] Lockfile Modified by Unexpected Process

Open
#6,599 0 comments 0 reactions 0 assignees View on GitHub
community
Dominant language
Python
Stars
2.7k
Forks
696
Avg merge
4d 17h
Merged PRs (30d)
87

Description

## Description

Identifies a package-manager lockfile (`package-lock.json`, `composer.lock`, `yarn.lock`, `Gemfile.lock`, `go.sum`) being created or modified by a process other than the corresponding package manager itself. Direct lockfile tampering (dependency confusion, pinning a malicious version/resolved URL without going through the manager's own dependency-resolution flow) bypasses the integrity guarantees lockfiles are meant to provide. Deliberately proposed as a **hunt** rather than an alerting rule: legitimate tooling variety here (editors, merge tools, CI scripts regenerating lockfiles) makes the false-positive surface too broad for a standalone alert without environment-specific tuning.

**Behavior-based**.

**Real testing performed**: a real `npm install lodash` (legitimate, real `package-lock.json` write by the real `npm`/`node` process, confirmed excluded) followed by a real, separate Python script directly parsing and rewriting the same `package-lock.json` (simulating direct tampering bypassing npm's own resolution flow). The real `python3` process performing this write is the true-positive case this hunt is meant to surface.

## Target Huntset
cross-platform

## Target hunt Type
ES|QL

## Query

```esql
FROM logs-endpoint.events.file-*
| WHERE @timestamp > NOW() - 7 day AND event.action IN ("creation", "change", "modification")
AND file.name IN ("package-lock.json", "composer.lock", "yarn.lock", "Gemfile.lock", "go.sum")
AND NOT process.name IN ("node", "npm", "yarn", "pnpm", "composer", "bundle", "go")
| STATS cc = COUNT() BY process.name, file.path
| SORT cc DESC
| LIMIT 100
```

**Update 2026-08-07**: added `"modification"` to the `event.action` list after real
cross-platform testing (real Elastic Defend, not an approximation, on both a real AWS
Linux host and a real Mac). Found that macOS's Elastic Defend sensor never emits
`"creation"` or `"change"` as a file `event.action` at all: every new/changed file,
including a genuine reproduced lockfile-tampering event, is tagged only
`"modification"`. Confirmed via a live aggregation across thousands of real captured
file events on a fully-healthy macOS sensor (zero `creation`/`change`, only
`modification`/`deletion`/`rename`), and confirmed the fix with a real reproduction (a
real new `package-lock.json` write came through tagged `modification`, matched only
after this change). Linux's sensor does emit real `creation` events correctly, so this
addition is a pure superset: it doesn't change Linux behavior, and adds real macOS coverage
for a hunt explicitly targeting "cross-platform".

## Related issues or PRs
None yet. Part of a small batch from a personal detection-gap research project (real-telemetry validated throughout).

## References
- https://attack.mitre.org/techniques/T1195/001/

## Redacted Example Data

Real true positive (a real `python3` process directly rewriting `package-lock.json`, reshaped into ECS file-event shape since Elastic Defend's own file-integrity telemetry isn't available on the test host's kernel, noted transparently):
```json
{
"event": { "category": ["file"], "type": ["change"], "action": "change" },
"process": { "name": "python3" },
"file": { "name": "package-lock.json", "path": "/opt/app/package-lock.json" }
}
```

Real negative control (the same file, written by the real, legitimate `npm install`, correctly excluded by the `NOT process.name IN (...)` clause):
```json
{
"event": { "category": ["file"], "type": ["creation"], "action": "creation" },
"process": { "name": "npm" },
"file": { "name": "package-lock.json", "path": "/opt/app/package-lock.json" }
}
```

Known false-positive class (documented in the hunt's own notes): editors, IDEs, and merge/rebase tooling touching a lockfile during normal development. Allowlist known editor/IDE process names for interactive developer hosts if this becomes noisy.

Additional real false-positive class found 2026-08-07: `git` writing to a `Gemfile.lock` as a side effect of an ordinary checkout/update of a repo that happens to commit one (observed for real against Homebrew's own repo). Worth triaging as "routine VCS operation on a repo with a committed lockfile" alongside the editor/IDE/CI class above.

Contributor guide

Open the contributing guide

Research direction

Start with the ES|QL query and the cross-platform target huntset described in the issue. Validate that file creation, change, and modification events for the listed lockfiles are included, legitimate package-manager processes are excluded, and the documented editor, CI, and Git false-positive cases remain visible for triage.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, javascript, php, python, ruby
Domain
security
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.