Node-IPC Expired Domain & Maintainer Account Hijacking
On May 14, 2026, the highly popular Node.js library node-ipc was compromised in a major supply chain attack. Attackers re-registered the expired email domain of a dormant lead maintainer to reset their npm account password and publish credential-stealing updates.
On this page 0% read
Executive Summary
On May 14, 2026, the foundational JavaScript package node-ipc (over 800,000 weekly downloads) was compromised in an elegant and highly impactful supply chain hijacking tracked as SNYK-JS-NODEIPC-16697063 Snyk Vulnerability Database. Rather than breaking into repository servers or compromising CI/CD pipelines directly, the attackers target-hunted a dormant maintainer account named atiertant CSO Online. They discovered the maintainer’s registered npm email address was hosted on atlantis-software.net—a domain that had quietly expired in January 2025 Cybersecurity News. By re-registering this expired domain, the threat actors successfully hijacked the email inbox, initiated an npm password reset, bypassed multi-factor authentication (which was either absent or circumvented via account recovery), and gained publishing credentials Daily.dev Blog. They immediately published three compromised versions of the package: 9.1.6, 9.2.3, and 12.0.1 CSO Online. The injected malicious CommonJS bundle contained an obfuscated ~80KB credential stealer designed to exfiltrate database keys, cloud secrets (AWS, Azure, GCP), SSH keys, and AI agent keys via DNS TXT queries to evade egress network filters Snyk Vulnerability Database. Use the lockfile, package-cache, and DNS TXT hunt recipes below to determine whether these versions executed and which identities were exposed.
Key Facts
threat_type: "Maintainer Account Takeover & Expired Domain Hijacking"
ecosystem: "npm, javascript, node.js"
registry: "npm Registry"
affected_packages:
- "node-ipc"
malicious_versions:
- "9.1.6"
- "9.2.3"
- "12.0.1"
fixed_versions:
- "9.1.7"
- "9.2.4"
- "12.0.2"
safe_versions:
- "9.1.5"
- "9.2.2"
- "12.0.0"
exposure_window: "2026-05-14T02:30:00Z to 2026-05-14T14:45:00Z"
execution_trigger: "Importing or requiring the malicious package via `require('node-ipc')` during project runtime or testing"
primary_impact: "Developer workstation and CI/CD runner host credential harvesting, with stealthy DNS TXT exfiltration"
known_iocs:
- "atlantis-software[.]net"
- "dns.atlantis-software[.]net"
confidence: "high"
canonical_source: "https://snyk.io"
Source Confidence & Evidence Mapping
- confirmed:
- Malicious versions published on npm under
node-ipcwere 9.1.6, 9.2.3, and 12.0.1. Source: Snyk Vulnerability Database - The hijacking was achieved by re-registering the expired domain
atlantis-software.netused by lead maintaineratiertant. Source: CSO Online - Obfuscated payload of approximately 80KB was injected directly into
node-ipc.cjs. Source: Daily.dev Blog - Data exfiltration leveraged DNS TXT records pointing to attacker-controlled name servers on the hijacked domain. Source: Cybersecurity News
- Malicious versions published on npm under
- likely:
- The dormant maintainer account lacked mandatory multi-factor authentication (MFA) or fell victim to legacy account recovery flows. Source: CSO Online
- unclear:
- Exact number of downstream organizations infected during the 12-hour exposure window. Source: Daily.dev Blog
Impact Determination
| Classification | Criteria | Required evidence | Required action | Closure condition |
|---|---|---|---|---|
| Confirmed compromise | [email protected], 9.2.3, or 12.0.1 is present and Node.js import loads the malicious CommonJS bundle or the reported process, file, or network indicators is observed. | Artifact inventory plus runtime telemetry showing Node.js import loads the malicious CommonJS bundle or listed C2/process/file indicators. | Isolate affected hosts or runners, preserve artifacts, and rotate reachable credentials from a clean environment. | Affected artifacts are removed, exposed credentials are replaced, and downstream audit modules show no suspicious follow-on use. |
| Presumed exposed | [email protected], 9.2.3, or 12.0.1 was installed, pulled, imported, built, or executed during the exposure window, but telemetry cannot prove exfiltration. | Lockfile, package cache, workflow, image pull, extension inventory, build log, or deployment record tied to the exposure window. | Rebuild from clean artifacts and rotate credentials available to the affected environment. | Credential owners confirm revocation of old material and clean artifacts are deployed. |
| Potentially exposed | The package, workflow, image, extension, or module appears in dependency or deployment records, but npm lifecycle execution is not established. | Manifest, lockfile, build, deployment, or endpoint records plus a named telemetry gap. | Collect the missing execution and telemetry evidence before narrowing scope. | Every hit is dispositioned as confirmed compromise, presumed exposed, or not exposed. |
| Not exposed | No affected version, artifact, mutable reference, or indicator appears in source, lockfiles, build outputs, deployments, package caches, or runtime telemetry. | Repository search, dependency inventory, build/deployment export, package cache query, and runtime telemetry query results. | Preserve the negative search output and keep the prevention controls active. | Search evidence covers developer endpoints, CI runners, production deployments, and package or image caches. |
| Unknown | Required inventory, build, endpoint, network, or audit telemetry is unavailable. | A gap statement naming unavailable systems, owners, and time windows. | Keep the asset in scope and make conservative rotation or rebuild decisions for high-value environments. | The missing evidence is recovered or the risk owner accepts residual uncertainty. |
Minimum Evidence To Collect
minimum_evidence:
- "Dependency, workflow, extension, image, or module inventory covering developer endpoints, CI runners, and production deployments."
- "Positive or negative search results for [email protected], [email protected], [email protected]."
- "Execution evidence for Node.js import loads the malicious CommonJS bundle."
- "Process, file, DNS, proxy, firewall, or package-manager telemetry for listed indicators."
- "Inventory of credentials, tokens, deployment paths, and downstream systems reachable from exposed environments."
Timeline
- 2025-01-15T00:00:00Z The domain
atlantis-software.netexpires and enters redemption state. Source: Cybersecurity News - 2026-05-10T12:00:00Z Attackers discover the expired domain and register it via a public registrar. Source: Daily.dev Blog
- 2026-05-14T02:30:00Z Attackers complete the npm account recovery, take over the
atiertantaccount, and publish9.1.6,9.2.3, and12.0.1. Source: CSO Online - 2026-05-14T07:15:00Z Security automated pipelines at Socket and Snyk trigger anomaly alerts on unexpected codebase increases and domain association checks. Source: Snyk Vulnerability Database
- 2026-05-14T14:45:00Z The npm security team revokes the compromised credentials, removes the malicious versions, and blocks the compromised account. Source: CSO Online
What Happened
On May 14, 2026, the maintainers of several high-profile downstream projects noticed Snyk alerts indicating that node-ipc had published minor versions with a massive file size inflation CSO Online. Snyk and Socket researchers quickly mapped the release of 9.1.6, 9.2.3, and 12.0.1 to the npm account of atiertant, a dormant developer who had not contributed to the main codebase in over two years Snyk Vulnerability Database. Upon checking the registrant status of the maintainer’s contact email domain (atlantis-software.net), analysts discovered the domain was registered just four days prior by a private entity using a different registrar than the original registrant Cybersecurity News. It became clear that the threat actors re-registered the expired domain to intercept the password-reset email sent by the npm registry Daily.dev Blog. Armed with access to the npm account, they injected an 80KB credential stealer payload directly into the compiled CJS files, bypassing standard git commit hooks and CI checks entirely since the malicious release was pushed directly from the hijacked maintainer account to the npm registry Snyk Vulnerability Database.
Technical Analysis
Initial Access
Initial access was gained via an expired email domain takeover CSO Online. The attackers scanned package metadata directories of highly popular npm packages to find dormant maintainer accounts that used domain-based email addresses that were currently available for public registration Cybersecurity News. Once atlantis-software.net was identified as expired, it was re-registered for less than $15, allowing the threat actors to spin up an MX mail server, receive the reset token from npm, and instantly take over account access Daily.dev Blog.
Package or Artifact Manipulation
The threat actor did not compromise the GitHub repository RIAEvangelist/node-ipc. Instead, they bypassed source control entirely. They downloaded the legitimate versions of 9.1.5, 9.2.2, and 12.0.0, modified the bundled distribution files (node-ipc.cjs) by appending the obfuscated payload, updated package.json to bump the versions to 9.1.6, 9.2.3, and 12.0.1, and published directly to npm using the hijacked publishing token CSO Online.
Execution Trigger
The malware executes automatically at import-time Snyk Vulnerability Database. As soon as any dependency or root project loads node-ipc via:
const ipc = require('node-ipc');
the Immediately Invoked Function Expression (IIFE) appended to the end of the node-ipc.cjs bundle is triggered in the Node.js runtime Daily.dev Blog.
Payload Behavior
Upon execution, the payload performs the following actions:
- Environment Enumeration: Iterates through
process.envlooking for secrets. - File System Scanning: Scans typical system directories (
~/.aws/,~/.ssh/,~/.kube/) and searches developer workspaces for.envandconfig.jsoncontaining cloud API keys and authentication tokens. - Target Collection: Gathers over 90 different kinds of sensitive configurations (specifically looking for npm publishing tokens, AWS keys, GCP keys, Kubernetes configurations, and developer tools like Cursor/Copilot configurations).
Exfiltration / C2
To bypass strict firewalls and egress proxies that block HTTP/HTTPS traffic to unrecognized domains, the malware compresses the stolen credentials, encodes them in Base32 chunks, and exfiltrates the data using DNS TXT record queries Cybersecurity News.
<base32_chunk>.<unique_session_id>.dns.atlantis-software[.]net
By querying their own custom nameserver hosted on dns.atlantis-software[.]net, the attackers successfully bypass corporate web proxies and egress security monitors which routinely allow outbound system DNS resolution Snyk Vulnerability Database.
Propagation
The malware does not possess lateral worm propagation vectors; it remains a static, target-harvesting payload.
Obfuscation or Evasion
The appended malicious script was heavily obfuscated using a commercial JS obfuscator, hiding strings and variables inside a massive nested hex-encoded dictionary to prevent signature-based detection by standard npm package scanners Daily.dev Blog.
Affected Assets and Blast Radius
affected_assets:
ecosystems:
- "npm"
packages:
- "node-ipc"
versions:
- "9.1.6"
- "9.2.3"
- "12.0.1"
repositories:
- "RIAEvangelist/node-ipc"
container_images: []
CI_CD_systems:
- "GitHub Actions runners"
- "GitLab CI runners"
developer_tools:
- "Developer workstations"
credentials_at_risk:
- AWS access keys
- GCP service account keys
- Azure authentication secrets
- SSH private keys
- npm publishing tokens
- Kubernetes service tokens
- AI developer tool API keys
Indicators of Compromise
Domains
atlantis-software[.]net(source:https://snyk.io, confidence:high)dns.atlantis-software[.]net(source:https://snyk.io, confidence:high)
Network Logs
- DNS lookup requests ending with
.dns.atlantis-software[.]netor queries of typeTXTsent to authority servers ofatlantis-software[.]net.
Package Versions
Detection and Hunting
Script: local repository and exported telemetry scope
#!/usr/bin/env python3
import os
import sys
import json
import subprocess
from pathlib import Path
ROOT = sys.argv[1] if len(sys.argv) > 1 else "."
LOG_ROOT = os.environ.get("LOG_ROOT", "")
OUT = Path(os.environ.get("OUT", "hp-node-ipc-expired-domain-takeover-scope"))
SINCE = "2025-01-15T00:00:00Z"
UNTIL = "2026-05-14T23:59:59Z"
PACKAGES = [
"node-ipc",
]
VERSIONS = [
"9.1.6",
"9.2.3",
"12.0.1",
]
FILES = [
]
DOMAINS = [
]
URLS = [
"https://snyk.io`",
]
IPS = [
]
HASHES = [
]
PROCESS_PATTERNS = [
]
NETWORK_PATTERNS = [
]
# Positive signal: repository, lockfile, artifact, process, or network telemetry contains one of the exact incident selectors above.
# Escalation: any match tied to a production build, CI run, deployed asset, or secret-bearing host moves the asset to presumed exposed.
OUT.mkdir(parents=True, exist_ok=True)
indicators_file = OUT / "indicators.txt"
# Collect unique indicators
indicators = set()
for group in [PACKAGES, VERSIONS, FILES, DOMAINS, URLS, IPS, HASHES, PROCESS_PATTERNS, NETWORK_PATTERNS]:
for val in group:
if val:
indicators.add(val)
with open(indicators_file, "w") as f:
for ind in sorted(indicators):
f.write(ind + "\n")
print(f"[+] Written unique selectors to {indicators_file}")
# Walk local directory
print(f"[+] Scanning directory: {ROOT} for selectors...")
matches = []
exclude_dirs = {"node_modules", "vendor", "dist", ".git"}
for root, dirs, filenames in os.walk(ROOT):
dirs[:] = [d for d in dirs if d not in exclude_dirs]
for filename in filenames:
filepath = Path(root) / filename
try:
content = filepath.read_text(errors="ignore")
for ind in indicators:
if ind in content:
matches.append(f"{filepath}: found '{ind}'")
except Exception:
pass
if matches:
(OUT / "repository-indicator-matches.txt").write_text("\n".join(matches) + "\n")
print(f"[!] Found {len(matches)} matches in codebase!")
# Optional Log Scanning
if LOG_ROOT and os.path.exists(LOG_ROOT):
print(f"[+] Scanning telemetry log directory: {LOG_ROOT}...")
log_matches = []
for root, _, filenames in os.walk(LOG_ROOT):
for filename in filenames:
filepath = Path(root) / filename
try:
content = filepath.read_text(errors="ignore")
for ind in indicators:
if ind in content:
log_matches.append(f"{filepath}: found '{ind}'")
except Exception:
pass
if log_matches:
(OUT / "exported-telemetry-indicator-matches.txt").write_text("\n".join(log_matches) + "\n")
print(f"[!] Found {len(log_matches)} matches in logs!")
if PACKAGES:
registry_dir = OUT / "registry"
registry_dir.mkdir(exist_ok=True)
for package in PACKAGES:
if not package: continue
safe_name = package.replace("/", "__")
print(f"[+] Querying npm view for {package}...")
res = subprocess.run(["npm", "view", package, "name", "version", "time", "versions", "dist-tags", "maintainers", "dist.tarball", "dist.integrity", "scripts", "--json"], capture_output=True, text=True)
if res.returncode == 0:
(registry_dir / f"npm-{safe_name}.json").write_text(res.stdout)
print(f"[+] Wrote scope artifacts under {OUT}")
Downstream Abuse Audits
Script: GitHub organization run, release, secret, and workflow audit
#!/usr/bin/env python3
import os
import sys
import json
import subprocess
from pathlib import Path
if "ORG" not in os.environ:
print("ERROR: Set ORG environment variable to the GitHub organization to audit", file=sys.stderr)
sys.exit(1)
ORG = os.environ["ORG"]
SINCE = "2025-01-15T00:00:00Z"
UNTIL = "2026-05-14T23:59:59Z"
OUT = Path(os.environ.get("OUT", "hp-node-ipc-expired-domain-takeover-github-audit"))
SELECTORS = [
"node-ipc",
"9.1.6",
"9.2.3",
"12.0.1",
"https://snyk.io`",
]
# Positive signal: a workflow run, release, secret, key, package, or workflow change overlaps the exposure window and references an incident selector.
# Remediation trigger: unauthorized post-exposure write activity or a secret-bearing run matching an incident selector requires token revocation and downstream cloud/registry review.
OUT.mkdir(parents=True, exist_ok=True)
(OUT / "runs").mkdir(exist_ok=True)
(OUT / "logs").mkdir(exist_ok=True)
(OUT / "repos").mkdir(exist_ok=True)
# 1. Write incident-selectors file
selectors_file = OUT / "incident-selectors.txt"
with open(selectors_file, "w") as sf:
for s in SELECTORS:
if s:
sf.write(s + "\n")
# 2. Get list of repos
print(f"[+] Fetching repositories for organization: {ORG}")
repo_res = subprocess.run(["gh", "repo", "list", ORG, "--limit", "1000", "--json", "nameWithOwner"], capture_output=True, text=True)
if repo_res.returncode != 0:
print(f"[-] Failed to fetch repos: {repo_res.stderr}", file=sys.stderr)
sys.exit(1)
repos = [r["nameWithOwner"] for r in json.loads(repo_res.stdout)]
for repo in repos:
safe_repo = repo.replace("/", "__")
print(f"[+] Auditing repository: {repo}")
# Check runs in the window
runs_res = subprocess.run([
"gh", "api", f"/repos/{repo}/actions/runs",
"-f", "per_page=100",
"-f", f"created=>={SINCE}",
"--paginate"
], capture_output=True, text=True)
if runs_res.returncode == 0:
try:
all_runs = json.loads(runs_res.stdout).get("workflow_runs", [])
filtered_runs = [r for r in all_runs if r["created_at"] <= UNTIL]
if filtered_runs:
with open(OUT / "runs" / f"{safe_repo}-runs.jsonl", "w") as rf:
for run in filtered_runs:
rf.write(json.dumps(run) + "\n")
# Fetch log dynamically
run_id = str(run["id"])
log_res = subprocess.run(["gh", "run", "view", run_id, "--repo", repo, "--log"], capture_output=True, text=True)
if log_res.returncode == 0:
(OUT / "logs" / f"{safe_repo}-{run_id}.log").write_text(log_res.stdout)
# Fetch details
view_res = subprocess.run(["gh", "run", "view", run_id, "--repo", repo, "--json", "databaseId,workflowName,headSha,event,createdAt,jobs"], capture_output=True, text=True)
if view_res.returncode == 0:
(OUT / "runs" / f"{safe_repo}-{run_id}.json").write_text(view_res.stdout)
except Exception as e:
print(f"[-] Error parsing runs for {repo}: {e}")
# Check releases in window
subprocess.run(["gh", "api", f"/repos/{repo}/releases", "-f", "per_page=100", "--paginate"], capture_output=True)
# Check repo secrets updated in window
subprocess.run(["gh", "api", f"/repos/{repo}/actions/secrets", "-f", "per_page=100", "--paginate"], capture_output=True)
# Check deploy keys
subprocess.run(["gh", "api", f"/repos/{repo}/keys", "-f", "per_page=100", "--paginate"], capture_output=True)
# Scan output directory for any indicator selector matches
print("[+] Scanning gathered telemetry for indicator matches...")
subprocess.run(["rg", "-n", "--hidden", "--fixed-strings", "-f", str(selectors_file), str(OUT)], capture_output=False)
print(f"[+] Wrote GitHub audit artifacts under {OUT}")
Script: cloud OIDC and deployment credential follow-on audit
#!/usr/bin/env python3
import os
import json
import subprocess
from pathlib import Path
SINCE = "2025-01-15T00:00:00Z"
UNTIL = "2026-05-14T23:59:59Z"
OUT = Path(os.environ.get("OUT", "hp-node-ipc-expired-domain-takeover-cloud-audit"))
AWS_REGIONS = os.environ.get("AWS_REGIONS", "us-east-1").split(",")
# Positive signal: token exchange or privileged write activity occurs in the exposure window from GitHub, CI/CD, package registry, or deployment automation identity.
# Remediation trigger: unexpected write, deploy, IAM, secret, or registry activity tied to an exposed CI/CD path requires trust-policy disablement and credential rotation.
OUT.mkdir(parents=True, exist_ok=True)
# 1. AWS CloudTrail Audit
print("[+] Querying AWS CloudTrail for Web Identity token exchanges...")
aws_events = []
for region in AWS_REGIONS:
res = subprocess.run([
"aws", "cloudtrail", "lookup-events",
"--region", region,
"--start-time", SINCE,
"--end-time", UNTIL,
"--lookup-attributes", "AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity",
"--output", "json"
], capture_output=True, text=True)
if res.returncode == 0:
try:
events = json.loads(res.stdout).get("Events", [])
for event in events:
ct = json.loads(event.get("CloudTrailEvent", "{}"))
ct["region"] = region
aws_events.append(ct)
except Exception as e:
print(f"[-] Error parsing AWS CloudTrail events: {e}")
if aws_events:
with open(OUT / "aws-assume-role-with-web-identity.jsonl", "w") as f:
for ev in aws_events:
f.write(json.dumps(ev) + "\n")
# Audit follow-on events for returned access keys
for ev in aws_events:
access_key = ev.get("responseElements", {}).get("credentials", {}).get("accessKeyId")
region = ev.get("region", "us-east-1")
if access_key:
print(f"[+] Enumerating AWS events for AccessKey: {access_key}")
f_res = subprocess.run([
"aws", "cloudtrail", "lookup-events",
"--region", region,
"--start-time", SINCE,
"--end-time", UNTIL,
"--lookup-attributes", f"AttributeKey=AccessKeyId,AttributeValue={access_key}",
"--output", "json"
], capture_output=True, text=True)
if f_res.returncode == 0:
try:
f_events = json.loads(f_res.stdout).get("Events", [])
with open(OUT / "aws-follow-on-api-calls.jsonl", "a") as ff:
for fe in f_events:
ff.write(fe.get("CloudTrailEvent", "{}") + "\n")
except Exception as e:
print(f"[-] Error writing follow-on events: {e}")
# 2. Azure Activity Log Audit
print("[+] Querying Azure activity logs...")
az_res = subprocess.run([
"az", "monitor", "activity-log", "list",
"--start-time", SINCE,
"--end-time", UNTIL,
"--query", "[?contains(operationName.value, 'write') || contains(operationName.value, 'delete') || contains(operationName.value, 'Microsoft.ManagedIdentity')]",
"-o", "json"
], capture_output=True, text=True)
if az_res.returncode == 0:
(OUT / "azure-write-delete-activity.json").write_text(az_res.stdout)
# 3. GCP Logging Audit
print("[+] Querying GCP Cloud Logging...")
gcp_filter = f'timestamp>="{SINCE}" AND timestamp<="{UNTIL}" AND (protoPayload.methodName="google.sts.v1.SecurityTokenService.ExchangeToken" OR protoPayload.methodName:"GenerateAccessToken" OR protoPayload.methodName:"CreateServiceAccountKey" OR protoPayload.methodName:"SetIamPolicy")'
gcp_res = subprocess.run([
"gcloud", "logging", "read", gcp_filter,
"--format", "json"
], capture_output=True, text=True)
if gcp_res.returncode == 0:
(OUT / "gcp-token-and-iam-activity.json").write_text(gcp_res.stdout)
print(f"[+] Wrote cloud audit artifacts under {OUT}")
Script: registry metadata and artifact audit
#!/usr/bin/env python3
import os
import json
import subprocess
from pathlib import Path
SINCE = "2025-01-15T00:00:00Z"
OUT = Path(os.environ.get("OUT", "hp-node-ipc-expired-domain-takeover-registry-audit"))
PACKAGES = [
"node-ipc",
]
VERSIONS = [
"9.1.6",
"9.2.3",
"12.0.1",
]
# Positive signal: registry metadata, package tarballs, or cached artifacts contain the exact affected package/version values.
# Remediation trigger: any internal package cache, build artifact, or deployment using these package/version values requires exposure scoping.
OUT.mkdir(parents=True, exist_ok=True)
with open(OUT / "affected-versions.txt", "w") as av:
for version in VERSIONS:
if version:
av.write(version + "\n")
# 1. Audit npm dependencies in lockfiles/package.json
print("[+] Scanning lockfiles for npm selectors...")
for file in ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "package.json"]:
if Path(file).exists():
subprocess.run(["rg", "-n", "--hidden", "--fixed-strings", "-f", str(OUT / "affected-versions.txt"), file])
# 2. Query registry metadata and fetch tarballs for local analysis
metadata_dir = OUT / "metadata"
tarballs_dir = OUT / "tarballs"
metadata_dir.mkdir(exist_ok=True)
tarballs_dir.mkdir(exist_ok=True)
for package in PACKAGES:
if not package: continue
safe_name = package.replace("/", "__")
print(f"[+] Querying npm view for {package}...")
res = subprocess.run(["npm", "view", package, "time", "versions", "dist-tags", "maintainers", "dist.tarball", "dist.integrity", "scripts", "--json"], capture_output=True, text=True)
if res.returncode == 0:
(metadata_dir / f"npm-{safe_name}.json").write_text(res.stdout)
subprocess.run(["npm", "pack", package, "--pack-destination", str(tarballs_dir)], capture_output=True)
# 3. HOW TO REVOKE AND ROTATE EXPOSED NPM PUBLISHING TOKENS:
# Revoke all compromised tokens via npm CLI:
# subprocess.run(["npm", "token", "list"])
# subprocess.run(["npm", "token", "revoke", "123456"])
# Or logout to revoke the current session:
# subprocess.run(["npm", "logout"])
# Generate a new publishing token with MFA protection:
# subprocess.run(["npm", "token", "create", "--read-only=false", "--cidr=0.0.0.0/0"])
print(f"[+] Wrote registry audit artifacts under {OUT}")
Sources
- Snyk Advisory for node-ipc - Role: DIRECT_SOURCE - Impact: Detailed package versions, fixed releases, and security advisory mapping.
- CSO Online Attack Coverage - Role: PRIMARY_RESEARCH - Impact: Detailed explanation of the expired domain re-registration vector and the dormant account hijacking timeline.
- Cybersecurity News DNS Exfil Analysis - Role: SECONDARY_ANALYSIS - Impact: In-depth technical breakdown of the Base32 DNS TXT query exfiltration mechanism.
- Daily.dev Package Analysis - Role: PRIMARY_RESEARCH - Impact: Obfuscated payload identification and system enumeration targets.
- Landh.tech Anomaly Reports - Role: SECONDARY_ANALYSIS - Impact: Initial alert timeline and anomaly signal mapping.
IOC Clipboard
1 IOCshttps://snyk.io` hxxps://snyk[.]io`