On November 26 a crypto payment company: BitPay has published a security advisory about compromised private keys for an undisclosed number of users of their wallet application: Copay. Private keys are used to access and spend crypto currency that the wallet stores.
The culprit of this incident is a malicious code that was specifically crafted and carefully introduced into a Copay app that stole and transferred private keys from the mobile app to a 3rd party servers with following IP addresses
Ayrton Sparling, a computer science student was looking for a reason for strange depreciation warning reported on github. He tried to locate the code that’s causing the warning, but it was both obfuscated and had encrypted parts in it that he wasn’t able to read. He warned the community of an open-source library event-stream by creating an issue and mentioning the possibility of injected code. It took event-stream contributors several days to uncover the malicious code that was both obfuscated and encrypted. When the code was discovered, it was confirmed that it only targets the mobile wallet BTC application: Copay. The incident was reported to Copay’s maintainer: BitPay and they produced a patch. flatmap-stream is an open-source library that was used as one of the dependencies for Copay mobile app through event-stream dependency. BitPay simply had to remove the dependency to the infected version of the event-stream and flatmap-stream libraries to fix the issue.
The code was injected by a series of multiple events:
September 5: flatmap-stream library package v0.1.1 was published
September 6: event-stream v3.3.6 was updated to use flatmap-stream v0.1.1 as a dependency
Later in September: a new version of Copay app was released v5.0.2 relying on both packages
event-stream library is used by millions of developers every day, it was somewhat of a shock for the open-source community to see how such a popular library can be easily infected.
Malicious Code Execution Process
The overall process looks like this:
Step 1: Malicious code is loaded as a dependency of copay application
Step 2: Code creates a new Function A from the encrypted string and uses run-time environment variable of the targeted application as passphrase to decrypt it
Step 3: Function A checks if the it’s being executed as part of the build command like “npm run build:ios-release
Step 4: Function A adds Function B to a different dependency of copay application: @zxing/library
Step 5: Function B executes when mobile application is first loaded on users’ phone
Step 5: Function B steals private keys from users’ phone and sends them to a 3rd party server
Why this happened
The creator of event-stream library handed over the development and maintenance of the project several months ago to an unknown contributor called right9ctrl, who made some valuable contributions to the open-source library code before.
After gaining access to the project, the rightful maintainer “right9ctrl” released event-stream v3.3.6, containing a new dependency on flatmap-stream v0.1.1 that contained the malicious code. right9ctrl later removed the malicious dependency from event-stream code base in an attempt to conceal the fact that the change was made. flatmap-stream was maintained by another unknown developer who could be the same person as right9ctrl.
The code was crafted in such a way to conceal its existence from other applications that depended on flatmap-stream and event-stream by using encryption with decryption passphrase as a direct attribute of a targeted package: Copay. The code was also designed to conceal its existence from static code analyzers and tools by delaying the addition of the actual code until the build phase when the binary of the mobile application is produced. Also malicious code only appeared in the minified version of flatmap-stream that made it invisible for Github community.
Attackers took careful measures hide the presence of the code for as long as possible but did not take into the consideration the depreciation warning that the malicious code would eventually generate. Attackers also had an opportunity and time to prepare a sophisticated attack using code injection because the targeted application: Copay is open-source and runs on open-source build servers, that gives attackers full visibility and ability to test their code before releasing it
How this could have been prevented
The weakest part of the open-source process is no standard policy for assigning maintainers to the libraries. This vulnerability was easily exploited by right9ctrl to make modifications to one of the most popular NodeJS libraries. Keeping above in mind the weakness of Copay application is the usage of unknown dependencies in a mobile app that handles financial transactions and stores highly sensitive information. Since Copay has not demonstrated an ability to check each code dependency it uses for the application, a similar attack like this may happen to Copay and other apps that rely on open-source libraries again.
Having the process of security testing and security rating open-source libraries could be a long-term solution to help prevent open-source packages being infected again.