[
  {
    "id": "SEC-2026-001",
    "title": "Shai-Hulud 蠕虫：npm 自传播、凭证滥用与 CI 信任边界",
    "type": "供应链事件",
    "severity": "高风险（维护者研判）",
    "verification": "已核实",
    "published": "2025-09-14",
    "updated": "2026-10-22",
    "identifiers": [],
    "tags": [
      "npm",
      "生命周期脚本",
      "凭证窃取",
      "自传播",
      "CI 缓存污染",
      "OIDC",
      "GitHub Actions"
    ],
    "summary": "安装依赖触发代码执行，窃取发布身份后再污染其他包，形成跨维护者传播闭环。不同批次分别使用 postinstall、Bun 引导及 CI 缓存污染等入口，需要按批次判断特征和处置顺序。",
    "affected": "安装恶意包版本并执行其载荷的工作站或 CI 任务。影响必须定位到包名、精确版本、获取时间与实际执行记录；不能将整个包名、全部版本或所有 npm 用户视为已感染。",
    "exploitation": "家族机制已有技术分析支持；本文不维护实时感染数量。2025 年初代、2025 年 11 月 2.0 与 2026 年 Mini 批次分别分析，不将能力与指标跨批次套用。",
    "actions": [
      "先核对包的精确版本、执行记录与批次特征，保全锁文件、安装日志、发布审计和进程证据。",
      "疑似存在删文件守护进程时，先隔离主机并通过离线分析或应急处置控制破坏进程，再协调撤销暴露身份；不要在仍受控的机器上生成新凭证。",
      "从可信环境撤销并轮换暴露的 npm、GitHub 和云身份，检查异常发布、仓库变更、runner 注册与工作流改动。",
      "清理并重建受影响 runner、依赖缓存和构建产物；恢复可信包版本后复核所有持久化入口，不能以 npm uninstall 作为清理完成标准。"
    ],
    "notes": "高风险为维护者基于凭证暴露、包发布和持久化影响的判断，不是 CVSS 评分。公开源代码与实际投放样本不能直接视为逐字相同。",
    "sources": [
      {
        "title": "Xygeni：Shai-Hulud npm 软件包蠕虫详解",
        "url": "https://xygeni.io/zh-CN/blog/shai-hulud-the-npm-packages-worm-explained/",
        "kind": "技术背景与初代链路",
        "date": "页面日期格式异常，未确认"
      },
      {
        "title": "GitHub：Our plan for a more secure npm supply chain",
        "url": "https://github.blog/security/supply-chain-security/our-plan-for-a-more-secure-npm-supply-chain/",
        "kind": "平台说明 · 初代安装入口",
        "date": "2025 年"
      },
      {
        "title": "StepSecurity：Shai-Hulud Self-Replicating Worm",
        "url": "https://www.stepsecurity.io/blog/ctrl-tinycolor-and-40-npm-packages-compromised",
        "kind": "初代样本技术分析",
        "date": "2025-09-15"
      },
      {
        "title": "Datadog Security Labs：Shai-Hulud 2.0 npm worm",
        "url": "https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/",
        "kind": "2.0 载荷、传播与持久化分析",
        "date": "2025-11-25；更新 2025-12-04"
      },
      {
        "title": "Akamai：Mini Shai-Hulud The Worm Returns and Goes Public",
        "url": "https://www.akamai.com/blog/security-research/mini-shai-hulud-worm-returns-goes-public",
        "kind": "2026 年 Mini 与公开代码分析",
        "date": "2026-05-15"
      },
      {
        "title": "安全内参：Shai-Hulud 恶意软件深度剖析",
        "url": "https://www.secrss.com/articles/90248",
        "kind": "补充阅读 · 公开代码分析",
        "date": "2026-05-13"
      }
    ],
    "technical": {
      "mechanism": "蠕虫把包注册表当作传播网络，把维护者身份当作跨包的通行证。恶意安装脚本先以安装用户的权限运行，再获取环境中的发布凭证；随后向该身份可写的包植入自身，发布新版本。下游安装形成下一轮执行。被突破的是“允许构建依赖”与“允许读取凭证、修改仓库、发布包”之间的权限边界。",
      "prerequisites": [
        "受影响版本进入直接或传递依赖，且安装生命周期脚本或其他载荷入口实际执行。仅下载 tarball、命中包名或出现锁文件记录，不能单独证明代码执行。",
        "窃取范围受进程权限限制：环境变量、用户配置、可读文件及可访问的云身份均可能暴露；不能把凭证发现等同于云资源全部失陷。",
        "继续污染其他包需要有效且被授权的发布身份；没有发布权限仍可能发生数据外传或本地持久化。GitHub 仓库操作也取决于令牌权限和组织策略。"
      ],
      "attackChain": [
        {
          "stage": "入口 / 依赖变成执行路径",
          "detail": "初代使用 postinstall 与 bundle.js；2.0 则在 preinstall 阶段加载 setup_bun.js 和 bun_environment.js。安装阶段发生执行意味着业务代码尚未运行，恶意行为就可能已经开始。"
        },
        {
          "stage": "收集 / 从代码权限跨到身份权限",
          "detail": "安装进程继承的环境变量、.npmrc 和云配置构成凭证暴露面。初代还使用 TruffleHog 扩大扫描范围；扫描工具本身合法，需根据启动者、读取范围和后续行为判断。"
        },
        {
          "stage": "传播 / 发布链闭环",
          "detail": "在 2.0 中，载荷校验 npm 身份、枚举维护者包、获取 tarball、增加安装入口与自身内容、递增补丁版本并重新发布。复制源可来自本机正在运行的载荷，因此阻断单一 C2 不能直接切断自传播。"
        },
        {
          "stage": "外传与长期访问 / 按批次判断",
          "detail": "2.0 使用公开 GitHub 仓库外传，并可注册自托管 runner 建立后续执行通道。Mini 增加开发工具配置持久化。删除 npm 依赖并不会同时清除仓库、runner 或编辑器配置中的入口。"
        }
      ],
      "conditions": [
        {
          "environment": "2025-09 初代",
          "status": "批次特征",
          "detail": "postinstall → bundle.js；凭证收集与再发布；工作流持久化。不要将后续 Bun 文件名套用于初代。"
        },
        {
          "environment": "2025-11 Shai-Hulud 2.0",
          "status": "批次特征",
          "detail": "preinstall → setup_bun.js / bun_environment.js；公开仓库外传、自托管 runner；另有特定失败条件下的删文件分支。"
        },
        {
          "environment": "2026-05 Mini Shai-Hulud",
          "status": "批次特征",
          "detail": "特定攻击链利用 CI 缓存污染进入发布任务，再滥用 OIDC 发布身份；持久化扩展到开发工具配置，存在监控令牌状态的破坏机制。"
        }
      ],
      "detection": [
        "包差异：比较受影响版本与前一可信版本的 scripts、新增脚本、体积和混淆代码。仓库源码与 npm tarball 也应交叉比较；发布产物中的恶意文件可能不在正常源码历史中。",
        "执行证据：关联 npm 安装、node 或 Bun 子进程、凭证文件读取与外联时间。合法 Bun、TruffleHog 或 bundle.js 文件名均不是充分感染证据。",
        "身份证据：查找同一身份在异常安装后发生的包发布、工作流变更和 runner 注册；记录时间、提交、发布版本和来源主机，形成证据链。",
        "批次指标：2.0 可检查 setup_bun.js、bun_environment.js 和异常 SHA1HULUD runner；Mini 可检查非预期 .claude/settings.json、.vscode/tasks.json 变化及 git-tanstack.com 外联。指标需结合批次与行为。",
        "缓存与构建：检查不可信 PR 任务能否写入发布任务会读取的缓存。依赖升级之外，还要覆盖 runner 镜像、缓存和构建产物的污染路径。"
      ],
      "fixMechanism": "防御设计：不可信依赖构建任务不应同时持有发布身份。分离 PR 验证、构建和发布信任域，限制缓存写入者，并在可信发布任务中只处理经过核验的产物。令牌最小权限和短有效期缩小传播范围；OIDC 减少静态密钥，却不能保护已经执行恶意代码的合法发布任务。",
      "pitfalls": [
        "锁文件与完整性校验保证拿到预期内容，不保证该版本无恶意逻辑。首次锁定的就是恶意版本时，重复安装仍可重复执行。",
        "禁用安装脚本能够减少这类入口，但会影响需要构建步骤的依赖，也不能覆盖业务导入时执行、缓存污染等其他路径。需测试后使用。",
        "源码审查或有效构建证明不能单独证明发布产物安全；被污染的可信发布流程也可能生成可验证的证明。",
        "删文件触发条件不同：2.0 的传播与外传失败分支，不能等同于 Mini 的令牌状态监控。存在后者时，处置顺序需要同时考虑凭证滥用与本地破坏。"
      ],
      "evidence": "家族机制和批次差异已与平台说明、独立样本分析交叉核对；未运行恶意样本。公开代码与某次真实投放载荷的完全一致性、实时包清单和组织归属仍需逐案核验。防御设计与证据关联方法是维护者分析。",
      "related": [],
      "sections": [
        {
          "title": "为什么传播单位是“发布身份”，不只是依赖关系",
          "paragraphs": [
            "一个项目安装了恶意包，不代表其其他依赖会被原地全部感染。横向扩张发生在注册表的发布权限图上：身份可写的包成为新的载荷容器，安装这些新版本的下游再提供下一组凭证。",
            "排查时分开建立两张清单：执行过恶意依赖的主机，以及这些主机上身份有权发布或修改的包与仓库。前者决定凭证暴露范围，后者决定潜在下游污染范围。"
          ]
        },
        {
          "title": "Mini：缓存如何跨越 PR 与发布任务的边界",
          "paragraphs": [
            "低信任 PR 任务写入缓存，高信任发布任务读取并执行其中内容，构成跨信任域的数据到代码转换。随后合法发布任务中的身份可被滥用，即使并没有长期 npm 令牌存放在仓库里。",
            "检查重点是缓存内容能否影响执行、谁能写入、哪些分支与事件能恢复该缓存，以及发布任务是否重新验证内容。不能仅因 workflow 文件未被修改，就排除发布链污染。"
          ]
        },
        {
          "title": "如何判断清理是否完成",
          "paragraphs": [
            "依赖侧恢复可信版本只是第一步。主机侧需要处理未知进程和启动配置；GitHub 侧需要核对 runner、工作流及仓库变更；身份侧需要撤销暴露授权；发布侧需要追踪并处置已污染版本。",
            "从干净环境重新构建和重新签发身份，再验证这些层面没有残留入口。出现历史指标只能触发调查，证据不足时保留“疑似执行”“确认执行”“确认身份滥用”等不同结论。"
          ]
        }
      ]
    }
  },
  {
    "id": "SEC-2026-002",
    "title": "PHP 内存耗尽处理导致远程代码执行（CVE-2026-109618）",
    "type": "漏洞",
    "severity": "严重（Critical）",
    "verification": "已核实",
    "published": "2026-10-21",
    "updated": "2026-10-22",
    "identifiers": [
      "CVE-2026-109618",
      "GHSA-w8hw-w9fx-j79w"
    ],
    "tags": [
      "PHP",
      "远程代码执行",
      "Web 服务",
      "已有利用报告"
    ],
    "summary": "PHP 处理内存耗尽时可能留下无效请求内存状态，后续清理过程可导致未经认证的远程代码执行。Apache mod_php 存在已验证利用场景，其他运行方式的触发条件有差异。",
    "affected": "按 PHP 分支判断：8.2 分支低于 8.2.35、8.3 分支低于 8.3.36、8.4 分支低于 8.4.27、8.5 分支低于 8.5.12。对应修复版本为 8.2.35、8.3.36、8.4.27、8.5.12；发行版回移补丁情况需另查软件包厂商公告。",
    "exploitation": "在野利用状态尚未由本库独立验证；已验证的技术利用场景见上方环境条件。",
    "actions": [
      "确认实际提供 Web 服务的 PHP 运行版本、运行方式及发行版补丁状态。",
      "备份并验证兼容性后，升级到所属分支修复版本或更新的安全版本，重启所有 PHP 工作进程。",
      "升级前针对具体攻击路径限制请求和相关功能；临时配置与 WAF 规则不能替代完整补丁。",
      "审查 Web、PHP 和反向代理日志中的异常请求、内存耗尽及进程错误，结合业务环境排查。"
    ],
    "notes": "漏洞原理与修复版本已核实，未进行独立实机复现。不同部署的可利用性需要结合运行方式、配置和应用路径判断。",
    "sources": [
      {
        "title": "PHP 官方安全通告：PHP 内存耗尽处理导致远程代码执行",
        "url": "https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w",
        "kind": "项目官方安全通告",
        "date": "2026-10-21"
      },
      {
        "title": "华为云：PHP 远程代码执行漏洞预警",
        "url": "https://www.huaweicloud.com/notice/20261022155907845.html",
        "kind": "云厂商安全公告",
        "date": "2026-10-22"
      }
    ],
    "technical": {
      "mechanism": "请求状态尚未初始化完整时，内存耗尽触发 longjmp()，跳过正常收尾；请求关闭过程再访问无效状态，可能转为代码执行。关键在于异常退出破坏了状态有效性约束。",
      "prerequisites": [
        "攻击路径能在状态不完整时触发内存耗尽，且关闭阶段继续处理该状态。",
        "不同 SAPI 的失败处理不同，不能只凭 PHP 版本推断利用方式一致。"
      ],
      "attackChain": [
        {
          "stage": "请求解析 → 内存耗尽",
          "detail": "输入处理产生的内存开销可高于请求体大小；限制请求体大小不能等同于限制解析内存。"
        },
        {
          "stage": "异常跳转 → 状态不完整",
          "detail": "OOM 中断正常控制流，尚未准备好的请求状态仍可被后续清理逻辑接触。"
        },
        {
          "stage": "关闭清理 → 不安全访问",
          "detail": "清理阶段使用无效状态，可能导致未经认证的远程代码执行。mod_php 存在已验证场景，具体可靠性受构建与运行环境影响。"
        }
      ],
      "conditions": [
        {
          "environment": "Apache mod_php",
          "status": "已验证场景",
          "detail": "请求启动失败后仍进行关闭清理；攻击可发生在应用代码运行前。"
        },
        {
          "environment": "PHP-FPM",
          "status": "有条件受影响",
          "detail": "启动失败时子进程退出，阻断该启动期路径；启动后的 OOM 路径仍可能受影响，完整 FPM 利用链尚未验证。"
        }
      ],
      "detection": [
        "防御分析：将请求时间、PHP OOM 日志、工作进程退出与异常子进程或外联关联检查。OOM 本身不是利用成功证据。",
        "防御分析：核对 Web 服务实际加载的 PHP 包及补丁状态；CLI 版本不能单独代表所有进程池。"
      ],
      "fixMechanism": "补丁改变 OOM 处理方式，避免在不安全位置跳出并让清理逻辑看到无效状态。完整修复依赖升级并替换仍在运行的旧进程。",
      "pitfalls": [
        "memory_limit=-1 只能缓解部分可预测的 OOM 触发条件，同时会改变资源耗尽风险，不能作为完整修复或无条件配置建议。",
        "不要假设增加或降低某个内存阈值即可彻底修复。"
      ],
      "evidence": "原理与修复版本已核实，未独立实机复现；环境条件中的已验证场景不代表所有部署均可利用。",
      "related": [
        "SEC-2026-003"
      ]
    }
  },
  {
    "id": "SEC-2026-003",
    "title": "PHP 过期全局状态导致远程代码执行（CVE-2026-109619）",
    "type": "漏洞",
    "severity": "严重（Critical）",
    "verification": "已核实",
    "published": "2026-10-21",
    "updated": "2026-10-22",
    "identifiers": [
      "CVE-2026-109619",
      "GHSA-6wmf-4rv5-p3rp"
    ],
    "tags": [
      "PHP",
      "远程代码执行",
      "Web 服务",
      "已有利用报告"
    ],
    "summary": "PHP 请求结束后残留的全局状态可能引用已释放内存，在同一工作进程处理后续请求时触发释放后使用并导致远程代码执行。具体可利用性依赖运行方式、配置和应用路径。",
    "affected": "按 PHP 分支判断：8.2 分支低于 8.2.35、8.3 分支低于 8.3.36、8.4 分支低于 8.4.27、8.5 分支低于 8.5.12。对应修复版本为 8.2.35、8.3.36、8.4.27、8.5.12；发行版回移补丁情况需另查软件包厂商公告。",
    "exploitation": "在野利用状态尚未由本库独立验证；已验证的技术利用场景见上方环境条件。",
    "actions": [
      "确认实际提供 Web 服务的 PHP 运行版本、运行方式及发行版补丁状态。",
      "备份并验证兼容性后，升级到所属分支修复版本或更新的安全版本，重启所有 PHP 工作进程。",
      "升级前针对具体攻击路径限制请求和相关功能；临时配置与 WAF 规则不能替代完整补丁。",
      "审查 Web、PHP 和反向代理日志中的异常请求、内存耗尽及进程错误，结合业务环境排查。"
    ],
    "notes": "漏洞原理与修复版本已核实，未进行独立实机复现。不同部署的可利用性需要结合运行方式、配置和应用路径判断。",
    "sources": [
      {
        "title": "PHP 官方安全通告：PHP 过期全局状态导致远程代码执行",
        "url": "https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp",
        "kind": "项目官方安全通告",
        "date": "2026-10-21"
      },
      {
        "title": "华为云：PHP 远程代码执行漏洞预警",
        "url": "https://www.huaweicloud.com/notice/20261022155907845.html",
        "kind": "云厂商安全公告",
        "date": "2026-10-22"
      }
    ],
    "technical": {
      "mechanism": "工作进程的全局字段保留了某次请求拥有的内存引用；请求释放后，同一进程的后续请求在初始化前使用旧引用，形成跨请求的释放后使用。它与 OOM 清理漏洞相关，但涉及不同的状态生命周期。",
      "prerequisites": [
        "前一次请求留下未重置的状态，后一次请求进入能消费该状态的路径。",
        "两次请求由同一工作进程处理；可达性依赖配置、扩展与应用行为。"
      ],
      "attackChain": [
        {
          "stage": "请求 A / 留下引用",
          "detail": "操作发布请求内存引用，随后异常中断或清理阶段再次写入，使全局状态未能正确复位。"
        },
        {
          "stage": "请求 A 结束 / 释放内存",
          "detail": "请求堆被释放，工作进程仍保留旧引用。"
        },
        {
          "stage": "请求 B / 提前消费",
          "detail": "正常初始化前的配置诊断或上传进度等路径触及旧状态，可能引发 UAF 并转为 RCE。"
        }
      ],
      "conditions": [
        {
          "environment": "Apache mod_php",
          "status": "已验证场景",
          "detail": "PHP 8.5 的特定错误回溯状态存在已验证的利用场景，依赖相应配置与后续消费路径。"
        },
        {
          "environment": "PHP-FPM",
          "status": "已验证条件路径",
          "detail": "应用执行后留下状态并触发致命错误，再由后续请求的上传进度路径消费。需要合适的应用操作，不能仅凭 FPM 部署判断可利用性。"
        }
      ],
      "detection": [
        "防御分析：审计初始化前的配置诊断、致命错误及清理阶段异常，并按工作进程关联请求。日志缺失不能证明安全。",
        "防御分析：检查上传进度、扩展和每请求配置覆盖是否被使用，而非只查看默认 php.ini。"
      ],
      "fixMechanism": "补丁完善跨请求全局状态重置。禁用特定回溯或上传进度功能仅切断部分路径，不能覆盖所有状态生产者和消费者。",
      "pitfalls": [
        "关闭 display_errors 或 log_errors 不能阻止初始化前对旧状态的访问。",
        "不能将 FPM 启动失败会退出子进程，推广为 FPM 完全不受影响。"
      ],
      "evidence": "原理与修复版本已核实，未独立实机复现；环境条件中的已验证场景不代表所有部署均可利用。",
      "related": [
        "SEC-2026-002"
      ]
    }
  }
]
