composer.json 的 scripts 字段存在高危命令注入风险,源于未转义的变量插值(如 ${APP_ENV})和 shell 元字符拼接,应禁用插值、优先使用 PHP 脚本、静态扫描危险函数及元字符,并移除非必要脚本。

composer.json 中 scripts 字段是命令注入高发区
脚本注入风险不来自 composer install 本身,而来自你写的 "scripts" ——尤其是 post-install-cmd、pre-autoload-dump 这类钩子。Composer 会原样拼接字符串并交给 shell 执行,exec() 级别的危险直接暴露。
常见错误现象:本地开发正常,CI 中因环境变量含空格或特殊字符(如 $PATH、$(whoami))导致命令截断或意外执行;更隐蔽的是,有人把用户输入拼进脚本,比如:"post-install-cmd": "php ./tools/patch.php --env=${APP_ENV}",而 APP_ENV=dev; rm -rf . 就能触发命令注入。
- 所有
scripts值都应视为不可信输入,哪怕只在 CI 中运行 - 避免使用
${VAR}插值语法——它不做转义,等价于eval - 优先用 PHP 脚本替代 shell 命令:写
php patch.php,而不是./patch.sh - 若必须用 shell,用单引号包裹整个命令,禁用变量插值:
'php ./tools/patch.php --env dev'
静态扫描要盯住三个危险模式
靠人工 review composer.json 容易漏,需用工具匹配典型危险模式。重点不是“有没有脚本”,而是“脚本里有没有拼接、执行、解析外部输入”。
以下模式必须告警:
-
exec(、shell_exec(、system(出现在scripts指向的 PHP 文件中 -
$_ENV、$_SERVER、getenv(直接传给passthru或proc_open -
scripts值里含;、&&、|、`、$()、$(等 shell 元字符
示例:"post-install-cmd": "php ./build.php && chmod +x ./bin/*" 看似安全,但若 build.php 内部用了 exec($_GET['cmd']),静态扫描仍需穿透到该文件。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
composer audit 不查 scripts 注入,别指望它
composer audit 只比对 composer.lock 里的包版本和 FriendsOfPHP 的 CVE 数据库,它完全不解析 composer.json 结构,也不执行或模拟任何 scripts。报出 “no vulnerabilities found” 和你的 post-update-cmd 是否安全毫无关系。
真正能覆盖 scripts 风险的静态检查方式只有:
- 用
php -l扫描所有scripts引用的 PHP 文件,确认无危险函数调用 - 用正则匹配
composer.json:找"scripts":\s*{[^}]*?["'].*[;|&`$()].*["'] - CI 中加一步
grep -r 'exec\|shell_exec\|system\|passthru' src/ tools/ --include='*.php'
注意:roave/security-advisories 插件也只管包冲突,不管脚本逻辑。
修复建议:删掉 scripts,改用 Makefile 或专用 CLI 工具
最彻底的解法不是加固 scripts,而是移除它。Composer 的脚本机制设计初衷是轻量钩子,不是应用级任务调度器。
- 把构建、补丁、权限设置等逻辑全抽到
Makefile或独立 PHP CLI 命令里,用make build替代composer run build - 若必须保留钩子,强制要求所有
scripts值以php开头,且路径为绝对或 vendor 内固定位置(如php vendor/bin/phpstan),杜绝任意路径执行 - 禁止在
scripts中调用composer自身命令(如composer dump-autoload),这会形成递归执行链,增加攻击面
复杂点在于:很多团队把 scripts 当成文档用,写一堆注释式命令。这类“伪脚本”看似无害,但一旦被复制粘贴进真实环境,就变成可执行入口——静态扫描必须区分“声明”和“执行”。

















