Safeguard
Supply Chain Security•

mbt and @cap-js npm Compromise: How to Check, What to Rotate

Malicious mbt 1.2.48 and @cap-js releases ran a credential stealer at install on 29 April 2026. Check lockfiles and CI logs, rotate secrets, harden CI.

Safeguard Security Team
24 min read

On 29 April 2026, malicious versions of mbt and three @cap-js database packages from SAP's open source tooling ran a credential stealer from a preinstall hook. Any laptop or CI runner that installed mbt@1.2.48, @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2 or @cap-js/db-service@2.10.1 should be treated as compromised. Check lockfiles and CI logs, rotate every reachable secret, then upgrade.

This was months ago, but lockfiles from late April still sit in old branches, CI caches and container layers. Below: the verified facts, how to prove whether you installed a bad version, what to rotate, and what would have helped. Safeguard does not detect malicious packages; its part is inventory and response.

What happened

The four packages belong to SAP's developer tooling. mbt is the Cloud MTA Build Tool used to build multitarget application archives. The @cap-js packages are database adapters for the SAP Cloud Application Programming Model (CAP), which Onapsis describes as the de facto framework for custom development on SAP BTP. Socket put weekly downloads at roughly 260,000 for @cap-js/db-service, 250,000 for @cap-js/sqlite, 52,000 for mbt and 10,000 for @cap-js/postgres.

The bad versions arrived by two different routes, a detail that matters for the lessons later.

  • mbt was published from the cloudmtabot npm account. StepSecurity says the package did not use OIDC trusted publishing, so the attacker most likely used a stolen long-lived npm automation token. BleepingComputer cites security engineer Adnan Khan's report that a token may have been exposed through a misconfigured CircleCI job. The exact channel has not been confirmed.
  • The three @cap-js packages were published through the project's own GitHub Actions release path. According to StepSecurity and The Hacker News, a developer's GitHub account was compromised and commits were pushed to a non-main branch of cap-js/cds-dbs. SafeDep, as quoted by The Hacker News, said the npm trusted publisher setting trusted any workflow in the repository, not only the release workflow on main. A branch push could therefore obtain a publish token. SAP's own fix PR says the workflow had publish rights with no manual approval gate.

Timeline

All times UTC. Registry times come from the npm registry metadata we fetched on 22 October 2026.

Date and timeEventSource
24 Apr, 11:29mbt@1.2.47 published (last version before the incident)npm registry
29 Apr, 09:55:25mbt@1.2.48 published from the cloudmtabot accountnpm registry, Snyk, StepSecurity
29 Apr, 10:01:07First victim dead drop repository appears on GitHubSnyk
29 Apr, about 11:23First malicious commit pushed to a release branch of cap-js/cds-dbsStepSecurity
29 Apr, 11:25:47@cap-js/sqlite@2.2.2 publishednpm registry
29 Apr, 12:14@cap-js/postgres@2.2.2 and @cap-js/db-service@2.10.1 publishedOnapsis, Snyk
29 Apr, 13:33 to 13:46Clean @cap-js releases published through SAP's OIDC trusted publisher, including @cap-js/sqlite@2.4.0 at 13:46Onapsis, Snyk, npm registry
29 Apr, 16:15:54mbt@1.2.49 published; maintainers call it "not infected" and say it was released manuallynpm registry, GitHub issue #1224
30 Apr, 02:33npm confirms mbt@1.2.48 removed, per the maintainerGitHub issue #1224
30 AprSAP releases Security Note 3747787 covering the four packagesOnapsis
4 MaySAP merges PR #1592: npm publishing now needs a human approval, and workflows are pinned to commit SHAscap-js/cds-dbs PR #1592
14 MayAdvisory GHSA-pvw4-cvr4-97p8 (CVE-2026-46421) published on cap-js/cds-dbsGitHub
19 MayA separate compromised release, @cap-js/openapi@1.4.1, is published; fixed in 1.4.2GitHub advisory GHSA-jpvj-wpmj-h7rv
20 MayGHSA-pvw4-cvr4-97p8 reviewed in the GitHub Advisory DatabaseGitHub

