--no-plugins是最直接的安全闸门,因它强制跳过插件全生命周期:不扫描vendor插件、不读composer.json的plugins字段、不调用activate(),使恶意插件零机会运行。

Composer 的 plugins 机制本身就有执行任意代码的能力,不是“可能有风险”,而是“默认就具备高危权限”——只要插件被加载,它就能修改依赖解析、劫持下载、注入 autoload、甚至在 install 过程中写文件或发请求。
为什么 --no-plugins 是最直接的安全闸门
它强制跳过整个插件生命周期:不扫描 vendor/ 下的插件包、不读 composer.json 中的 plugins 字段、不调用任何 PluginInterface::activate()。恶意插件(比如被污染的 fork 包或私有仓库里的钩子)根本没机会运行。
-
--no-plugins必须紧接在子命令之后,例如composer install --no-plugins✅;composer --no-plugins install❌(等价于composer --help) - CI 脚本里若用了 wrapper(如
bin/composer或 alias),要确认参数透传到了真实二进制,否则形同虚设 - 终端没报错 ≠ 插件没运行:真正验证方式是检查
vendor/composer/autoload_plugins.php是否为空,或运行composer diagnose --verbose看末尾有没有Loading plugin类日志
禁用特定插件不能靠注释 require 行
只注释掉 "hirak/prestissimo": "^0.3" 这类 require 行,vendor/ 里的代码还在,autoload 仍会加载类,甚至触发 Cannot redeclare class。真正有效的做法只有两种:
- 在
composer.json的extra.disabled-plugins中写全包名(大小写敏感),例如:{"extra": {"disabled-plugins": ["hirak/prestissimo"]}}—— 这是 Composer ≥2.2 官方唯一支持的按名禁用方式,只影响后续install/update - 临时重命名插件目录,如把
vendor/hirak/prestissimo改成vendor/hirak/prestissimo.disabled,再跑composer dump-autoload清缓存;改回去即恢复,不碰 lock 文件
--no-plugins 不等于安全闭环
它只停第三方插件,但以下内容依然会执行,且同样可被利用:
-
scripts钩子(如post-install-cmd):必须额外加--no-scripts才能跳过 -
platform检查失败可能触发隐式重新解析,--ignore-platform-reqs是自毁操作,应改用composer config platform.php 8.1.0显式锁定 -
vendor/bin/下的可执行文件(如phpstan)不受影响——它们不是 Composer 插件,只是普通依赖
最容易被忽略的是:插件禁用后,某些深度集成行为(如 Symfony Flex 的 recipes 注入、PHP_CodeSniffer 的自动配置)会静默消失,这不是异常,是设计使然。调试时若发现 config 文件没生成、autoload 规则没更新,先确认是不是插件被禁了,而不是去查语法错误。











