security-updates
Security Updates for Drupal with Composer
Use when:
- Running a security audit on a Drupal project
- Fixing packages flagged by
composer audit - Applying a specific security advisory
- Verifying no known vulnerabilities remain
Before You Start — Create a Branch
This step is mandatory. Do not run any composer commands until a new branch is created and confirmed. Never update packages directly on
mainormaster.
Check the current branch first:
git branch --show-current
If the user is on main, master, or any protected branch, stop and ask: "What would you like to name the new branch for these security fixes?"
Suggest a default if they are unsure (e.g., security/drupal-updates-YYYY-MM-DD).
git checkout -b <branch-name>
Confirm the new branch is active before proceeding:
git branch --show-current
Only continue to the next step once the output confirms a non-protected branch.
Audit for Vulnerabilities
composer audit
Output lists packages with known advisories, CVE IDs, and links to the advisory.
JSON output (for scripting)
composer audit --format=json
Audit without dev dependencies
composer audit --no-dev
Fix a Specific Vulnerable Package
composer update drupal/package --with-all-dependencies
Use --with-all-dependencies to allow transitive dependency version changes required by the update.
Example — fix a known advisory in drupal/core
composer update drupal/core-recommended drupal/core-composer-scaffold --with-all-dependencies
Fix All Packages with Advisories
Update only packages flagged by the audit, staying within the version constraints in composer.json:
composer update --with-all-dependencies $(composer audit --format=json 2>/dev/null \
| python3 -c "import sys,json; data=json.load(sys.stdin); print(' '.join(set(a['packageName'] for a in data.get('advisories', {}).values() if isinstance(a, dict)) or [v[0]['packageName'] for v in data.get('advisories', {}).values()]))" 2>/dev/null)
Or update them manually after reviewing the audit output:
# List vulnerable packages from audit output, then update each
composer update drupal/package1 drupal/package2 --with-all-dependencies
Verify No Vulnerabilities Remain
composer audit
Expected output after all fixes:
No security vulnerability advisories found.
Confirm the updated version is installed
composer show drupal/package | grep versions
Check the installed version matches the expected fix release. For Drupal core:
composer show drupal/core | grep versions
Confirm Drupal still bootstraps
If Drush is available locally:
drush status
Expected: Drupal bootstrap: Successful. If bootstrap fails, do not commit — investigate before proceeding.
After the audit is clean, always ask the user these questions in order:
1. "Do you want to commit these changes?"
- If yes:
git add composer.json composer.lock git commit -m "Apply Drupal security updates"- If no → remind the user that
composer.jsonandcomposer.lockare uncommitted before proceeding.2. "Do you want to deploy these changes to an Acquia environment?"
- If yes → follow the Drupal Update and Deploy playbook to push code, switch the environment, and optionally trigger a pipeline build.
- If no → done.
3. After deployment: Run database updates on the target environment before marking the work complete:
drush updb --yes drush cr
Troubleshooting
"Your requirements could not be resolved"
The version required to fix the advisory conflicts with another constraint. Options:
# Check what requires the package
composer why drupal/package
# Check what prevents the update
composer why-not drupal/package 2.x
# Relax the constraint in composer.json if safe, then retry
composer update drupal/package --with-all-dependencies
Advisory persists after update
Composer's local advisory database may be stale. Refresh it:
composer audit --update-cache
composer audit
Package cannot be updated without breaking other packages
Pin the conflicting package temporarily and file a follow-up:
# Check the full dependency tree
composer depends drupal/conflicting-package
Resolve the constraint in composer.json before retrying.
Rollback a bad update
If the update introduced a regression, restore the previous state from version control and reinstall:
git checkout composer.json composer.lock
composer install
If the update was already committed, revert the commit:
git revert HEAD
composer install
Best Practices
- Run
composer auditbefore every deploy — catch new advisories early. - Use
--with-all-dependencies— security fixes often require transitive updates. - Review
composer.lockdiff — confirm only expected packages changed. - Check the advisory link — understand what the vulnerability is before updating.
More from acquia/acquia-skills
application-management
Use when listing Acquia Cloud applications, linking or unlinking a local repo to an application, opening an app in browser, checking VCS/branch deployment status, or exporting a site archive.
44getting-started
Use when acli is not installed, authentication fails, or user needs to install and authenticate acli for the first time.
42troubleshooting
Use when acli commands fail, return unexpected errors, authentication breaks, or the CLI behaves unexpectedly.
37pull-push
Use when syncing code, database, or files between local and Acquia Cloud environments, or pulling a Cloud database/files locally.
37remote-access
Use when SSHing into a Cloud environment, running Drush commands remotely, or tailing live application logs.
37environment-management
Use when listing, creating, deleting, or mirroring Cloud environments, managing CDEs, deploying code to an environment, or checking environment status.
37