# [HIGH] Why EDR and proxy won’t save you from supply chain malware

**Source:** Aikido
**Published:** 2026-06-02
**Article:** https://www.aikido.dev/blog/edr-proxy-wont-protect-supply-chain-malware

## Threat Profile

Blog News Why EDR and proxy won’t save you from supply chain malware Why EDR and proxy won’t save you from supply chain malware Written by Samuel Vandamme Published on: Jun 2, 2026 Most security teams check the EDR box, check the proxy box, and move on. Against supply chain malware, neither provides meaningful protection because they were built for a different problem. 
Traditional malware has a way of sneaking onto a machine, whereas supply chain malware gets invited. The developer runs npm ins…

## Indicators of Compromise (high-fidelity only)

- **IPv4 (defanged):** `142.11.206.73`
- **IPv4 (defanged):** `160.119.64.3`
- **Domain (defanged):** `sfrclak.com`
- **Domain (defanged):** `check.git-service.com`
- **Domain (defanged):** `t.m-kosche.com`
- **Domain (defanged):** `packages.npm.org`
- **SHA256:** `069ac1dc7f7649b76bc72a11ac700f373804bfd81dab7e561157b703999f44ce`
- **SHA256:** `7d80b3ef74ad7992b93c31966962612e4e2ceb93e7727cdbd1d2a9af47d44ba8`
- **SHA256:** `3de04fe2a76262743ed089efa7115f4508619838e77d60b9a1aab8b20d2cc8bf`
- **SHA256:** `aeaf583e20347bf850e2fabdcd6f4982996ba023f8c2cd56bbd299cfd56516f5`
- **SHA256:** `85f54c089d78ebfb101454ec934c767065a342a43c9ee1beac8430cdd3b2086f`
- **SHA256:** `877ff2531a63393c4cb9a3c86908b62d9c4fc3db971bc231c48537faae6cb3ec`
- **SHA256:** `c0b094e46842260936d4b97ce63e4539b99a3eae48b736798c700217c52569dc`
- **SHA1:** `2553649f2322049666871cea80a5d0d6adc700ca`
- **SHA1:** `d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71`
- **SHA1:** `07d889e2dadce6f3910dcbc253317d28ca61c766`

## MITRE ATT&CK Techniques

- **T1195.002** — Compromise Software Supply Chain
- **T1071** — Application Layer Protocol
- **T1027** — Obfuscated Files or Information
- **T1204.002** — User Execution: Malicious File
- **T1071.001** — Application Layer Protocol: Web Protocols
- **T1195.002** — Supply Chain Compromise: Compromise Software Supply Chain
- **T1021.007** — Remote Services: Cloud Services
- **T1609** — Container Administration Command
- **T1078.004** — Valid Accounts: Cloud Accounts
- **T1059.001** — Command and Scripting Interpreter: PowerShell
- **T1105** — Ingress Tool Transfer
- **T1552.001** — Unsecured Credentials: Credentials In Files
- **T1528** — Steal Application Access Token
- **T1485** — Data Destruction
- **T1561.001** — Disk Wipe: Disk Content Wipe

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### Package manager runtime connecting to durabletask/axios supply-chain C2 IOCs

`UC_142_4` · phase: **c2** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Network_Traffic where All_Traffic.app IN ("node.exe","python.exe","python3.exe","npm.exe","pip.exe","pip3.exe","node","python","python3") AND (All_Traffic.dest IN ("142.11.206.73","160.119.64.3") OR All_Traffic.dest_host IN ("sfrclak.com","check.git-service.com","t.m-kosche.com","packages.npm.org")) by All_Traffic.src All_Traffic.user All_Traffic.app All_Traffic.dest All_Traffic.dest_host All_Traffic.dest_port | `drop_dm_object_name(All_Traffic)` | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
let MalIPs = dynamic(["142.11.206.73","160.119.64.3"]);
let MalDomains = dynamic(["sfrclak.com","check.git-service.com","t.m-kosche.com","packages.npm.org"]);
DeviceNetworkEvents
| where Timestamp > ago(14d)
| where InitiatingProcessFileName in~ ("node.exe","python.exe","python3.exe","npm.exe","pip.exe","pip3.exe","node","python","python3")
| where RemoteIP in (MalIPs) or RemoteUrl has_any (MalDomains)
| project Timestamp, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessParentFileName, RemoteIP, RemoteUrl, RemotePort
| order by Timestamp desc
```

### Lateral movement via aws ssm send-command or kubectl exec spawned by python/node

`UC_142_5` · phase: **actions** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name IN ("python.exe","python3.exe","node.exe","python","python3","node") AND Processes.process_name IN ("aws.exe","aws","kubectl.exe","kubectl") AND (Processes.process="*ssm send-command*" OR Processes.process="*ssm start-session*" OR Processes.process="*kubectl exec*" OR Processes.process="*exec -it*" OR Processes.process="*exec --stdin*") by Processes.dest Processes.user Processes.parent_process Processes.process_name Processes.process | `drop_dm_object_name(Processes)` | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(14d)
| where InitiatingProcessFileName in~ ("python.exe","python3.exe","node.exe","python","python3","node")
| where FileName in~ ("aws.exe","aws","kubectl.exe","kubectl")
| where ProcessCommandLine has_any ("ssm send-command","ssm start-session","kubectl exec","exec -it","exec --stdin")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine
| order by Timestamp desc
```