What SAP has said publicly

SAP's formal guidance is Security Note 3747787, which sits behind an SAP login, and a linked SAP document that returned an access error when we tried to fetch it. The public record from SAP's own engineers is in GitHub:

  • In the mbt issue, a maintainer posted the release times above and said only the npm package was affected, with no GitHub or Dockerfile release of 1.2.48.
  • In cds-dbs, the fix PR says an unauthorized actor pushed commits that hijacked the release workflow, and moves publishing into a job a reviewer must approve.
  • The cds-dbs advisory says to treat all credentials on any machine that installed a bad version as compromised: npm tokens, cloud credentials, SSH keys and GitHub personal access tokens. It lists no workarounds.

Attribution

Wiz said the packages match several features of earlier TeamPCP operations, including a shared RSA public key, according to The Hacker News. Socket and BleepingComputer link it to TeamPCP with medium confidence. Researchers call it "Mini Shai-Hulud," the same phrase the malware writes on its exfiltration repositories. For the family's history, see our Shai-Hulud explainer.

Who is affected

PackageMalicious versionMove toNotesSource
mbt1.2.481.2.49 or later (latest is 1.2.49)Removed from the registry; 1.2.49 was released manually and maintainers describe it as functionally identical to 1.2.47npm registry, issue #1224
@cap-js/sqlite2.2.22.4.0 or laterRemoved from the registryGHSA-pvw4-cvr4-97p8, npm registry
@cap-js/postgres2.2.22.3.0 or laterGHSA-pvw4-cvr4-97p8
@cap-js/db-service2.10.12.11.0 or laterCan arrive transitively through @cap-js/sqlite@2.2.2GHSA-pvw4-cvr4-97p8, Snyk
@cap-js/openapi1.4.1 (19 May, separate event)1.4.2 or laterCVSS 3.1 base 9.6GHSA-jpvj-wpmj-h7rv

Snyk notes that @cap-js/sqlite@2.2.2 declares @cap-js/db-service@^2.10.0, so a project that never listed db-service could still resolve 2.10.1 during the window. Snyk also observed that while it was writing, mbt@1.2.48 was still the latest tag, so a bare npm install mbt got the bad tarball.

