Packagist GitHub Postinstall Hook Malware Campaign
A campaign inserted malicious package.json postinstall hooks into Packagist-linked GitHub repositories, causing npm install workflows to download and execute a GitHub Releases binary as /tmp/.sshd.
- Date:
- Severity:
- high
- Sources:
- 1
Executive Summary
Socket reported a supply-chain campaign in which GitHub repositories behind Packagist packages contained a malicious package.json postinstall hook. Eight Packagist packages were confirmed, while broader GitHub search results showed hundreds of references to the same attacker-controlled payload pattern Socket.
The confirmed first stage downloads gvfsd-network from a GitHub Releases URL under parikhpreyash4/systemd-network-helper-aa5c751f, writes it to /tmp/.sshd, marks it executable, and launches it in the background. The second-stage binary was unavailable when Socket followed up, so defenders should treat execution as unknown malware with potential credential and persistence impact Socket.
Key Facts
threat_type: "malicious postinstall hook in Packagist-linked GitHub repositories"
ecosystem: "Composer/Packagist with npm lifecycle execution"
registry: "Packagist and GitHub"
affected_packages:
- "moritz-sauer-13/silverstripe-cms-theme"
- "crosiersource/crosierlib-base"
- "devdojo/wave"
- "devdojo/genesis"
- "katanaui/katana"
- "elitedevsquad/sidecar-laravel"
- "r2luna/brain"
- "baskarcm/tzi-chat-ui"
malicious_versions:
- "dev-main"
- "dev-master"
- "3.x-dev"
known_good_versions: []
fixed_or_safe_versions:
- "unknown; verify upstream repository cleanup before reinstalling branch-tracking versions"
execution_trigger: "npm install executing package.json scripts.postinstall"
primary_impact: "arbitrary binary download and execution on developer or CI systems"
campaign_context: "A PHP/Composer ecosystem compromise that uses Node/npm lifecycle scripts as the execution path."
confidence: "medium"
canonical_source: "https://socket.dev/blog/malicious-postinstall-hook-found-across-700-github-repos"
last_verified: "2026-05-24"
Source Confidence & Evidence Mapping
- confirmed: Socket lists eight Packagist packages containing the malicious
postinstallhook Socket. - confirmed: The hook downloads from
parikhpreyash4/systemd-network-helper-aa5c751fGitHub Releases, writes/tmp/.sshd, sets executable permissions, and runs it in the background Socket. - confirmed: The second-stage binary was not available during Socket’s follow-up analysis, limiting behavioral certainty Socket.
- likely: Additional GitHub repositories beyond the eight confirmed Packagist packages may have been seeded with the same hook, but each hit should be validated before being counted as a distinct compromise.
- unclear: The final payload behavior, victim count, and cleanup status of every branch-tracking package remain open.
Attack Execution Flow
sequenceDiagram
autonumber
actor Attacker
participant Repo as GitHub Repository
participant Packagist as Packagist
participant Build as Developer or CI Build
participant Release as GitHub Releases
Attacker->>Repo: Add package.json postinstall script
Repo->>Packagist: Branch-tracking version reflects poisoned source
Packagist->>Build: Dependency source is installed or built
Build->>Build: npm install runs postinstall
Build->>Release: Download gvfsd-network
Build->>Build: Write and execute /tmp/.sshd
Timeline
- 2026-05-22 Socket publishes the Packagist/GitHub postinstall campaign report Socket.
- 2026-05-24 This local feed split creates a standalone article for the campaign rather than grouping it into a weekly roundup.
What Happened
The campaign abused a cross-ecosystem blind spot: PHP projects can contain JavaScript build assets and package.json files, and many developer or CI environments run npm install as part of frontend asset preparation. The affected packages were Packagist entries, but execution happened through npm lifecycle behavior inside the repository source tree.
Socket confirmed eight Packagist packages with the malicious hook and described a broader set of GitHub references matching the same pattern. The distinction matters: defenders should immediately handle the eight confirmed package names, then use the IoCs below to hunt for other repositories or forks that contain the same postinstall payload.
Technical Analysis
Initial Access
The public report does not prove a single initial access path. The observed state is source repositories containing a malicious package.json script and Packagist branch-tracking package versions reflecting those repository states Socket.
Package or Artifact Tampering
The tampering is a scripts.postinstall entry in package.json. The hook uses curl to fetch a file named gvfsd-network from GitHub Releases, writes it as /tmp/.sshd, sets execute permissions, and starts it in the background Socket.
Execution Trigger
The trigger is npm install. Composer alone may not execute the hook, but projects that install frontend dependencies or run build scripts can execute it during development, CI, packaging, or deployment.
Payload Behavior
Only the first stage is confirmed from public reporting. The second-stage binary was unavailable when Socket attempted retrieval, so defenders should not assume a narrow payload. Treat execution as arbitrary native-code compromise until endpoint and network telemetry prove otherwise.
Exfiltration / C2
The confirmed network dependency is the GitHub Releases URL hosting gvfsd-network. Any later C2 behavior is unknown from the reviewed public source.
Propagation
No autonomous propagation is confirmed. The practical spread mechanism is repository reuse: branch-tracking Packagist versions and forks can continue to reflect malicious source if maintainers do not clean the underlying repository state.
Obfuscation or Evasion
The campaign hides in ecosystem mismatch. A PHP dependency carrying a JavaScript lifecycle hook may be missed by Composer-focused scanners, and /tmp/.sshd resembles a system service name while living in a temporary path.
MITRE ATT&CK Mapping
| Tactic | Technique ID | Technique Name | Observed Behavior |
|---|---|---|---|
| Initial Access | T1195.002 | Compromise Software Supply Chain | Packagist-linked source repositories contained malicious install hooks. |
| Execution | T1059.004 | Unix Shell | postinstall used shell commands to download and execute a binary. |
| Command and Control | T1105 | Ingress Tool Transfer | Hook downloaded gvfsd-network from GitHub Releases. |
| Defense Evasion | T1036 | Masquerading | Payload was written as /tmp/.sshd. |
Affected Assets and Blast Radius
affected_assets:
ecosystems:
- "Packagist"
- "Composer"
- "npm"
packages:
- "moritz-sauer-13/silverstripe-cms-theme"
- "crosiersource/crosierlib-base"
- "devdojo/wave"
- "devdojo/genesis"
- "katanaui/katana"
- "elitedevsquad/sidecar-laravel"
- "r2luna/brain"
- "baskarcm/tzi-chat-ui"
versions:
- "dev-main"
- "dev-master"
- "3.x-dev"
repositories:
- "parikhpreyash4/systemd-network-helper-aa5c751f"
ci_cd_systems:
- "GitHub Actions"
- "Composer/npm build pipelines"
container_images: []
developer_tools:
- "Composer"
- "npm"
credentials_at_risk:
- "unknown; treat all secrets reachable from affected developer or CI hosts as exposed if /tmp/.sshd executed"
not_currently_known_to_affect:
- "Projects that used the affected Composer packages but never executed npm install or equivalent lifecycle scripts."
Indicators of Compromise
package_versions:
- "moritz-sauer-13/silverstripe-cms-theme dev-master"
- "crosiersource/crosierlib-base dev-master"
- "devdojo/wave dev-main"
- "devdojo/genesis dev-main"
- "katanaui/katana dev-main"
- "elitedevsquad/sidecar-laravel 3.x-dev"
- "r2luna/brain dev-main"
- "baskarcm/tzi-chat-ui dev-main"
files:
- "package.json"
- "/tmp/.sshd"
hashes: []
domains:
- "github[.]com"
urls:
- "hxxps://github[.]com/parikhpreyash4/systemd-network-helper-aa5c751f/releases/latest/download/gvfsd-network"
ips: []
process_patterns:
- "curl -skL ... -o /tmp/.sshd"
- "chmod +x /tmp/.sshd"
- "/tmp/.sshd running in background"
network_patterns:
- "download of gvfsd-network from parikhpreyash4/systemd-network-helper-aa5c751f"
provenance_signals:
- "PHP/Composer package unexpectedly containing npm postinstall lifecycle script"
Detection and Hunting
lockfiles:
- "Search composer.lock for the eight confirmed Packagist packages."
- "Flag branch-tracking versions dev-main, dev-master, and 3.x-dev for manual review."
filesystem:
- "Search source trees for parikhpreyash4, gvfsd-network, /tmp/.sshd, curl -skL, and scripts.postinstall."
process:
- "Alert on npm lifecycle scripts writing executables under /tmp."
- "Alert on /tmp/.sshd process execution."
network:
- "Search proxy logs for the GitHub Releases gvfsd-network URL."
github_audit:
- "Review source commits that introduced package.json postinstall hooks in PHP projects."
ci_cd:
- "Review npm install runs for affected projects after the malicious commit entered the branch."
registry:
- "Block or pin affected branch-tracking Packagist package versions until source cleanup is verified."
sigma_candidates:
- "NPM Postinstall Downloads GitHub Release Binary To /tmp/.sshd"
yara_candidates:
- "Unavailable until gvfsd-network sample is recovered."
Remediation Workflow
- Immediate: Stop builds for affected projects, preserve CI logs and dependency caches, block the GitHub Releases payload URL, and isolate systems where
/tmp/.sshdexecuted. - Short-term: Remove the malicious
postinstall, pin Composer dependencies to clean commits, purge Composer/npm caches, and rotate secrets reachable by affected developer and CI hosts. - Long-term: Treat package lifecycle scripts in non-JavaScript projects as high-risk, require review for new
package.jsonscripts, and prevent production builds from consuming branch-tracking dependency references without approval.
Defensive Lessons
- prevent: Branch-tracking dependency versions and cross-ecosystem build hooks need the same review as normal package updates.
- detect: Search source trees for lifecycle scripts, not only package registries for known malicious versions.
- respond: Unknown second-stage binaries require broad credential rotation and endpoint triage, even when the first-stage script looks simple.
Open Questions
- What did
gvfsd-networkdo after execution? - Which GitHub references beyond Socket’s eight confirmed Packagist packages were true compromises?
- Which affected package branches have been cleaned and protected?
Sources
- Socket: Malicious Postinstall Hook Found Across 700+ GitHub Repositories - Role: PRIMARY_RESEARCH - Impact: Documents confirmed packages, postinstall code behavior, payload URL, and cleanup caveats.
Machine-Readable Event Profile
{
"schema_version": "2.0",
"event_id": "packagist-github-postinstall-hook-campaign-2026-05-22",
"event_name": "Packagist GitHub Postinstall Hook Malware Campaign",
"publication_state": "publish_ready",
"confidence": "medium",
"attack_types": ["malicious postinstall", "source repository compromise", "arbitrary binary execution"],
"sources": {
"direct": [],
"primary_research": ["https://socket.dev/blog/malicious-postinstall-hook-found-across-700-github-repos"],
"correlated": []
},
"affected_assets": {
"ecosystems": ["Packagist", "Composer", "npm"],
"packages": ["moritz-sauer-13/silverstripe-cms-theme", "crosiersource/crosierlib-base", "devdojo/wave", "devdojo/genesis", "katanaui/katana", "elitedevsquad/sidecar-laravel", "r2luna/brain", "baskarcm/tzi-chat-ui"],
"versions": ["dev-main", "dev-master", "3.x-dev"],
"repositories": ["parikhpreyash4/systemd-network-helper-aa5c751f"],
"ci_cd_systems": ["GitHub Actions", "Composer/npm build pipelines"],
"container_images": [],
"developer_tools": ["Composer", "npm"],
"credentials_at_risk": ["unknown; all secrets reachable from hosts executing /tmp/.sshd"]
},
"timeline": {
"first_seen": "unknown",
"malicious_publish_time": "unknown",
"discovery_time": "2026-05-22",
"removal_time": "mixed",
"disclosure_time": "2026-05-22",
"patch_or_fix_time": "unknown"
},
"artifact_analysis": {
"malicious_artifacts": ["package.json scripts.postinstall", "/tmp/.sshd", "gvfsd-network"],
"execution_trigger": "npm install postinstall",
"payload_behavior": ["download GitHub Releases binary", "chmod executable", "background execution"]
},
"iocs": {
"package_versions": ["Packagist dev-main/dev-master/3.x-dev package states"],
"files": ["package.json", "/tmp/.sshd"],
"hashes": [],
"domains": ["github.com"],
"urls": ["https://github.com/parikhpreyash4/systemd-network-helper-aa5c751f/releases/latest/download/gvfsd-network"],
"ips": [],
"process_patterns": ["curl -skL to /tmp/.sshd", "chmod +x /tmp/.sshd"],
"network_patterns": ["download gvfsd-network from GitHub Releases"]
},
"detection": {
"lockfile_hunts": ["composer.lock confirmed Packagist packages"],
"filesystem_hunts": ["parikhpreyash4", "gvfsd-network", "/tmp/.sshd", "scripts.postinstall"],
"process_hunts": ["/tmp/.sshd execution"],
"network_hunts": ["GitHub Releases gvfsd-network URL"],
"ci_cd_hunts": ["npm install in affected PHP projects"],
"registry_hunts": ["branch-tracking Packagist versions"]
},
"open_questions": ["second-stage behavior", "full affected repository count", "cleanup status"],
"defender_takeaways": {
"detection": "Hunt for lifecycle scripts and /tmp executable drops in Composer projects.",
"hunting": "Start with the eight confirmed packages, then expand to source-code pattern matches.",
"remediation": "Remove hooks, pin clean commits, purge caches, and rotate secrets after execution.",
"prevention": "Review package.json scripts in non-JavaScript dependencies and avoid branch-tracking production dependencies."
}
}