### Downloader or shell child of npm/pip install (postinstall RAT loader)

`UC_142_6` · phase: **install** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name IN ("npm.exe","pip.exe","pip3.exe","node.exe","python.exe","python3.exe","npm","pip","pip3","yarn","pnpm") AND Processes.process_name IN ("curl.exe","wget.exe","powershell.exe","pwsh.exe","cmd.exe","bash","sh","bitsadmin.exe","certutil.exe") AND (Processes.process="*http://*" OR Processes.process="*https://*" OR Processes.process="*Invoke-WebRequest*" OR Processes.process="*DownloadString*" OR Processes.process="*-OutFile*" OR Processes.process="*/dev/tcp/*") by Processes.dest Processes.user Processes.parent_process Processes.process_name Processes.process | `drop_dm_object_name(Processes)` | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("npm.exe","pip.exe","pip3.exe","node.exe","python.exe","python3.exe","npm","pip","pip3","yarn","pnpm")
| where FileName in~ ("curl.exe","wget.exe","powershell.exe","pwsh.exe","cmd.exe","bash","sh","bitsadmin.exe","certutil.exe")
| where ProcessCommandLine has_any ("http://","https://","Invoke-WebRequest","DownloadString","-OutFile","/dev/tcp/","base64 -d")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, SHA256
| order by Timestamp desc
```

### Cloud credential file access by node/python runtime

`UC_142_7` · phase: **actions** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Filesystem where Filesystem.process_name IN ("node.exe","python.exe","python3.exe","node","python","python3") AND (Filesystem.file_path="*.aws/credentials*" OR Filesystem.file_path="*\\.aws\\credentials*" OR Filesystem.file_path="*.kube/config*" OR Filesystem.file_path="*\\.kube\\config*" OR Filesystem.file_path="*/.azure/*" OR Filesystem.file_path="*\\.azure\\*" OR Filesystem.file_path="*/.config/gcloud/*" OR Filesystem.file_path="*\\gcloud\\*" OR Filesystem.file_path="*.vault-token*" OR Filesystem.file_path="*.npmrc*") by Filesystem.dest Filesystem.user Filesystem.process_name Filesystem.file_path Filesystem.action | `drop_dm_object_name(Filesystem)` | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
DeviceFileEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("node.exe","python.exe","python3.exe","node","python","python3")
| where FolderPath has_any (@".aws\credentials", ".aws/credentials", @".kube\config", ".kube/config", @".azure\", "/.azure/", "/.config/gcloud/", @"\gcloud\", ".vault-token", ".npmrc")
| project Timestamp, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessParentFileName, FileName, FolderPath, ActionType
| order by Timestamp desc
```

### Locale-conditional rm -rf wiper command from python/node runtime