Onapsis says the most exposed are Node.js apps on SAP BTP, CAP and Fiori backends, and MTA projects pulling @sap/* and @cap-js/* with loose ranges. One user asked in the mbt issue whether the mbt preinstalled in SAP Business Application Studio was affected; the thread has no answer, so check it directly.

How it works

No exploit details here, only what you need to recognise it and respond.

The install hook

Each malicious release added "preinstall": "node setup.mjs" to its manifest. StepSecurity notes that clean mbt@1.2.47 has no scripts block at all, so a new install hook was itself the signal. npm runs lifecycle scripts automatically, so the code ran before any of your code and whether or not you ever imported the package. Onapsis points out that because it runs at preinstall, credentials may be stolen even if the install fails or is cancelled.

setup.mjs is a small loader. Per Socket and StepSecurity, it checks whether Bun is on PATH, downloads Bun 1.3.13 from GitHub Releases if not, and uses it to run execution.js, an obfuscated single line file of about 11.6 MB. Running under Bun keeps it away from tooling that only watches Node.

What it takes

Across StepSecurity, Socket, Snyk and The Hacker News, the payload:

  • Harvests npm and GitHub tokens (including the output of gh auth token), AWS, Azure and GCP credentials and the contents of AWS Secrets Manager and GCP Secret Manager it can reach, Kubernetes configs, SSH keys, Docker and git credentials, .npmrc, .env files, shell history, crypto wallets, VPN profiles and messaging app data.
  • Reads AI tool configs such as ~/.claude.json and MCP settings, probes cloud metadata endpoints, and, per Wiz via The Hacker News, steals saved browser passwords.
  • On Linux GitHub Actions runners, reads the memory of the Runner.Worker process to pull secrets out directly. Socket says this bypasses "all log masking applied by the CI platform."

Counts differ: Socket says 25 CI platforms and 80 plus file patterns, StepSecurity about 32 and about 134. On a developer machine it detaches so npm install looks normal. It exits on a Russian locale.

Exfiltration, spread and persistence

Stolen data is compressed, encrypted with AES-256-GCM and the key wrapped with an embedded RSA-4096 public key, so defenders cannot read what was taken. It is committed to new public repositories created on the victim's own GitHub account with the description "A Mini Shai-Hulud has Appeared." The Hacker News counted more than 1,100 such repositories at the time of its report.

It then tries to spread. StepSecurity says it publishes infected versions of packages the victim can write to, straight through the registry API, and injects a format-check.yml workflow that dumps toJSON(secrets) into an artifact on a branch named to look like Dependabot.

For persistence it commits two files into repositories it can reach, authored as claude@users.noreply.github.com with the message "chore: update dependencies":

  • .claude/settings.json with a SessionStart hook, which runs when someone opens the project in Claude Code.
  • .vscode/tasks.json with a task set to run on folder open in VS Code.

Each one launches the payload copy stored next to the other, so removing one file is not enough. StepSecurity called this "one of the first supply chain attacks to target AI coding agent configurations" as a persistence vector.

How to check

Work through these in order. Run the checks from a machine you trust, not the one you suspect.

  1. Search the dependency tree in each project. npm ls shows transitive copies too.

    npm ls mbt @cap-js/sqlite @cap-js/postgres @cap-js/db-service @cap-js/openapi --all
    

    Any of the versions in the table above means that project resolved a bad release at some point.

  2. Search lockfiles across every branch, not only main. Tarball URLs are the most reliable string to grep for in package-lock.json and yarn.lock; pnpm records name@version.

    PATTERN='mbt-1\.2\.48\.tgz|sqlite-2\.2\.2\.tgz|postgres-2\.2\.2\.tgz|db-service-2\.10\.1\.tgz|openapi-1\.4\.1\.tgz|mbt@1\.2\.48|@cap-js/(sqlite|postgres)@2\.2\.2|@cap-js/db-service@2\.10\.1|@cap-js/openapi@1\.4\.1'
    for b in $(git for-each-ref --format='%(refname)' refs/heads refs/remotes); do
      git grep -nE "$PATTERN" "$b" -- '*package-lock.json' '*yarn.lock' '*pnpm-lock.yaml' 2>/dev/null
    done
    

    A hit in a @cap-js scoped URL (/@cap-js/sqlite/-/sqlite-2.2.2.tgz) is what you care about; ignore unrelated packages with the same file name pattern.

  3. Check the npm cache on developer machines. A cache entry proves the tarball was downloaded on that machine, even if the project was later fixed.

    grep -rlE 'mbt-1\.2\.48\.tgz|@cap-js/(sqlite|postgres)/-/(sqlite|postgres)-2\.2\.2\.tgz|db-service-2\.10\.1\.tgz' ~/.npm/_cacache/index-v5 2>/dev/null | head
    
  4. Check CI history for the window. For GitHub Actions, list runs on 29 April (and 19 May if you use @cap-js/openapi) and search their logs.

    gh run list --created 2026-04-29 --limit 500 --json databaseId,workflowName,createdAt
    gh run view <run-id> --log | grep -nE 'mbt@1\.2\.48|setup\.mjs|bun-v1\.3\.13|execution\.js'
    

    If logs have expired, check which jobs ran npm install without a lockfile that day, and any caches or images built then.

  5. Look for files on disk. In projects and CI caches:

    find . -path '*/node_modules/*' -name setup.mjs -maxdepth 5 2>/dev/null
    shasum -a 256 $(find . -path '*/node_modules/*' -name setup.mjs -maxdepth 5 2>/dev/null)
    ls -la .claude/settings.json .claude/setup.mjs .claude/execution.js .vscode/tasks.json .vscode/setup.mjs 2>/dev/null
    ps aux | grep -i '[b]un'
    

    StepSecurity and Onapsis publish the loader hash 4066781fa830224c8bbcc3aa005a396657f9c8f9016f9a64ad44a9d7f5f45e34.

  6. Look for the GitHub side effects. For each user and organisation:

    gh repo list <account> --visibility public --limit 500 --json name,description,createdAt \
      | grep -i 'shai-hulud'
    git log --all --author='claude@users.noreply.github.com' --oneline
    git log --all --grep='OhNoWhatsGoingOnWithGitHub' --oneline
    git branch -a | grep -i dependabout
    

    Also search workflow files for toJSON(secrets) and check your npm packages' publish history for versions you did not release.

  7. Check cloud audit logs around the time of any install you find. Onapsis suggests looking for calls such as GetSecretValue from developer IPs or CI runners shortly after an install.

If steps 1 to 4 are clean everywhere, including old branches, caches and images, you are very likely unaffected.

What to rotate, and in what order

  1. Isolate the machine or runner. Disconnect it, then work from a clean machine. Do not revoke tokens from the infected one.

  2. Revoke npm publish tokens first. They are how the worm spreads to packages you maintain. Then check whether any of your packages got new versions you did not publish, and deprecate or unpublish them.

  3. Revoke GitHub tokens: personal access tokens, OAuth tokens behind gh, deploy keys and any GitHub App credentials on the host. Check gh auth status from the clean machine afterwards.

  4. Rotate CI secrets for every workflow that ran an install on an affected runner. On GitHub hosted Linux runners, assume every secret available to that job was read from memory, whether or not it was printed.

  5. Rotate cloud credentials: AWS, Azure and GCP keys, and the secrets in Secrets Manager, Key Vault and Secret Manager that those identities could read. Rotating the access key alone leaves the stored secrets exposed.

  6. Rotate the rest: SSH keys, Kubernetes service account tokens and kubeconfigs, Docker registry credentials, .env values, AI provider and MCP server keys, and passwords saved in browsers on that machine.

  7. Clean the repositories. Remove .claude/settings.json hooks and .vscode/tasks.json tasks you did not write, the setup.mjs and execution.js copies, the injected workflow and branch. Delete the public dead drop repositories on your accounts. Check every branch, since StepSecurity says it commits to up to 50 per repository.

  8. Reinstall cleanly. Pin the fixed versions, delete node_modules, clean the cache with npm cache clean --force, regenerate the lockfile with scripts off, and review what changed:

    npm install mbt@1.2.49 @cap-js/sqlite@^2.4.0 @cap-js/db-service@^2.11.0 @cap-js/postgres@^2.3.0 --ignore-scripts
    npm ls mbt @cap-js/sqlite @cap-js/db-service @cap-js/postgres --all
    git diff package-lock.json
    

    If a package you trust needs its install script, run npm rebuild <package> for that one after review. Adjust the major versions to what your CAP release supports; @cap-js/sqlite is on 3.x now.

  9. Rebuild and redeploy images and MTA archives built from an affected tree, and purge CI caches that hold the old node_modules.

Our incident response playbook for a compromised dependency covers the communication and evidence side.

What would have helped

Practices any team can use

The tensorlake write up covered why provenance alone did not stop a similar worm. This one adds its own lessons.

For anyone who publishes packages:

  • No long lived publish tokens. The mbt route relied on a static token. Use OIDC trusted publishing so there is no token to steal.
  • Scope trusted publishing narrowly. The @cap-js route went through trusted publishing configured for the whole repository. Bind it to one workflow file, and put publishing in a protected GitHub environment with required reviewers, which is what SAP's PR #1592 does.
  • Pin actions to commit SHAs and protect release branches, so a pushed branch cannot rewrite the release job.
  • Fail the release if a lifecycle hook appears in a manifest that did not have one before.

For anyone who installs packages:

  • Turn off dependency install scripts by default and keep a reviewed allowlist. Our install script policy guide has the exact settings for npm, pnpm, Yarn and Bun.
  • Use a release cooldown. Every bad version here was replaced within hours. A one day minimum release age would have skipped all of them.
  • Commit lockfiles and install with npm ci in CI, so a caret range cannot resolve to a new release mid build. Pin exact versions for build tools such as mbt.
  • Separate install from secrets. Run dependency installation in a job that holds no deploy credentials, and pass artifacts to later jobs that do. Memory scraping on the runner makes "masked" secrets no protection.
  • Prefer short lived cloud credentials through OIDC in CI, and restrict runner egress where you can.
  • Review agent and editor config like code. Add .claude/, .vscode/ and .github/workflows/ to CODEOWNERS so hooks and tasks need a human approval, and keep VS Code workspace trust on.
  • Know what you run. A current inventory turns "are we affected?" into a query. See SBOM incident response.

Where Safeguard fits

Safeguard would not have detected or prevented this. It does not scan packages for malicious code, and it does not flag new install scripts or maintainer changes. A malicious release with no advisory looks to it like any other version. Its part is the inventory and the response.

Finding every affected project. safeguard scan --dir . builds an SBOM for a repository, safeguard scan --image <name> does the same for a container image, and safeguard scan --sbom <file> ingests an existing SBOM; results land as JSON under ./output. Once projects are in the platform, it shows which projects contain a given component and version, so "who has @cap-js/db-service 2.10.1, including transitively" is a lookup. Scanning images matters because a container built in April can still hold the old node_modules.

Matching against advisories. The @cap-js versions now carry CVE-2026-46421, so vulnerability matching against databases that include it flags them in later scans. We did not find a CVE for mbt@1.2.48, so search for it by name and version.

Keeping them out. Platform policies and gates evaluate what a build contains, which helps stop an old lockfile from bringing a known bad version back.

Doing the fix with approval. The Safeguard CLI's assistant can edit code and run commands on your machine. In the default flow it asks before each one, and /permissions offers Ask, Accept edits, Plan, Auto and Strict modes. You can ask it to bump these packages, regenerate the lockfile with --ignore-scripts, find and remove unexpected .claude/settings.json hooks and .vscode/tasks.json tasks, and run your tests. The desktop and phone apps can send that work to a computer running the CLI and approve each command. In CI, safeguard exec runs the checks. Rotation at npm, GitHub and your cloud provider is still yours to do.

Zero-Day Discovery and Gold

These address a different problem, and it is worth being exact about it.

  • Zero-Day Discovery looks for previously unknown vulnerabilities before a CVE exists, in an agentic mode and a deterministic scanner mode, across seven package ecosystems. Findings are issued as SGZ advisories before they reach public CVE databases. It hunts for flaws in code, not for deliberately planted malware, and it did not flag these releases.
  • Gold Open Source at gold.safeguard.sh is free with no login: searchable CVE intelligence with CVSS, EPSS, KEV status, affected and fixed versions and a recommended safe version, plus a free read API and a CI gate GitHub Action.
  • Gold Registry at registry.safeguard.sh is paid: hardened drop in components and container images held to zero exploitable critical or high CVEs, built to SLSA L3+, signed with Sigstore, with evidence pages. An artifact loses its badge if it regresses.

The habit that ties these together: pull dependencies from a curated, signed source, know exactly what you run, and be able to rebuild fast. For the wider picture of the month, see October 2026 security incidents and what would have helped.

Common mistakes

  • Upgrading and stopping there. The payload ran at install time. A clean lockfile today does nothing about tokens stolen in April.
  • Only checking direct dependencies. @cap-js/db-service came in through @cap-js/sqlite. Use npm ls --all.
  • Trusting masked CI logs. Masking hides values in output. It does not stop a process reading runner memory.
  • Revoking from the infected machine. Work from a clean host, and revoke npm tokens before anything else.
  • Deleting one persistence file. .claude/settings.json and .vscode/tasks.json each restart the payload from the other location. Remove both and their payload copies.
  • Reinstalling with scripts on. Regenerate the lockfile with --ignore-scripts and review before anything runs.

FAQ

Which versions were malicious?

mbt@1.2.48, @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2 and @cap-js/db-service@2.10.1, all published on 29 April 2026. A separate compromised release, @cap-js/openapi@1.4.1, followed on 19 May. Versions before and after those are not listed as affected in the advisories.

Which versions should I move to?

The cds-dbs advisory lists @cap-js/sqlite 2.4.0 or later, @cap-js/postgres 2.3.0 or later and @cap-js/db-service 2.11.0 or later. For mbt, 1.2.49 is the current latest. Use @cap-js/openapi 1.4.2 or later. Some reports list different "safe" numbers, so confirm against the advisory and the registry.

Is mbt 1.2.49 safe?

The maintainers say 1.2.49 is "not infected," released manually and functionally identical to 1.2.47. One user reported a Microsoft Defender detection of it, unconfirmed in the thread. If in doubt, compare its tarball with 1.2.47.

I only ran npm install once that day. Is that enough to be affected?

Yes, if it resolved a bad version. The hook runs during install, before your code, and Onapsis notes credentials may be taken even if the install fails. Check the lockfile and cache from that install.

Does using a lockfile protect me?

A lockfile pinned to a clean version and installed with npm ci would have kept the clean version. A lockfile that was regenerated or updated during the window, or an npm install that allowed range updates, would not.

Why does this attack touch Claude Code and VS Code settings?

To run again later. It commits a SessionStart hook in .claude/settings.json and a folder open task in .vscode/tasks.json, so anyone who opens the repository in those tools can restart the payload. Review changes to those files the way you review CI workflows.

Can Safeguard tell me if I installed one of these?

It can tell you where these package versions appear in the repositories, images and SBOMs you have scanned, which is the inventory half. It cannot tell you whether malicious code ran on a given machine or whether a secret was stolen. Use the CI log, cache and GitHub checks above for that.

Fix it without waiting for upstream

In incidents like this one, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.

3. Gold Registry: start from components that are already fixed

registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would have helped

None of these demos show this incident. Each is a real Safeguard session; the text says how the same flow applies here.

The first demo is a CLI session that fixes a lodash CVE: the assistant reads the finding and advisory, asks before each command, edits package.json, runs the install and tests with your approval, and pushes nothing. For this incident, you would open the same session in a CAP project and ask it to move @cap-js/sqlite to 2.4.0 or later, regenerate the lockfile with --ignore-scripts, run npm ls --all to prove db-service 2.10.1 is gone, and run your tests. It asks before each command.

Click through it at your own pace, or open it full screen.

The second demo is a desktop app session. The CLI session shows in the conversation list, you ask for work on your computer, pick the folder, then Approve or Deny each command and file edit, and it ends with an upgrade done and tests passing. Here you would pick a repository, ask it to find .claude/settings.json hooks and .vscode/tasks.json tasks that run setup.mjs, and approve each removal while you rotate tokens elsewhere.

Click through it at your own pace, or open it full screen.

The third demo is a real Android session: work is sent to a computer running the CLI, and the command is approved on the phone with Allow once, Allow for turn or Deny. During a cleanup across many repositories, that lets the on call engineer approve each lockfile regeneration from a phone, and deny anything that would run install scripts.

Click through it at your own pace, or open it full screen.

To try it on your own projects, download Safeguard and follow the CLI documentation.

Quick check

Your package.json lists only @cap-js/sqlite, never @cap-js/db-service. Can you skip checking db-service?

No. @cap-js/sqlite@2.2.2 declares @cap-js/db-service@^2.10.0, so an install during the window could pull the malicious 2.10.1 transitively. Run npm ls @cap-js/db-service --all and check the lockfile.

A CI job installed mbt@1.2.48, but its logs show every secret as masked. Are the secrets safe?

No. On Linux GitHub Actions runners the payload read the runner process memory, which Socket says bypasses log masking. Rotate every secret that job could access.

Sources

Last reviewed: 22 October 2026. This is a developing story; check the linked advisories for the latest status.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.