The need

On 20th June this year, the Drupal Security Team issued a public service announcement, logically named PSA-2022-06-20, entitled “Updated security policy for Drupal core Composer dependencies”.

In a nutshell, it discusses what happens when a library that Drupal core is dependent on issues a new release because of a security vulnerability.

Previously, the Drupal maintainers would issue a new release of Drupal core, so that site maintainers update their installation and benefit from the secured version of the upstream library. Going forwards, this will no longer happen, unless Drupal core is known to be exploitable as a result. Site maintainers are now responsible for monitoring upstream libraries, and keeping them up to date.

That’s reasonable enough in theory. In practice, there are a great many of them. A quick check on one site I manage showed that drupal/core requires a further 44 packages. They will announce new releases in different places. A workable strategy is needed to keep track of such things.

A Reminder giving us an example

The release notes for Drupal 9.4.4 reminded site maintainers of the importance of keeping track of such things. It was a bug-fix release, not a security release, but would fix a vulnerability in a dependent package (laminas/laminas-diactoros)

Drupal core uses the third-party Diactoros library as its PSR-7 implementation. Diactoros has issued a security advisory:

Drupal core is unlikely to be vulnerable. This bugfix release updates the version of Diactoros used in drupal/core-recommended to a secure version as a precaution. As a reminder, Drupal 9.4 and higher sites should update their third-party Composer dependencies when an upstream security advisory is issued.

That reminded me that I did not have an adequate way to monitor fixed vulnerabilities in dependent packages. In an ideal world, I would already have known of the Diactoros vulnerability and installed a version that fixes it.

Solutions that won’t work

So how do we keep track?

One possibility would be to run composer outdated. The problem there is that a site can be up to date on all the packages you directly installed, but still have many outdated dependencies. I’ve just checked (composer outdated) on one site, and there were 48 outdated packages. None of them were security issues. So this approach wouldn’t work because I’d be prompted about every minor dependent update, and those do not require urgent attention.

Running composer outdated --direct also doesn’t work. It only lists top-level packages that are out of date. It would tell me if drupal/core-recommended needed updating, but not about a package dependent on it. This is the problem I’m trying to solve: Drupal core will no longer be updated just because of a vulnerability in a dependency.

Running composer outdated --major-only doesn’t work. That shows outdated packages that are a major update in terms of their semver numbering, not in terms of their importance at a security level

Introducing the audit command

Composer 2.4 introduced a new command: composer audit.

Here’s what their documentation says about it:

This command is used to audit the packages you have installed for possible security issues. It checks for and lists security vulnerability advisories according to the Packagist.org api.

Sounds perfect, let’s give it a try.

On a site that had an outdated version of Diactoros (2.11.0), here was the result

$ composer audit --format=plain
Found 1 security vulnerability advisory affecting 1 package:
Package: laminas/laminas-diactoros
CVE: CVE-2022-31109
Title: Diactoros before 2.11.1 vulnerable to HTTP Host Header Attack.
URL: https://github.com/advisories/GHSA-8274-h5jp-97vr
Affected versions: <2.11.1

Now update the site to the latest version of Drupal core (9.4.5, at time of writing), and run it again:

$ composer audit --format=plain
No security vulnerability advisories found

Exactly what we wanted

Composer 2.4

I said that the audit command was new as of Composer 2.4. At time of writing, the stable version of Composer is 2.3, and 2.4 is in release candidate status. You’ll either need to wait for 2.4 to be released to use this command, or run composer self-update --preview to pick it up early.

If you’re running a global installation of Composer, and do not wish (or do not have root access) to update the whole server to 2.4, you can install a local copy and run that.

Running from cron

The last piece in the puzzle is that I want to run this command from cron.

I assume readers know how to use cron, but there are two things to watch.

Firstly, Composer needs to run from the CLI version of PHP, which may not be the one cron serves up. So you may need to specify which PHP the command is to use. Your server may vary, but something like:

/usr/local/bin/php ~/bin/composer audit

Second, you’d want the command to have no output unless an issue is found. For some reason, “No security vulnerability advisories found”, is written to StdErr not StdOut. So it’s not enough to remove that line from the output; we also need to redirect StdErr to StdOut first. Without repeating the paths to PHP and composer from the above snippet:

composer audit 2>&1 | grep -v "No security vulnerability"

Over to you

Thanks for reading, and I hope this helps. If you’ve found other ways to keep track of all relevant security advisories, I’d love to hear in the comments.


Source link