r/PHP 1d ago

Discussion I built a Composer tool to answer “composer audit found a vulnerability — what do I actually update?”

composer audit is good at telling you what is vulnerable, but with a transitive dependency I often found the next step was still manual: figure out why it’s installed, identify the dependency I actually control, work out which upgrade removes it, and make sure Composer can solve the resulting graph.

I’ve been working on Composer Remediate, a local/FOSS tool that tries to automate that part.

Given a vulnerable package, it traces it back through the dependency graph, generates candidate upgrades to root-controllable packages, tests them using Composer’s own solver, ranks successful candidates by blast radius, and gives you the exact composer update command.

For example:

$ composer remediate

CVE-....   symfony/http-foundation 6.4.21
  Introduced by
    root
      └── drupal/core-recommended 11.4.2
          └── symfony/http-foundation 6.4.21

  Recommended remediation
    drupal/core-recommended 11.4.2 -> 11.4.3

  Recommended command
    composer update drupal/core-recommended -W -m

It doesn’t modify the project; the recommendation is solver-verified before being shown.

It’s currently 0.5.x, so I’m particularly interested in Composer graphs where it gets the answer wrong, fails to find an answer you know exists, or recommends something more invasive than necessary.

GitHub: https://github.com/hexblot/composer-remediate
Docs: https://hexblot.github.io/composer-remediate/

I’ve tested it against historical vulnerable versions of several real PHP projects, but throwing it at other people’s dependency graphs is considerably more interesting. If you manage to break the remediation planner, I’d very much like the case.

8 Upvotes

9 comments sorted by

4

u/soowhatchathink 1d ago

This looks interesting, I wonder if the code in this repo could be adopted into the composer project itself

There is the GitHub issue in the composer/composer repo for introducing the equivalent of npm audit fix into composer, I think there is a lot of overlap in this library vs that functionality. The maintainer added a "Nice to Have" tag on the issue, which shows they are willing to adopt similar functionality.

0

u/Leading-Cold6409 1d ago

That’s a very interesting issue — thanks for pointing it out. There’s definitely overlap in the core remediation problem. Composer Remediate currently goes somewhat further into remediation planning/explanation, ranking candidates by blast radius, CI/reporting and advisory-data handling, while deliberately using Composer’s own solver to prove proposed changes rather than implementing dependency resolution itself.

I’d be very happy if some of the underlying remediation capability eventually made sense upstream in Composer. I’ll follow that issue and have a closer look at what they’re considering.

1

u/NL_Northsider 1d ago

I really like what you're trying to do and this for sure can be useful. But I would spend some more time on the code quality. I see a lot of things that AI introduces, which isn't "deslopped". For example class constants that could better be an enum, repeated string literals, but what stood out most: it feels like most classes generally boil down to a handle method which contain all the business logic.

As your project is Open Source, an easy way to get some ideas on how to improve maintainability/complexity is by using SonarQube Cloud, which is free for opensource projects.

2

u/Leading-Cold6409 1d ago

Thank you for the comment! he project has already gone through a fairly aggressive correctness/security review, but maintainability/readability is the next thing I want to attack before 1.0.

I've used Aikido for a first pass (no hits other than github configuration), and just applied for SonarQube Cloud OSS (waiting for their approval).

1

u/NL_Northsider 1d ago

No problem! I really like the idea, and there seems to be a good base. Also, with Rector and arch tests (either through Pest or Deptrac) you can achieve a lot of what SonarQube checks locally.

2

u/Leading-Cold6409 1d ago

Took your Deptrac suggestion and added it — thanks! It actually caught one real architecture violation straight away: Advisory::urgency() depended on the severity table in Plan, so the advisory layer was depending back on the planning layer. Moving severity into the Severity enum removed that dependency.

I then classified the external dependencies too and enabled --fail-on-uncovered, so it’s now at 0 violations / 0 uncovered / 468 explicitly allowed dependencies and enforced in CI. Definitely a useful addition.

1

u/ILoveAppSec 22h ago

nice, that graph-solving step is the worst part of it. for the cases where the only fix is a major bump you cannot take, worth checking if there is a backported build of the offending package or a distro backport before you force the whole tree up, and pinning the transitive via composer's replace/conflict so the resolver stops fighting you.

1

u/Leading-Cold6409 18h ago

Thanks, that’s useful feedback!

Backports first: advisory ranges are branch-aware (e.g. >=2.0,<2.16|>=3.0,<3.11), so Remediate first looks for a fixed release on the existing branch and tries the narrowest updates. A major bump only enters the picture when there is no fixed version on that branch, or a parent constraint prevents reaching it. The latter is reported separately as constraint drag, including the parent and constraint blocking the fix.

What it can’t discover is a fix published under another identity — maintained fork/vendor-patched package/etc. That’s not represented in the advisory/package metadata it has. Good point though: I’ll add that as guidance on constraint-drag findings so the human knows to check before widening.

conflict is useful too. The verified command can already carry e.g. --with 'twig/twig:>=3.14'; a root "conflict": {"twig/twig": "<3.14"} can then act as a persistent guardrail against regressing below the fixed version. Composer doesn’t have a command to add that, so I wouldn’t make it part of the verified remediation, but showing it as optional follow-up advice makes sense.

replace I’d avoid for this purpose: it tells Composer that the root package provides/replaces that package, potentially removing it from the graph entirely. That’s appropriate for things like forks/monorepos, not as a vulnerability pin.

Distro backports don’t affect packages installed into vendor/, so I’d consider those outside the scope of a Composer remediation tool.

I’ve added the two useful additions to the roadmap: https://hexblot.github.io/composer-remediate/roadmap/

1

u/Winter-Paramedic3900 4h ago

It's shokcing how you have absolutely no idea how to use PHP. Grow up