`UC_142_8` · phase: **actions** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name IN ("python","python3","node","python.exe","python3.exe","node.exe") AND Processes.process_name IN ("rm","sh","bash","busybox","dash") AND (Processes.process="*rm -rf /*" OR Processes.process="*rm -rf /" OR Processes.process="*rm -rf --no-preserve-root*") by Processes.dest Processes.user Processes.parent_process Processes.process_name Processes.process | `drop_dm_object_name(Processes)` | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(14d)
| where InitiatingProcessFileName in~ ("python.exe","python3.exe","node.exe","python","python3","node")
| where FileName in~ ("rm","sh","bash","busybox","dash")
| where ProcessCommandLine matches regex @"(?i)\brm\s+-rf\s+(/\*?|--no-preserve-root)"
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine
| order by Timestamp desc
```

### Trusted vendor binary / installer launching unusual children

`UC_SUPPLY_CHAIN` · phase: **exploit** · confidence: **Medium**

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime
    from datamodel=Endpoint.Processes
    where Processes.parent_process_name IN ("setup.exe","installer.exe","update.exe")
      AND Processes.process_name IN ("powershell.exe","cmd.exe","rundll32.exe","regsvr32.exe","mshta.exe","wscript.exe","cscript.exe","wmic.exe","bitsadmin.exe")
    by Processes.dest, Processes.user, Processes.parent_process_name, Processes.process_name, Processes.process
| `drop_dm_object_name(Processes)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where AccountName !endswith "$"
| where InitiatingProcessFileName in~ ("setup.exe","installer.exe","update.exe")
| where FileName in~ ("powershell.exe","cmd.exe","rundll32.exe","regsvr32.exe","mshta.exe","wscript.exe","cscript.exe","wmic.exe","bitsadmin.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
```

### Article-specific behavioural hunt — Why EDR and proxy won’t save you from supply chain malware

`UC_142_3` · phase: **exploit** · confidence: **High**

**Splunk SPL (CIM):**
```spl
``` Article-specific bespoke detection — Why EDR and proxy won’t save you from supply chain malware ```
| tstats `summariesonly` count earliest(_time) AS firstTime latest(_time) AS lastTime
    from datamodel=Endpoint.Processes
    where (Processes.process_name IN ("__init__.py"))
    by Processes.dest, Processes.user, Processes.process_name,
       Processes.process, Processes.parent_process_name, Processes.process_path
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| append [
| tstats `summariesonly` count
    from datamodel=Endpoint.Filesystem
    where Filesystem.action IN ("created","modified")
      AND (Filesystem.file_name IN ("__init__.py"))
    by Filesystem.dest, Filesystem.user, Filesystem.process_name,
       Filesystem.file_path, Filesystem.file_name
| `drop_dm_object_name(Filesystem)`
]
```

**Defender KQL:**
```kql
// Article-specific bespoke detection — Why EDR and proxy won’t save you from supply chain malware
// Hunts the actual binaries / paths / commandline fragments named
// in the article instead of a generic technique-class template.
DeviceProcessEvents
| where Timestamp > ago(30d)
| where (FileName in~ ("__init__.py"))
| project Timestamp, DeviceName, AccountName, FileName,
          FolderPath, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc

// File-creation events for the named binaries / paths
DeviceFileEvents
| where Timestamp > ago(30d)
| where ActionType in ("FileCreated","FileModified")
| where (FileName in~ ("__init__.py"))
| project Timestamp, DeviceName, AccountName, FolderPath,
          FileName, ActionType, InitiatingProcessFileName,
          InitiatingProcessCommandLine
| order by Timestamp desc
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Network connections to article IPs / domains** ([template](../_TEMPLATES.md#network-ioc)) — phase: **c2**, confidence: **High**
  - IP / domain IOC(s): `142.11.206.73`, `160.119.64.3`, `sfrclak.com`, `check.git-service.com`, `t.m-kosche.com`, `packages.npm.org`

- **File hash IOCs — endpoint file/process match** ([template](../_TEMPLATES.md#hash-ioc)) — phase: **install**, confidence: **High**
  - file hash IOC(s): `069ac1dc7f7649b76bc72a11ac700f373804bfd81dab7e561157b703999f44ce`, `7d80b3ef74ad7992b93c31966962612e4e2ceb93e7727cdbd1d2a9af47d44ba8`, `3de04fe2a76262743ed089efa7115f4508619838e77d60b9a1aab8b20d2cc8bf`, `aeaf583e20347bf850e2fabdcd6f4982996ba023f8c2cd56bbd299cfd56516f5`, `85f54c089d78ebfb101454ec934c767065a342a43c9ee1beac8430cdd3b2086f`, `877ff2531a63393c4cb9a3c86908b62d9c4fc3db971bc231c48537faae6cb3ec`, `c0b094e46842260936d4b97ce63e4539b99a3eae48b736798c700217c52569dc`, `2553649f2322049666871cea80a5d0d6adc700ca` _(+2 more)_


## Why this matters

Severity classified as **HIGH** based on: IOCs present, 9 use case(s) fired, 15 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
