Skip to main content
Malicious Packages on Packagist: A Detection and Response ReferenceStandards
5 min readFor Developers

Malicious Packages on Packagist: A Detection and Response Reference

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:

  1. 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.

  2. Inspect the dependency tree: Run composer show --tree package-name before installation. The nhattuanbl/lara-swagger attack succeeded because developers didn't review what lara-helper would install. Any unexpected dependency should halt the process.

  3. Review installation scripts: Check composer.json for scripts blocks that execute on post-install-cmd or post-update-cmd. Legitimate packages rarely need installation hooks. If you see one, read the code it references.

  4. 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 outdated and 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:

  1. Isolate the affected system from network access immediately.
  2. Capture memory dump and filesystem snapshot for forensics.
  3. Review application logs for C2 connection attempts to helper.leuleu[.]net:2096 or similar.
  4. Check for files written to /tmp, /var/tmp, or user home directories.
  5. Examine cron jobs and systemd timers for persistence mechanisms.
  6. Run composer show --installed and compare against your composer.lock to identify unauthorized additions.
  7. 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.

Topics:Standards

You Might Also Like