Scope
This guide focuses on detecting, preventing, and remediating malicious packages in PHP Composer dependency chains, specifically targeting threats from Packagist. It covers reconnaissance methods, dependency analysis workflows, and runtime monitoring controls applicable to Laravel and other PHP frameworks.
You'll find specific detection patterns, verification steps, and containment procedures. This is a tactical reference for teams managing PHP dependencies in production environments.
Key Concepts and Definitions
Dependency chain poisoning: Attackers publish a seemingly legitimate package that declares malicious dependencies. For example, the package nhattuanbl/lara-swagger listed nhattuanbl/lara-helper as a Composer dependency, with the latter installing a remote access trojan.
Obfuscation layers: Malicious code often uses encoding, variable indirection, and dynamic execution to bypass static analysis. You won't see exec() or shell_exec() in plaintext; instead, you'll encounter base64-encoded strings passed to eval() or create_function().
Command-and-control (C2) persistence: The RAT connects to helper.leuleu[.]net:2096 and retries every 15 seconds, even when the server is non-responsive. This retry pattern means a dormant threat can activate days or weeks after installation.
System reconnaissance payload: Before executing commands, the RAT sends operating system details, hostname, and network configuration to the C2 server. This data helps attackers tailor their exploitation to your environment.
Requirements Breakdown
Dependency Verification (ISO/IEC 27001:2022 Control 8.31)
Control 8.31 requires you to identify and document security requirements for software acquisition and use. For Composer dependencies:
- Document approved package sources and maintainer verification steps.
- Establish package age and download count thresholds (packages with fewer than 100 downloads or less than 30 days of history trigger manual review).
- Require cryptographic signature verification for critical dependencies.
Supply Chain Risk Assessment (NIST CSF v2.0 SR.GV-1)
SR.GV-1 calls for cybersecurity roles and responsibilities to include third-party stakeholders. Apply this to package maintainers:
- Identify packages maintained by single, unverified individuals.
- Track maintainer account age and contribution history.
- Flag packages where maintainer identity cannot be verified through GitHub, Packagist profile, or external reputation signals.
Secure Development (PCI DSS v4.0.1 Requirement 6.3.2)
Requirement 6.3.2 mandates that custom software is developed securely. This extends to dependency selection:
- Implement automated scanning before packages enter your
composer.json. - Block packages containing suspicious patterns: base64 encoding in install scripts, network calls during installation, filesystem writes outside the vendor directory.
- Maintain an approved package list with version pins.
Implementation Guidance
Pre-Installation Verification
Before adding any package to your project:
Check package metadata: Visit the Packagist page. Look for maintainer verification badges, package age, and dependent project count. Packages claiming to be Laravel utilities should have hundreds of dependents—if they don't, investigate why.
Inspect the dependency tree: Run
composer show --tree package-namebefore installation. Thenhattuanbl/lara-swaggerattack succeeded because developers didn't review whatlara-helperwould install. Any unexpected dependency should halt the process.Review installation scripts: Check
composer.jsonforscriptsblocks that execute onpost-install-cmdorpost-update-cmd. Legitimate packages rarely need installation hooks. If you see one, read the code it references.Scan the codebase: Clone the repository and run static analysis. Search for:
eval(),assert(),create_function()base64_decode(),gzinflate(),str_rot13()- Network functions:
fsockopen(),curl_exec(),file_get_contents()with URLs - File operations:
file_put_contents(),fwrite()to paths outside the package directory
Runtime Monitoring
Deploy these controls after installation:
Network egress filtering: Block outbound connections from your application servers to non-approved destinations. The RAT connected to port 2096—your application has no legitimate reason to initiate connections on high-numbered ports to unknown hosts.
File integrity monitoring: Track changes to files in your vendor/ directory after installation completes. The RAT wrote files post-installation; your monitoring should alert on this.
Process monitoring: Watch for PHP processes spawning shells or executing system commands. Tools like auditd (Linux) or sysmon (Windows) can log these events.
Dependency Auditing
Establish a monthly audit cycle:
- Run
composer outdatedand review why packages haven't been updated. - Check for new maintainers on existing packages (compromised accounts are common).
- Scan for packages no longer maintained—if the last commit was over 18 months ago, evaluate alternatives.
- Review your dependency count—every package is attack surface.
Common Pitfalls
Trusting package names: Attackers use names like lara-swagger that sound official. Laravel's actual packages are published under the laravel/ namespace. If it's not namespaced to the framework vendor, verify it independently.
Ignoring transitive dependencies: You reviewed package-a but didn't check what package-a depends on. The malicious code was in lara-helper, not lara-swagger. Always inspect the full tree.
Running Composer as root: Installation scripts execute with the same privileges as the Composer process. Run Composer as a non-privileged user, never as root or with sudo.
Skipping lock file review: When a teammate adds a dependency, review the composer.lock diff. You should see exactly which packages and versions were added. Unexpected entries indicate dependency chain issues.
Disabling TLS verification: Never set "secure-http": false in composer.json. This allows man-in-the-middle attacks during package download.
Quick Reference Table
| Detection Point | Command/Check | Red Flag Indicator |
|---|---|---|
| Package age | Check Packagist page | Published <30 days ago |
| Download count | Check Packagist page | <100 total downloads |
| Dependency tree | composer show --tree pkg-name |
Unexpected transitive dependencies |
| Installation hooks | Search composer.json for scripts |
post-install-cmd present |
| Obfuscation | grep -r "base64_decode" vendor/pkg-name |
Multiple encoding functions |
| Network calls | grep -r "fsockopen|curl" vendor/pkg-name |
Connections during class loading |
| File writes | grep -r "file_put_contents" vendor/pkg-name |
Writes outside package directory |
| Maintainer identity | Check GitHub profile linked from Packagist | No verified email, new account |
| C2 communication | Monitor egress on ports >1024 | Connections to unknown hosts |
| Process behavior | ps aux | grep php during install |
Child processes spawned |
Emergency Response Checklist
If you've installed a suspected malicious package:
- Isolate the affected system from network access immediately.
- Capture memory dump and filesystem snapshot for forensics.
- Review application logs for C2 connection attempts to
helper.leuleu[.]net:2096or similar. - Check for files written to
/tmp,/var/tmp, or user home directories. - Examine cron jobs and systemd timers for persistence mechanisms.
- Run
composer show --installedand compare against yourcomposer.lockto identify unauthorized additions. - Rebuild the environment from a known-good state—don't attempt to "clean" an infected system.
Your dependency management process should prevent these scenarios. When it doesn't, speed matters more than perfection.



