Scope a Supply-Chain Compromise
Identify the compromised vendor, affected software versions, and the blast radius across the estate using SBOMs, package managers, and deployment telemetry. Confirm whether the malicious artifact is actually present and executed, not only downloaded, so containment can be focused.
Actions
- 1
Pull the vendor advisory and record: affected product, affected versions, published IoCs (hashes, domains, certificates), and the earliest known malicious release timestamp.
- 2
Query SBOMs and package registries (npm ls, pip freeze, go list -m all, Trivy SBOM, Syft output) across build systems and runtime hosts for the affected package and version range.
- 3
Across EDR telemetry, search for the malicious hash(es) as `FileHash` and as a loaded module parent: `DeviceFileEvents | where SHA256 in~ (<hashes>)` joined with `DeviceProcessEvents | where SHA256 in~ (<hashes>)` to separate "present on disk" from "actually executed".
- 4
Check artifact repositories (JFrog, Nexus, GitHub Packages, internal PyPI mirror) for upload timestamps and download counts of the affected package to estimate blast radius.
- 5
Search CI/CD logs (GitHub Actions, GitLab CI, Jenkins, Buildkite) for pipelines that installed the compromised package during the malicious-version window.
- 6
Cross-reference outbound network telemetry for the vendor-disclosed C2 domains/IPs -- this is often faster than finding the artifact itself in a large estate.
Queries
DeviceFileEvents | where SHA256 in~ ("<hash1>","<hash2>") | summarize first_seen=min(Timestamp), hosts=make_set(DeviceName) by SHA256, FileNameDeviceProcessEvents | where SHA256 in~ ("<hash1>","<hash2>") or InitiatingProcessSHA256 in~ ("<hash1>","<hash2>") | project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessCommandLineDeviceNetworkEvents | where RemoteUrl has_any ("<c2-domain-1>","<c2-domain-2>") or RemoteIP in ("<c2-ip-1>") | summarize conns=count() by DeviceName, RemoteUrl, RemoteIPindex=ci sourcetype=github-actions earliest=<malicious-release-ts> ("npm install" OR "pip install" OR "go get") package="<compromised-pkg>" | stats values(repo), values(branch), min(_time), max(_time) by packageNotes
Distinguish "downloaded" from "executed" early. A package being present in node_modules or a Docker image layer does not necessarily mean the malicious payload ran -- check for the specific malicious function invocation, C2 callback, or post-install hook execution.
For signed malicious updates, hash-based IoCs are reliable but signing-chain IoCs (certificate thumbprints) can be more useful for hunting untagged versions.
If the vendor has not yet published IoCs, request private sharing under NDA through an ISAC or trusted peer channel -- do not wait for public disclosure.