Malicious package: npm/fmt-date-lite (date-utility download-execute dropper)#1345
Malicious package: npm/fmt-date-lite (date-utility download-execute dropper)#1345akyroslabs wants to merge 2 commits into
Conversation
…ropper) Signed-off-by: Sascha Klein <akyroslabs@gmail.com>
| "155.190.124.243" | ||
| ], | ||
| "hashes": [ | ||
| "sha256:987872707c668af0739f7d0193c1db906eb87e0749a5801a8a166a0aa2735136" |
There was a problem hiding this comment.
The spec currently doesn't include hashes.
I am interested in ideas about how to add support for this.
For example, what does this hash apply to? Is it the archive, an artifact in the archive, or a file dropped by the malicious package?
There was a problem hiding this comment.
Good question — happy to clarify, and glad you're thinking about formalizing this.
In these entries the hash is the SHA-256 of the published npm package tarball — the .tgz artifact exactly as served by the registry (the same bytes npm pack produces / the registry dist points at). So it applies to the archive, not to a file inside it and not to the dropped second-stage payload. It can be verified against the registry tarball directly.
On adding first-class support, the three cases you list are genuinely distinct, and I think it's worth letting an entry carry more than one, discriminated by subject. Using this package as a concrete example (real hashes):
"hashes": [
{ "alg": "sha256", "value": "987872707c668af0739f7d0193c1db906eb87e0749a5801a8a166a0aa2735136",
"target": "archive" },
{ "alg": "sha256", "value": "3268a973540ef67255c402867f3b189b6a5ac912952d49cd408a09fe622f518d",
"target": "file", "path": "postinstall.js" },
{ "alg": "sha256", "value": "<unavailable>", "target": "dropped-payload",
"note": "second-stage fetched at install time from 155.190.124.243:6788; C2 already offline, not retrievable" }
]From working these supply-chain droppers, the practical trade-offs between the three:
- archive — the most reliable/verifiable IOC: it pins the exact malicious release, and once the package is unpublished the hash still lets anyone confirm a cached/mirrored copy is the bad one. Downside: any repack (even a version bump with identical behaviour) changes it.
- file-in-archive — useful when only one file in an otherwise-plausible package is malicious (here
postinstall.js;index.jsis a benign date-format facade), and it survives repackaging of unrelated files — good for clustering a campaign that reuses the same install shell across sibling packages. - dropped-payload — the highest-value IOC for correlating across ecosystems, but frequently unavailable: these droppers live ~40–60h before takedown and the C2 is often already gone by the time we catch them, so the second stage can't be retrieved and hashed. Worth supporting, but it can't be required.
Happy to send a small PR proposing the target field in docs/schema_additions.md, or to expand the current entries with the per-file hashes as a worked example — whichever is more useful.
Adds an OSV record for the npm package
fmt-date-lite, a download-and-execute supply-chain dropper disguised as a date-formatting utility ("Lightweight date formatting utility with locale support").A
postinstallhook runsnode postinstall.json install, which fetches a payload from the hardcoded endpoint 155.190.124.243:6788 and executes it via a Node child process — arbitrary code execution on any machine or CI runner that installs the package (version 1.0.0).Part of a coordinated campaign of near-identical date-utility droppers: siblings datefmt-helper (C2 115.190.124.243) and date-fns-lite (C2 115.190.124.243, OSV MAL-2026-6722).
Detected by codelake Research from the live npm feed; not present in OSV or GHSA at the time of reporting.
IOCs:
Full write-up: https://research.codelake.dev/advisories/clr-2026-2991-fmt-date-lite