91. How would you respond to a compromised Composer dependency in a PHP application?
Describe identifying affected versions, containment, lockfile and dependency analysis, secret rotation when needed, patching or replacing the package, testing, deployment, monitoring, and post-incident controls.
I would treat it as an incident, find every affected locked version and deployment, contain the package, preserve evidence, assess and rotate reachable secrets, patch or replace it, rebuild from trusted inputs, test and deploy safely, then monitor and improve dependency controls.
This question asks what you would do when outside software used by a PHP application may have been changed or controlled by an attacker. You must explain how you would find every affected copy, stop further harm, preserve useful records, decide whether passwords or keys were exposed, replace the unsafe software, test the repaired application, release it safely, and watch for continuing problems. You should also explain how the team would prevent or detect a similar event sooner. The goal is to restore trust without assuming damage that has not been proven.
Useful clarifying questions:
- Which package, versions, release references, or time window are reported as compromised?
- Is the compromise confirmed, and are an advisory, maintainer instructions, or indicators of compromise available?
- Is the package a direct dependency, a transitive dependency, a Composer plugin, or a development-only dependency?
- In which repositories, build artifacts, container images, hosts, and environments might it exist?
- Where and when could its code have executed: during Composer operations, CI builds, web requests, workers, or command-line jobs?
- Is there a verified fixed version, safe rollback version, maintained replacement, or approved temporary fork?
I would treat the report as a security incident and assign clear ownership. I would pause risky deployments and package updates while establishing facts. I would not begin with an unrestricted composer update, because it can change many packages, complicate the investigation, and introduce unrelated differences.
First, I would confirm the affected package name, versions, source or distribution references, publication time, advisory details, and available indicators of compromise. I would obtain this information from trusted sources such as the package maintainer, Composer or Packagist security information, the affected source repository, and the organization's security team. A package name or version alone may be insufficient if an existing release archive was replaced or if only a specific commit or distribution artifact was affected.
Next, I would identify the exact exposure. composer.json describes acceptable version constraints, but composer.lock records the exact package versions and references selected for a particular application build. I would inspect both the packages and packages-dev sections of each lockfile. Useful read-only commands include composer show --locked, composer depends vendor/package --tree, and composer audit --locked. I would run Composer investigation commands in an isolated environment with plugins disabled when practical, because installed Composer plugins can execute during Composer commands. I would not treat a clean audit result as proof of safety because a new compromise may not yet appear in an advisory database.
I would search source repositories, archived lockfiles, CI records, software bills of materials, deployment manifests, release artifacts, container images, server inventories, and running environments for the affected package and reference. I would include older releases that could still be running or available for rollback. I would classify each occurrence as direct, transitive, production, development-only, build-time, Composer-plugin, or runtime use.
A development-only dependency is not automatically harmless. It may have executed in CI, tests, code generation, static analysis, or developer workstations, or it may have influenced an artifact later deployed to production. A Composer plugin is especially important because plugins can execute with the permissions of the account running Composer. Ordinary dependency-defined Composer scripts are not automatically executed by the root project; Composer executes scripts defined in the root package. However, compromised dependency code can still execute through plugins, autoloaded files, application imports, framework bootstrapping, test execution, command-line tools, or direct runtime calls.
I would contain the incident according to what the dependency could reach. Actions could include disabling the affected feature, stopping deployments, removing instances from service, pausing workers, blocking suspicious outbound destinations, restricting network egress, isolating CI runners, revoking package-repository credentials, or rolling back to a release independently verified as clean. If safe operation cannot be guaranteed, the application should fail closed by disabling the affected capability or rejecting related requests rather than continuing with untrusted code.
Before replacing systems, I would preserve relevant evidence. This can include composer.json, composer.lock, installed-package metadata, package archives, hashes, build and deployment logs, CI runner information, container image identifiers, filesystem timestamps, process information, network records, and relevant application or cloud audit logs. I would preserve evidence according to the organization's incident process and access controls. Investigation logs must identify events and affected resources without copying secret values, session tokens, authorization headers, or sensitive personal data.
I would then determine how the package could execute and what it could access. I would review whether it was a Composer plugin, whether the root project invoked any package binaries or callbacks, whether its classes or autoloaded files ran during requests or jobs, and whether CI or deployment steps executed its commands. I would map the operating-system identity, filesystem permissions, environment variables, mounted secrets, database permissions, cloud identity, network access, and external services available in each execution context.
Secret rotation would be based on credible reachability, not guesswork alone. If compromised code could read a secret or use an attached identity, I would treat that credential as potentially exposed even when exfiltration is not yet proven. I would prioritize externally usable and highly privileged credentials, including CI tokens, package-repository credentials, cloud keys, signing keys, database credentials, API tokens, session-signing keys, and deployment credentials. Where supported, I would revoke or disable the old credential first, issue a replacement, update dependent services in a controlled order, and verify that the old credential no longer works. For credentials that cannot be rotated without disruption, I would use a documented staged rotation or temporary access restriction.
I would also consider active sessions and derived credentials. Rotating a session-signing key may invalidate all sessions, which can be appropriate when the key was reachable but has a user-impact tradeoff. Rotating a database password does not by itself remove database persistence that an attacker may already have created. Therefore, credential rotation must be combined with access-log review, privilege review, persistence checks, and monitoring.
For remediation, I would prefer a fixed version or recovery procedure verified by trusted maintainers and reviewed internally. If no trusted fix exists, I would remove the package, disable the feature, replace it with a maintained alternative, pin an independently verified safe version, or create a minimal internal fork containing only reviewed changes. A rollback is safe only when the selected version and its distribution artifact are outside the affected scope. Version numbers alone must not be trusted when the incident involved altered tags, commits, repository access, or replaced archives.
I would make the smallest dependency change that resolves the incident while allowing required transitive updates. For example, I could perform a targeted package update with an explicit version and appropriate dependency flags rather than updating the entire dependency graph. I would inspect the complete composer.lock diff, including added, removed, upgraded, downgraded, and transitive packages. I would also review changes to Composer plugins, autoload configuration, package binaries, repositories, and root scripts.
I would rebuild the application on a clean, isolated CI runner or build host using a trusted Composer executable, trusted repositories, the reviewed composer.json, and the approved lockfile. Composer should not run as a privileged host user. During investigation, I would use --no-plugins --no-scripts when possible and perform the build inside a sandbox with restricted credentials and network access. This prevents Composer plugins and root-package scripts from executing during that step. If the application legitimately requires a plugin or root script, I would review it explicitly and enable only the minimum trusted functionality needed for the final build.
I would not reuse a possibly contaminated vendor directory, dependency cache, build workspace, CI runner, or container layer without validation. I would install dependencies from the reviewed lockfile and confirm that the resulting installed-package metadata matches it. Where the build system supports them, I would verify trusted checksums, source references, repository provenance, artifact attestations, or signatures. These controls help establish provenance but do not prove that trusted source code itself is harmless, so code review and behavioral testing remain necessary.
Testing would include unit, integration, regression, and security-focused tests for the affected paths. I would verify application startup, autoloading, dependency injection, web requests, background workers, scheduled jobs, command-line tools, authentication, authorization, session behavior, file handling, database access, and external integrations that the package could influence. I would test on supported PHP 8.4 and PHP 8.5 environments when those versions are part of the application's deployment matrix.
I would verify the remediation directly. I would confirm that no affected version, reference, archive, or package file remains in the release artifact; inspect installed-package metadata; rerun dependency audits; scan the artifact; and compare the final dependency graph with the approved lockfile. I would also verify that revoked credentials fail, replacement credentials work only where expected, outbound restrictions are effective, and the affected feature fails safely when its dependency or external service is unavailable.
Deployment would use the normal controlled release process with peer review, staged rollout, a canary when available, health checks, and a documented rollback or forward-fix plan. The rollback target must be independently verified as clean. If the incident may involve stolen credentials or persistence outside the application artifact, deploying corrected code alone is not sufficient; the related systems, identities, and data stores must also be remediated.
After deployment, I would monitor for published indicators of compromise and behavior related to the package's actual capabilities. Examples include unusual authentication attempts, unexpected credential use, new privileged accounts, suspicious outbound connections, process creation, modified files, unexplained scheduled jobs, abnormal database access, unexpected package downloads, integrity changes, and application error or latency changes. Monitoring should be time-bounded and risk-based, with alerts connected to an incident owner rather than merely collected.
Finally, I would document the timeline, affected assets, evidence, containment decisions, credential actions, remediation, verification results, residual risk, and lessons learned. Post-incident controls could include automated lockfile auditing, dependency inventories or software bills of materials, ownership for dependency alerts, repository allowlists, restricted Composer allow-plugins configuration, reviewed root scripts, least-privilege CI and runtime identities, isolated builds, short-lived credentials, network egress controls, immutable artifacts, provenance records, protected release workflows, faster patch procedures, and exercises for dependency incidents.
The main tradeoff is speed versus certainty. High-risk containment and credential revocation may be necessary before the investigation is complete. However, broad package updates, mass secret rotation, or emergency rollbacks can also cause outages and hide evidence. I would take immediate reversible actions first, then make permanent changes based on the dependency's confirmed versions, execution paths, reachable privileges, and available evidence.
- Open a security incident, assign ownership, and pause unsafe deployments or updates.
- Confirm the affected package, versions, references, artifacts, time window, and trusted incident guidance.
- Inventory every repository, lockfile, artifact, image, build, host, and running environment containing the dependency.
- Classify each occurrence as direct, transitive, development-only, build-time, Composer-plugin, or runtime use.
- Contain the dependency according to its reachable capabilities while preserving relevant evidence.
- Analyze composer.json, composer.lock, the dependency tree, plugins, root scripts, autoloading, package binaries, runtime calls, and CI execution paths.
- Map the files, networks, data, services, identities, and secrets available to compromised code.
- Revoke and rotate credentials that were credibly reachable, prioritizing privileged and externally usable secrets.
- Patch, replace, remove, pin, or temporarily fork the package using independently reviewed and trusted inputs.
- Review the complete lockfile and dependency-graph changes.
- Rebuild from the approved lockfile in a clean, isolated environment without reusing suspect caches or workspaces.
- Run functional, regression, integration, and security verification, including direct confirmation that affected artifacts are absent.
- Deploy through a staged process with a verified clean rollback or forward-fix plan.
- Monitor relevant indicators and behavior, investigate possible persistence, and verify credential revocation.
- Document the incident and add preventive PHP and Composer supply-chain controls.
The investigation time grows mainly with the number of repositories, lockfiles, artifacts, environments, dependency paths, credentials, and historical releases that must be checked. Reading one lockfile uses little time and memory, but organization-wide inventory searches, artifact scans, clean rebuilds, and regression tests may require substantial computing and engineering effort. A dependency tree or lockfile analysis generally uses memory proportional to the number of packages and relationships being processed; no exact bound should be claimed without knowing the Composer version and project graph. Secret rotation can create operational downtime when services depend on the old credentials. Long-term controls add build time, storage, and maintenance work, but they reduce future detection and recovery costs.
Interviewers want to know whether the candidate can manage a PHP software supply-chain incident rather than treating it as a routine package upgrade. The question evaluates dependency and lockfile analysis, containment judgment, evidence preservation, secret-rotation decisions, safe remediation, clean builds, deployment verification, monitoring, and practical post-incident prevention.
Common mistakes include running an unrestricted composer update before recording the existing state; checking only composer.json instead of exact locked and deployed versions; ignoring packages-dev, transitive dependencies, historical releases, or Composer plugins; incorrectly claiming that scripts declared by ordinary dependencies are automatically executed; running investigation commands with untrusted installed plugins enabled; treating a clean composer audit result as proof of safety; trusting a version number without checking the affected reference or artifact; rolling back to an unverified release; rebuilding on a potentially contaminated runner or from a suspect cache; running Composer as root; enabling all plugins with an overly broad allow-plugins policy; rotating secrets without mapping access and service dependencies; failing to revoke old credentials; assuming rotation removes attacker persistence; logging secret values during investigation; claiming that data was stolen without evidence; testing only the application's happy path; and ending the response after patching without deployment verification, monitoring, or post-incident controls.
Present the response in incident order: confirm scope, inventory exact locked deployments, contain and preserve evidence, analyze execution and access, rotate reachable secrets, remediate, rebuild cleanly, verify, deploy safely, monitor, and prevent recurrence. Clearly distinguish confirmed compromise, possible exposure, and proven impact.






