Composer 2.7 and CVE-2024-24821: Code execution and possible privilege escalation

Please immediately update Composer to version 2.7.0 or 2.2.23 (composer.phar self-update). The new releases includes fixes for a code execution and possible privilege escalation via InstalledVersions.php or installed.php vulnerability (CVE-2024-24821) reported by Ed Cradock.

The vulnerability does not impact packagist.org and Private Packagist, but may impact you, as a user of Composer.

If you only run Composer commands on projects without a vendor directory or one containing only files that you trust to execute on your machine, and if you do not execute Composer as root and don't run it with sudo, you should not be impacted by the vulnerability. See below for a more detailed explanation.

You can view the full changelog for Composer 2.7 on GitHub:  https://github.com/composer/composer/releases/tag/2.7.0 

New Features in Composer 2.7

There are two noteworthy new features in Composer 2.7:

  • We added a new --minimal-changes (-m) flag to composer update, require, and remove. The option can be combined with --with-dependencies or --with-all-dependencies to perform a partial update of only the listed packages and their dependencies while only performing version changes or additional installations/removals of their dependencies when absolutely necessary to update the listed packages to their latest installable versions, rather than updating all of them to the latest possible versions.
  • We added a new --sort-by-age (-A) option to composer outdated and composer show. The option allows sorting by and displaying the release dates of the packages with the most outdated package returned first.

Cause of the fixed vulnerability

As a part of installing dependencies, Composer generates files in the vendor/composer/ directory. This includes a file called installed.php, that contains a PHP array definition of all the installed packages and their versions, and InstalledVersions.php which provides programmatic access to this information. This API is known as the Composer Runtime API which is designed to allow project code to inspect the list of installed packages in the project at application runtime. This is useful for example for plugin systems to dynamically enumerate installed compatible plugins and to retrieve some metadata on the installed packages, like their installation path.

Because Composer plugins and scripts may also need to access this information, Composer will load and execute the same two files from the vendor directory at runtime, to make them available to plugins or custom script code. Plugins and scripts can be disabled with the options --no-plugins --no-scripts. Disabling them is recommended if you run any Composer commands on projects you do not trust to execute code on your machine.

💡
When you run composer commands on a project without disabling plugins or scripts you must be certain you can trust the contents of the vendor directory. If you cannot, you need to either run with --no-plugins --no-scripts, or delete the vendor directory so you can regenerate it. We strongly recommend against commiting vendor directories to version control systems. If you need to control the contents of your dependencies more tightly you should use a private Composer repository like Private Packagist instead.

Problem 1: Improper Disabling of Generated File Loading

One discovered problem was the improper disabling of the file loading behavior when plugins and scripts were disabled. So the two files were still loaded even when running a command like composer self-update. This is problematic in particular on systems where users were granted sudo access specifically only to run composer self-update . It means these users could get Composer to execute arbitrary code as root by writing to these two files, thus escalating their privileges. This problem was resolved now.

💡
You should generally avoid running Composer as root. If you must grant sudo access to self-update, please pay attention to only explicitly allow composer self-update without further arguments, to prevent a downgrade to older vulnerable versions by non-privileged users.

Problem 2: Loading of arbitrary code from generated file locations

To further protect from potential attacks, we now verify that the loaded files contain content that was generated by Composer, and do not contain other arbitrary code.