2025年11月24日沙丘蠕虫袭击事件死后分析报告
Post-mortem of Shai-Hulud attack on November 24th, 2025

原始链接: https://posthog.com/blog/nov-24-shai-hulud-attack-post-mortem

## PostHog 安全事件总结 11月24日,PostHog 经历了一次重大的安全漏洞,涉及恶意软件包发布到 npm。一种自我复制的蠕虫,Shai-Hulud 2.0,被用于破坏 Javascript SDK(posthog-node、posthog-js 等 – 完整列表见原始报告)。该蠕虫利用 `preinstall` 脚本扫描并窃取凭据,然后使用这些凭据进一步传播攻击。 PostHog 在 UTC 时间上午 9:30 之前识别并删除了恶意软件包,并开始撤销受损的凭据。攻击源于通过恶意拉取请求针对工作流文件(auto-assign-reviewers.yaml)获取的被盗 GitHub 个人访问令牌 (PAT),该文件用于自动分配审查者。对 GitHub `pull_request_target` 触发器的误解允许攻击者在受信任的 CI 环境中执行任意代码。 PostHog 已经采取措施减轻损害,包括收紧发布工作流程、加强 PR 审查流程、切换到 pnpm 10 以及改进密钥管理。他们强调固定依赖项到已知良好版本以及利用包管理器中的 `minimumReleaseAge` 等功能的重要性。此事件凸显了 CI/CD 安全的复杂性以及在整个软件供应链中实施健全安全实践的必要性。

## PostHog “沙伊-胡鲁德”攻击事件总结 一则Hacker News讨论围绕PostHog详细的11月24日安全事件的总结,该事件被命名为“沙伊-胡鲁德”攻击。攻击涉及一个恶意pull request,利用工作流程窃取了一个具有广泛仓库写入权限的GitHub个人访问令牌(PAT)。 攻击者修改了工作流程中的一个脚本,将密钥泄露到受控的webhook。PR被打开、执行和关闭都在一分钟内完成。虽然一个静态分析工具标记了潜在的可利用的工作流程,但它被驳回为误报。 评论者赞扬了PostHog的透明度,但质疑是否可以分析原始工作流程以改进检测。一些用户也批评了PostHog的网站设计,指出在不同浏览器和操作系统上存在可用性问题。这次讨论强调了自动运行来自非贡献者的pull request的工作流程的风险,以及健全安全措施的重要性。
相关文章

原文

At 4:11 AM UTC on November 24th, a number of our SDKs and other packages were compromised, with a malicious self-replicating worm - Shai-Hulud 2.0. New versions were published to npm, which contained a preinstall script that:

  1. Scanned the environment the install script was running in for credentials of any kind using Trufflehog, an open-source security tool that searches codebases, Git histories, and other data sources for secrets.

  2. Exfiltrated those credentials by creating a new public repository on GitHub and pushing the credentials to it.

  3. Used any npm credentials found to publish malicious packages to npm, propagating the breach.

By 9:30 AM UTC, we had identified the malicious packages, deleted them, and revoked the tokens used to publish them. We also began the process of rolling all potentially compromised credentials pre-emptively, although we had not at the time established how our own npm credentials had been compromised (we have now, details below).

The attack only affected our Javascript SDKs published in npm. The most relevant compromised packages and versions were:

  • posthog-node 4.18.1, 5.13.3 and 5.11.3
  • posthog-js 1.297.3
  • posthog-react-native 4.11.1
  • posthog-docusaurus 2.0.6
  • posthog-react-native-session-replay@1.2.2
  • @posthog/agent@1.24.1
  • @posthog/ai@7.1.2
  • @posthog/cli@0.5.15

If you are using the script version of PostHog you were not affected since the worm spread via the preinstall step when installing your dependencies on your development/CI/production machines.

If you are using one of our Javascript SDKs, our recommendations are to:

  1. Look for the malicious files locally, in your home folder, or your document roots:

find . -name "setup_bun.js" \

-o -name "bun_environment.js" \

-o -name "cloud.json" \

-o -name "contents.json" \

-o -name "environment.json" \

-o -name "truffleSecrets.json"

  1. Check npm logs for suspicious entries:

grep -R "shai" ~/.npm/_logs

grep -R "preinstall" ~/.npm/_logs

  1. Delete any cached dependencies:

rm -rf node_modules

npm cache clean --force

pnpm cache delete

Pin any dependencies to a known-good version (in our case, all the latest published versions, which have been published after we identified the attack, are known-good), and then reinstall your dependencies.

We also suggest you make use of the minimumReleaseAge setting present both in yarn and pnpm. By setting this to a high enough value (like 3 days), you can make sure you won't be hit by these vulnerabilities before researchers, package managers, and library maintainers have the chance to wipe the malicious packages.

PostHog's own package publishing credentials were not compromised by the worm described above. We were targeted directly, as were a number of other major vendors, to act as a "patient zero" for this attack.

The first step the attacker took was to steal the Github Personal Access Token of one of our bots, and then use that to steal the rest of the Github secrets available in our CI runners, which included this npm token. These steps were done days before the attack on the 24th of November.

At 5:40PM on November 18th, now-deleted user brwjbowkevj opened a pull request against our posthog repository, including this commit. This PR changed the code of a script executed by a workflow we were running against external contributions, modifying it to send the secrets available during that script's execution to a webhook controlled by the attacker. These secrets included the Github Personal Access Token of one of our bots, which had broad repo write permissions across our organization. The PR itself was deleted along with the fork it came from when the user was deleted, but the commit was not.

The PR was opened, the workflow run, and the PR closed within the space of 1 minute (screenshots include timestamps in UTC+2, the author's timezone):

initial PR logs

联系我们 contact @ memedata.com