Malware on public repositories is nothing new. For a couple of years now, ReversingLabs threat researchers have been monitoring npm, PyPI and recently VSCode Marketplace, RubyGems and NuGet for potential malware whose inclusion in the development cycle could cause a supply chain attack. More often than not, malicious packages are published by new accounts and are made from scratch.
Sometimes they are very simple — ranging from simple infostealers usually used in red team operations to downloaders delivering malicious second stage payloads. Other times, malicious actors put some effort into making their packages seem trustworthy. They spend significant effort to typosquat or mimic another popular package, or try to build trust (and a community of users) by releasing non-malicious software versions before publishing a malicious one.
ReversingLabs (RL) researchers published a research blog post in June about a malicious npm package that was dormant for a couple of months before the malicious version was published. The team has also observed and documented the emergence of new, malicious packages linked to older, dormant campaigns that we have already seen and recorded. For example, in September, researchers wrote about PyPI packages connected with the VMConnect campaign that was identified almost a year earlier.
The majority of the malicious packages found on public repositories usually come from new, throwaway accounts. However, there have been some exceptions to this rule. In 2021, an official npm package, ua-parser-js, was caught serving malware in versions 0.7.29, 0.8.0 & 1.0.0. Compromised versions were using a legitimate Windows certificate management utility called certutil to download and launch a malicious executable.Then, in December 2023, another legitimate package, @ledgerhq/connect-kit, was compromised. Using an individual's session token, malicious actors gained access to the associated npm account and published three malicious versions of the connect-kit that were used to steal crypto wallet assets from victims.
Then, in October, RL and other firms observed something similar happening again: Three versions (2.0.5, 2.0.6 and 2.0.7) of a popular, legitimate package @lottiefiles/lottie-player were infected and used to spread malicious code that was designed to steal crypto wallet assets from victims.
Since then, LottieFiles maintainers worked with npm to remove malicious versions from the repository, and they have since published new, clean versions of @lottiefiles/lottie-player. The compromise has already attracted media attention, but ReversingLabs’ research team dug deeper to understand what is going on.
Unwanted pop-ups
First published five years ago, the package @lottiefiles/lottie-player is a legitimate npm package with an estimated 84,000 weekly downloads. It is used for easily embedding and playing Lottie animations and Lottie-based Telegram Sticker animations in websites.
The package itself has now over 50 versions since being released, and it is being semi sporadically updated. So new versions 2.0.5, 2.0.6 and 2.0.7 being published 8 months after the last one wasn’t something too strange. However, those versions were malicious.
The malicious changes attracted attention almost immediately after they were pushed out directly to the npm. Developers using @lottiefiles/lottie-player started noticing the package behaving differently then they were used to. Sites that installed the malicious versions of the package @lottiefiles/lottie-player, were displaying a pop-up to connect to web3 wallets. Any user that connected their wallets opened the door to attackers draining its assets.
Little did website visitors know that connecting their wallet would connect it to the attacker's architecture. Developers and users alike started raising alarms and discussing the behavior on forums and GitHub, trying to find more information about new versions in the community. It was apparent very fast that the new versions were malicious.
Figure 1: users on GitHub asking if @lottiefiles/lottie-player was hacked
LottieFiles maintainers were very fast with the response, and after investigation was concluded, Nattu Adnan, co-founder and CTO at LottieFiles, confirmed three versions were published over the course of a few hours using a compromised access token from a developer with the required privileges.
Figure 2: Incident response
Malicious versions were removed from npm, and a new, clean version that was a copy of version 2.0.4, the last-known “good” version, was published on npm. This was important for all developers that didn’t pin dependency to a specific version but were instead using @latest, as they received the patched update automatically.
Change in behaviors
So what exactly happened? What did the malicious actors do to alter versions of @lottiefiles/lottie-player? RL researcher analysis shows that malicious actors took the file lottie-player.js and replaced its code with their own. The malicious code was minified, but this wasn’t very weird or noticeable at first since the original file had minified code as well. However, even at first glance, the two sets of code looked very different.
Once our researchers were aware of the malicious nature of those three versions, we marked them as malicious — and they stand as such on RL’s Spectra Assure Community page. Additional research using the Spectra Assure CLI and taking the last known non-malicious version of lottie-player, 2.0.4, and the last malicious version, 2.0.7, and doing a differential analysis of them highlights how the malicious actors altered the @lottiefiles/lottie-player package (Figure 3).
Figure 3: Spectra Assure scan showing a differential analysis between lottie-player.js file from different versions of
@lottiefiles/lottie-player using Spectra Assure CLI
Differential analysis created with Spectra Assure CLI allows users to compare two versions of the same package and see the changes between them and their files. Changes can include the unexplained introduction of new behaviors; the omission of other behaviors; changes in package size; or behaviors that trigger threat hunting policies. Looking at the comparison between versions 2.0.4 and 2.0.7 of @lottiefiles/lottie-player, some things jump out at us. First is the big difference in size between two versions of a package — with no corresponding features to account for the extra code. That is often an indicator something has changed.
RL researchers also found that there was an omission of normal behaviors that can usually be found in the file lottie-player.js such as “Enumerates display information” or “Might enumerate information about screen” (Figure 4).
However, some behaviors that aren’t usually part of lottie-player.js files appeared, such as “Contains URLs related to Bitcoin exchange services”. These behaviors could have pointed to the new malicious functionality of @lottiefiles/lottie-player package.
Figure 4: changes in package behaviors between 2.0.4 and 2.0.7 of lottie-player.js as identified by Spectra Assure CLI
Also very important to note are the threat hunting policies that the @lottiefiles/lottie-player package tripped. These policies focus on detecting malicious and suspicious behaviors in software components to prevent tampering incidents and software supply chain attacks. The subset of these threat hunting polices that is of interest here is differential analysis policies. They detect behaviors and changes characteristic for known software supply chain attacks. Their focus is detecting issues that closely resemble previously discovered supply chain attacks based on their signatures. For example, there is differential analysis policy TH20101, which detects indicators of tampering that resemble the SolarWinds Orion software compromise. It gets triggered whenever there is a change between two versions of a package that is characteristic to the changes seen between the last-known good SolarWinds Orion software update and the compromised update.
In the case of lottie-player, RL researchers saw a number of differential analysis policies that were triggered (Figure 5). They include TH16128, which is designed to detect presence of software components that can detect common crypto tokens. Also, policy TH17107 was triggered. That policy detected the presence of files containing URLs related to Bitcoin exchange services.
Figure 5: Threat hunting policies triggered by the comparison of clean and compromised lottie-player.js file
Due to this incident with the npm package @lottiefiles/lottie-player, we are working on adding a differential analysis policy specifically targeted to this incident, so incidents of a similar type can be flagged as malicious in the future. One of the indicators that will be included in future differential analysis policy is “Contains URLs related to Bitcoin exchange services”.
Conclusion
The reported supply chain attack involving the @lottiefiles/lottie-player underscores the dangers posed by malicious packages and supply chain attacks. These threats can lurk not only in new packages published by new and unknown actors, but in established code bases. The lottie-player hack shows how malicious actors can hijack accounts of maintainers with privileged access and can publish a series of malicious versions of that package to the community of users and developers, polluting their product and causing supply chain attacks in different projects.
Smart, secure development practices can diminish the risks posed by supply chain attacks. One of those practices is pinning dependencies to a specific, known-good version or range of versions of a file instead of using @latest when specifying dependencies in production. Pinning specific versions in the production environment may deny you the immediate benefit of software updates, but it will allow developers to avoid the risks of a supply chain attack and exert more and better control over the code used in their development cycle. That allows them to vet any updates and avoid introducing breaking or unwanted changes, as well as mitigating incompatibilities.
It is also very important to remember to regularly update the dependencies as well, to avoid any vulnerabilities and risks older versions might bring (after vetting them for malicious implants of course).
The lottie-player compromise should serve as a reminder that malicious actors are crafty, trying new techniques to avoid detection and even going so far as to try and hijack and infect popular, widely used open-source packages.
In the case of the @lottiefiles/lottie-player, the supply chain compromise was detected quickly. However, that doesn’t mean that malicious actors couldn’t work in the future towards being even more secretive and better at hiding their malicious code. That’s why it’s necessary for developers to conduct security assessments that can verify the integrity and quality of public, open source libraries for safety before they are used.
This is not the only way malicious code can be added and compromise the product. Security assessments should be performed to make sure the build pipeline wasn’t compromised, and some malicious dependency added without notice.It is important to perform security assessments regularly. New versions of existing file dependencies or products can introduce new vulnerabilities, risks and other issues that can be caught with regular checks. Security assessments can also be beneficial in catching hijacked- and infected libraries before they are included in production.
With RL's Spectra Assure Community, developers and software publishers now have a powerful new tool to help them assess and manage packages on npm, PyPI and RubyGems.
Indicators of Compromise (IOCs)
Indicators of Compromise (IoCs) refer to forensic artifacts or evidence related to a security breach or unauthorized activity on a computer network or system. IOCs play a crucial role in cybersecurity investigations and cyber incident response efforts, helping analysts and cybersecurity professionals identify and detect potential security incidents.
The following IOCs were collected as part of ReversingLabs investigation of this malicious software supply chain campaign.
package_name | version | SHA1 |
@lottiefiles/lottie-player | 2.0.7 | 846f2efc0212317b5e44690234995ba7e269dee3 |
@lottiefiles/lottie-player | 2.0.6 | 5bbd2290a7de5a4736fdafe171f5b6eae6abc27e |
@lottiefiles/lottie-player | 2.0.5 | 446996c35a4188647361733b4c7175b2aeea9611 |
Keep learning
- Find the best building blocks for your next app with RL's Spectra Assure Community, where you can quickly search the latest safe packages on npm, PyPI and RubyGems.
- Get up to speed on securing AI/ML systems and software with our Special Report. Plus, see the Webinar: The MLephant in the Room.
- Learn about complex binary analysis and why it is critical to software supply chain security in our Special Report. Plus: Take a deep dive with RL's white paper.
Explore RL's Spectra suite: Spectra Assure for software supply chain security, Spectra Detect for scalable file analysis, Spectra Analyze for malware analysis and threat hunting, and Spectra Intelligence for reputation data and intelligence.