{"id":5026,"date":"2018-12-10T20:50:04","date_gmt":"2018-12-10T19:50:04","guid":{"rendered":"https:\/\/monodes.com\/predaelli\/?p=5026"},"modified":"2018-12-10T14:53:01","modified_gmt":"2018-12-10T13:53:01","slug":"exploiting-developer-infrastructure-is-ridiculously-easy","status":"publish","type":"post","link":"https:\/\/monodes.com\/predaelli\/2018\/12\/10\/exploiting-developer-infrastructure-is-ridiculously-easy\/","title":{"rendered":"Exploiting Developer Infrastructure Is Ridiculously Easy"},"content":{"rendered":"<blockquote>\n<h1><a href=\"https:\/\/medium.com\/s\/story\/exploiting-developer-infrastructure-is-insanely-easy-9849937e81d4\"><img data-recalc-dims=\"1\" decoding=\"async\" class=\"alignnone size-full\" src=\"https:\/\/i0.wp.com\/cdn-images-1.medium.com\/focal\/1200\/632\/69\/44\/1%2A7Bt-RaFSLD263mR7RMC4aw.jpeg?w=910&#038;ssl=1\" alt=\"\"\/><\/a>The open-source ecosystem is broken<\/h1>\n<\/blockquote>\n<p>Source: <em><a href=\"https:\/\/medium.com\/s\/story\/exploiting-developer-infrastructure-is-insanely-easy-9849937e81d4\">Exploiting Developer Infrastructure Is Ridiculously Easy<\/a><\/em><\/p>\n<p>That&#8217;s why Debian has its own repositories.<\/p>\n<p><!--more--><!--nextpage--><\/p>\n<blockquote>\n<h1 class=\"elevate-h1 u-marginBottom16 u-md-marginBottom8\">Exploiting Developer Infrastructure Is Ridiculously Easy<\/h1>\n<p class=\"elevate-summary u-md-marginBottom24\">The open-source ecosystem is broken<\/p>\n<div class=\"uiScale uiScale-ui--large uiScale-caption--regular\">\n<div class=\"u-flexCenter \">\n<div class=\"u-flex0 u-paddingRight10\"><a class=\"link u-baseColor--link avatar\" dir=\"auto\" href=\"https:\/\/medium.com\/@jsoverson\" data-action=\"show-user-card\" data-action-value=\"a19804ea02f3\" data-action-type=\"hover\" data-user-id=\"a19804ea02f3\"><img data-recalc-dims=\"1\" decoding=\"async\" class=\"avatar-image avatar-image--small\" src=\"https:\/\/i0.wp.com\/cdn-images-1.medium.com\/fit\/c\/78\/78\/1%2ADUjBSZ8vCnqtthWwHubL9A.png?w=910&#038;ssl=1\" alt=\"Go to the profile of Jarrod Overson\"\/><\/a><\/div>\n<div class=\"u-flexTop u-noWrapWithEllipsis u-flex0\">\n<div class=\"u-noWrapWithEllipsis u-flex0\">\n<div class=\"ui-captionStrong u-noWrapWithEllipsis\">\n<div class=\"u-flexEnd u-marginBottom4\"><a class=\"ds-link ds-link--styleSubtle postMetaInline postMetaInline--author\" dir=\"auto\" href=\"https:\/\/medium.com\/@jsoverson\" data-action=\"show-user-card\" data-action-value=\"a19804ea02f3\" data-action-type=\"hover\" data-user-id=\"a19804ea02f3\">Jarrod Overson<\/a><\/p>\n<div class=\"u-marginLeft8\"><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"ui-caption u-noWrapWithEllipsis\"><span class=\"u-noWrap\" data-tooltip=\"Updated Dec 5\"><time class=\"u-inlineBlock u-lineHeightBase\">Nov 27<\/time><\/span><\/div>\n<section class=\"elevateCoverContainer elevateCoverContainer--withImage\">\n<div class=\"elevateCover\">\n<div class=\"elevateCover-image\"><\/div>\n<div class=\"uiScale uiScale-ui--regular uiScale-caption--regular elevateCover-imageCaption elevateCover-content elevateCover-content--withImage u-paddingTop10 u-paddingRight0 u-xs-paddingRight16 u-xs-paddingBottom10 u-md-show\">\n<p id=\"384e\" class=\"graf graf--p\">Photo: <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/unsplash.com\/photos\/pjAH2Ax4uWk?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/unsplash.com\/photos\/pjAH2Ax4uWk?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Charles Deluvio<\/a>\/<a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/unsplash.com\/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/unsplash.com\/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Unsplash<\/a><\/p>\n<\/div>\n<\/div>\n<\/section>\n<div class=\"elevate-container u-relative u-marginAuto\">\n<div class=\"elevateSidebar\" data-scroll=\"native\">\n<div class=\"js-elevatePostActions u-foreground u-md-left50 u-sm-hide u-absolute\" data-scroll=\"fixed\">\n<div class=\"u-paddingTop30 u-md-paddingTop0 elevate-actions uiScale uiScale-ui--regular uiScale-caption--small\">\n<div class=\"multirecommend js-actionMultirecommend u-flexCenter\" data-post-id=\"9849937e81d4\" data-is-label-padded=\"true\" data-has-recommend-list=\"true\" data-source=\"-----9849937e81d4---------------------clap_elevate\">\n<div class=\"u-relative u-foreground\"><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"u-flex u-flexCenter u-marginTop15 elevate-actions\">\n<div class=\"u-flex0\"><\/div>\n<\/div>\n<div class=\"u-marginTop10 elevate-actions\"><\/div>\n<div class=\"u-marginTop10 elevate-actions\"><\/div>\n<div class=\"postArticle-content js-postField js-notesSource js-trackedPost\" data-post-id=\"9849937e81d4\" data-source=\"post_elevate_sequence_page\" data-tracking-context=\"postPage\" data-scroll=\"native\">\n<section class=\"section section--body section--first section--last\">\n<div class=\"section-content\">\n<div class=\"section-inner sectionLayout--insetColumn\"><\/div>\n<div class=\"section-inner sectionLayout--insetColumn\">\n<p id=\"2b21\" class=\"graf graf--p graf--hasDropCapModel graf--hasDropCap graf--leading\"><span class=\"graf-dropCap\">In<\/span> late October, an issue was opened on an extremely popular node.js tool, nodemon, describing <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/remy\/nodemon\/issues\/1442\" target=\"_blank\" rel=\"nofollow noopener\" data-href=\"https:\/\/github.com\/remy\/nodemon\/issues\/1442\">a deprecation warning<\/a> that was being logged to the console.<\/p>\n<p id=\"d7a2\" class=\"graf graf--p graf-after--p\">Warnings like these aren\u2019t uncommon. This one seemed harmless. It wasn\u2019t even related to the nodemon project, but rather to one of its dependencies. This easily could have gone completely ignored because, in many cases, warnings like these often resolve themselves.<\/p>\n<p id=\"95b5\" class=\"graf graf--p graf-after--p\">About three weeks after the initial report, <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/FallingSnow\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/github.com\/FallingSnow\">Ayrton Sparling<\/a> experienced the log output himself and <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/dominictarr\/event-stream\/issues\/116\" target=\"_blank\" rel=\"nofollow noopener\" data-href=\"https:\/\/github.com\/dominictarr\/event-stream\/issues\/116\">found that a new dependency<\/a> several layers deep was the cause of the warning. The output was coming from a strange bit of code at the end of a minified JavaScript file that did not exist in an earlier version and had been removed in a later version (compare <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/unpkg.com\/flatmap-stream@0.1.0\/index.min.js\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/unpkg.com\/flatmap-stream@0.1.0\/index.min.js\">flatmap-stream@0.1.0<\/a>, <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/unpkg.com\/flatmap-stream@0.1.1\/index.min.js\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/unpkg.com\/flatmap-stream@0.1.1\/index.min.js\">flatmap-stream@0.1.1<\/a>, and <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/unpkg.com\/flatmap-stream@0.1.2\/index.min.js\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/unpkg.com\/flatmap-stream@0.1.2\/index.min.js\">flatmap-stream@0.1.2<\/a>). Ayrton\u2019s research led him to a popular npm library, <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/www.npmjs.com\/package\/event-stream\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/www.npmjs.com\/package\/event-stream\">event-stream<\/a>, which is downloaded nearly two million times a week and, up until recently, was maintained by a reputable open-source developer.<\/p>\n<p id=\"c402\" class=\"graf graf--p graf-after--p\">Several months ago, control of event-stream changed hands, legitimately, to a relatively unknown user who <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/dominictarr\/event-stream\/issues\/116#issuecomment-440927400\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/github.com\/dominictarr\/event-stream\/issues\/116#issuecomment-440927400\">asked for publishing rights over email<\/a>. This user then updated event-stream to include the exploited flatmap-stream dependency in a patch version and then bumped the major version of event-stream without the dependency to limit the visibility of the change. New users who, presumably, are a little more inclined to question dependencies would get the latest version (4.x as of this writing) and users who depend on the previous version would automatically update to the infected patch release whenever npm install runs again (with many common configurations).<\/p>\n<h3 id=\"19e8\" class=\"graf graf--h3 graf-after--p\">Details of the&nbsp;Exploit<\/h3>\n<p id=\"1944\" class=\"graf graf--p graf-after--h3\">The payload on flatmap-stream was set up to <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/unpkg.com\/flatmap-stream@0.1.1\/test\/data\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/unpkg.com\/flatmap-stream@0.1.1\/test\/data\">ingest a data file<\/a> that had, among some trivially obfuscated strings, two encrypted payloads that could only be decrypted with a known password.<\/p>\n<figure id=\"7fca\" class=\"graf graf--figure graf--iframe graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"aspectRatioPlaceholder-fill\"><\/div>\n<div class=\"progressiveMedia js-progressiveMedia is-canvasLoaded is-imageLoaded\" data-scroll=\"native\"><\/div>\n<\/div>\n<\/figure>\n<\/div>\n<\/div>\n<\/section>\n<\/div>\n<figure id=\"7fca\" class=\"graf graf--figure graf--iframe graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"progressiveMedia js-progressiveMedia is-canvasLoaded is-imageLoaded\" data-scroll=\"native\">\n<div class=\"iframeContainer\"><iframe loading=\"lazy\" class=\"progressiveMedia-iframe js-progressiveMedia-iframe\" src=\"https:\/\/medium.com\/media\/dd64c6c673bcecb60cb4cecbb7922bce?postId=9849937e81d4\" allowfullscreen=\"allowfullscreen\" data-src=\"\/media\/dd64c6c673bcecb60cb4cecbb7922bce?postId=9849937e81d4\" data-media-id=\"dd64c6c673bcecb60cb4cecbb7922bce\" data-thumbnail=\"https:\/\/i.embed.ly\/1\/image?url=https%3A%2F%2Favatars1.githubusercontent.com%2Fu%2F842798%3Fs%3D400%26v%3D4&amp;key=a19fcc184b9711e1b4764040d3dc5c07\" data-mce-fragment=\"1\" width=\"700\" height=\"250\" frameborder=\"0\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<\/figure>\n<p id=\"adb7\" class=\"graf graf--p graf-after--figure\">This payload looked for the password in an environment variable named <strong class=\"markup--strong markup--p-strong\">npm_package_description <\/strong>set by npm, node\u2019s package manager. This environment variable is set to the root package\u2019s description, which allows this payload to scope its effects to a particular target package. Clever! In this case, the package was the <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/copay.io\/\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/copay.io\/\">client application for the bitcoin wallet Copay<\/a> and the password to decrypt the payload is the phrase \u201c<a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/bitpay\/copay\/blob\/master\/package.json#L3\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/github.com\/bitpay\/copay\/blob\/master\/package.json#L3\">A Secure Bitcoin Wallet<\/a>\u201d (found via brute force by Github user <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/dominictarr\/event-stream\/issues\/116#issuecomment-441744514\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/github.com\/dominictarr\/event-stream\/issues\/116#issuecomment-441744514\">maths22<\/a>).<\/p>\n<p id=\"6cd2\" class=\"graf graf--p graf-after--p\">After payload A successfully decodes the first entry in the test data, it executes payload B included below:<\/p>\n<figure id=\"acb5\" class=\"graf graf--figure graf--iframe graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"aspectRatioPlaceholder-fill\"><\/div>\n<div class=\"progressiveMedia js-progressiveMedia is-canvasLoaded is-imageLoaded\" data-scroll=\"native\"><\/div>\n<\/div>\n<\/figure>\n<figure id=\"acb5\" class=\"graf graf--figure graf--iframe graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"progressiveMedia js-progressiveMedia is-canvasLoaded is-imageLoaded\" data-scroll=\"native\">\n<div class=\"iframeContainer\"><iframe loading=\"lazy\" class=\"progressiveMedia-iframe js-progressiveMedia-iframe\" src=\"https:\/\/medium.com\/media\/6dd4933d325efd7cb47f37c61b2915fa?postId=9849937e81d4\" allowfullscreen=\"allowfullscreen\" data-src=\"\/media\/6dd4933d325efd7cb47f37c61b2915fa?postId=9849937e81d4\" data-media-id=\"6dd4933d325efd7cb47f37c61b2915fa\" data-thumbnail=\"https:\/\/i.embed.ly\/1\/image?url=https%3A%2F%2Favatars1.githubusercontent.com%2Fu%2F842798%3Fs%3D400%26v%3D4&amp;key=a19fcc184b9711e1b4764040d3dc5c07\" data-mce-fragment=\"1\" width=\"700\" height=\"250\" frameborder=\"0\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<\/figure>\n<p id=\"85f0\" class=\"graf graf--p graf-after--figure\">This code then makes sure to only continue executing if the script is being run with a particular command line argument, something that follows the pattern \u201cbuild:*-release\u201d, like <strong class=\"markup--strong markup--p-strong\">npm run build:ios-release<\/strong>. This isolates the execution down to only three build scripts in the Copay build pipeline, the <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/bitpay\/copay\/blob\/master\/package.json#L70-L72\" target=\"_blank\" rel=\"nofollow noopener\" data-href=\"https:\/\/github.com\/bitpay\/copay\/blob\/master\/package.json#L70-L72\">scripts in charge of building the hybrid iOS, Android, and desktop applications<\/a>.<\/p>\n<p id=\"1f6f\" class=\"graf graf--p graf-after--p\">The script then searches for the internals of another dependency of the application, ReedSolomonDecoder.js from the package <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/www.npmjs.com\/package\/@zxing\/library\" target=\"_blank\" rel=\"nofollow noopener\" data-href=\"https:\/\/www.npmjs.com\/package\/@zxing\/library\">@zxing\/library<\/a>. Payload B doesn\u2019t execute this file, it simply injects the next stage, payload C, so that this final payload is executed in the mobile application itself when ReedSolomonDecoder loads. A beautified payload C is included below.<\/p>\n<figure id=\"7dc3\" class=\"graf graf--figure graf--iframe graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"aspectRatioPlaceholder-fill\"><\/div>\n<div class=\"progressiveMedia js-progressiveMedia is-canvasLoaded is-imageLoaded\" data-scroll=\"native\"><\/div>\n<\/div>\n<\/figure>\n<figure id=\"7dc3\" class=\"graf graf--figure graf--iframe graf-after--p\">\n<div class=\"aspectRatioPlaceholder is-locked\">\n<div class=\"progressiveMedia js-progressiveMedia is-canvasLoaded is-imageLoaded\" data-scroll=\"native\">\n<div class=\"iframeContainer\"><iframe loading=\"lazy\" class=\"progressiveMedia-iframe js-progressiveMedia-iframe\" src=\"https:\/\/medium.com\/media\/587268c2640f2d4572757644bd6a7ad7?postId=9849937e81d4\" allowfullscreen=\"allowfullscreen\" data-src=\"\/media\/587268c2640f2d4572757644bd6a7ad7?postId=9849937e81d4\" data-media-id=\"587268c2640f2d4572757644bd6a7ad7\" data-thumbnail=\"https:\/\/i.embed.ly\/1\/image?url=https%3A%2F%2Favatars1.githubusercontent.com%2Fu%2F842798%3Fs%3D400%26v%3D4&amp;key=a19fcc184b9711e1b4764040d3dc5c07\" data-mce-fragment=\"1\" width=\"700\" height=\"250\" frameborder=\"0\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<\/figure>\n<p id=\"0191\" class=\"graf graf--p graf-after--figure\">Payloads A and B were to be run via node.js by way of npm on a build server somewhere, but payload C is intended to be run within a browser-like environment controlled by Cordova. <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/cordova.apache.org\/\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/cordova.apache.org\/\">Cordova<\/a> (previously <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/phonegap.com\/\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/phonegap.com\/\">PhoneGap<\/a>) is a framework that allows you to build native applications with web technology like HTML, CSS, and JavaScript. Copay\u2019s iOS, Android, and desktop clients (along with forks like <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/www.fcash.cash\/\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/www.fcash.cash\/\">FCash<\/a>) are all built with Cordova and this is where the damage occurs. These native applications are intended to be used by end users looking to manage their bitcoin wallets\u2014and that\u2019s precisely what this is intended to steal. This script manages the passing of data around in multiple contexts and eventually posts the target data to the servers at copayapi.host and 111.90.151.134.<\/p>\n<blockquote id=\"f1ef\" class=\"graf graf--pullquote graf-after--p\"><p>So much software is built on the backs of people who are expected to work for&nbsp;free.<\/p><\/blockquote>\n<p id=\"4aa7\" class=\"graf graf--p graf-after--pullquote\">The amount of effort this took was not trivial. This exploit took a lot of research and planning, and it likely had backup routes in the case that event-stream wasn\u2019t able to be hijacked. Given the way the attack played out, it seems plausible that the actor targeted Copay specifically rather than grabbing a valuable library and planning out an attack from there. The popularity of event-stream meant that the attacker had an easy route into privileged computers in hundreds of companies across the globe. Thankfully, it was limited and quickly caught considering how long it could have gone unnoticed, but thinking about what could have happened leads us to an obvious conclusion:<\/p>\n<h3 id=\"3f3d\" class=\"graf graf--h3 graf-after--p\">Open Source Is Incredibly Broken<\/h3>\n<p id=\"20b7\" class=\"graf graf--p graf-after--h3\">Let\u2019s count all the things that went wrong.<\/p>\n<ol class=\"postList\">\n<li id=\"7ac9\" class=\"graf graf--li graf-after--p\">An application (Copay) was built by consuming dependencies over the network without the entire tree\u2019s dependencies locked.<\/li>\n<li id=\"8a17\" class=\"graf graf--li graf-after--li\">Even without locked versions, those dependencies aren\u2019t cached and are pulled on every build.<\/li>\n<li id=\"763a\" class=\"graf graf--li graf-after--li\"><a class=\"markup--anchor markup--li-anchor\" href=\"https:\/\/www.npmjs.com\/package\/event-stream?activeTab=dependents\" target=\"_blank\" rel=\"nofollow noopener\" data-href=\"https:\/\/www.npmjs.com\/package\/event-stream?activeTab=dependents\">Thousands<\/a> of other projects are dependent on event-stream with the same or similar configurations.<\/li>\n<li id=\"8737\" class=\"graf graf--li graf-after--li\">The maintainer stopped caring about a library that thousands of projects depended on.<\/li>\n<li id=\"b16b\" class=\"graf graf--li graf-after--li\">Thousands of projects consume this library for free and expect it to be maintained without any compensation.<\/li>\n<li id=\"184b\" class=\"graf graf--li graf-after--li\">The maintainer gave full control to an unknown entity just because they asked for it.<\/li>\n<li id=\"80a6\" class=\"graf graf--li graf-after--li\">There was no notification that control had changed, thousands of projects were just expected to consume the package with no warning.<\/li>\n<li id=\"dacb\" class=\"graf graf--li graf-after--li\">There\u2019s really no end\u2014this list of things that went wrong could go on and on\u2026<\/li>\n<\/ol>\n<p id=\"cdb8\" class=\"graf graf--p graf-after--li\">The damage this could have caused is incredible to think about. The projects that depend on this aren\u2019t trivial either. <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/www.npmjs.com\/package\/azure-cli\" target=\"_blank\" rel=\"noopener nofollow\" data-href=\"https:\/\/www.npmjs.com\/package\/azure-cli\">Microsoft\u2019s original Azure CLI depends on event-stream<\/a>. Think of the systems that either develop that tool or run that tool. Each one of those potentially had this malicious code installed.<\/p>\n<blockquote id=\"5c5e\" class=\"graf graf--pullquote graf-after--p\"><p>Open source is broken, and the larger it grows the more likely that catastrophic events will&nbsp;occur.<\/p><\/blockquote>\n<p id=\"e7a1\" class=\"graf graf--p graf-after--pullquote\"><span class=\"markup--quote markup--p-quote is-other\" data-creator-ids=\"anon\">The problem is that so much software is built on the backs of people who are expected to work for free.<\/span> They deliver useful software once but are expected to maintain it until the end of time. If they can\u2019t, either they go dormant and ignore requests or security vulnerabilities (<a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/github.com\/jsoverson?utf8=%E2%9C%93&amp;tab=repositories&amp;q=&amp;type=&amp;language=javascript\" target=\"_blank\" rel=\"noopener nofollow noopener\" data-href=\"https:\/\/github.com\/jsoverson?utf8=%E2%9C%93&amp;tab=repositories&amp;q=&amp;type=&amp;language=javascript\">guilty!<\/a>) or they pass the baton to someone else hoping they can get away without getting tagged ever again. Sometimes it works. Sometimes it doesn\u2019t. But no outcome can excuse the security vulnerabilities this exposes in the software supply chain. Even the discovery of, research into, and subsequent damage control for this exploit was done largely by unpaid volunteers of the open-source ecosystem.<\/p>\n<p id=\"1e4c\" class=\"graf graf--p graf-after--p graf--trailing\">The fault is so widely distributed there\u2019s no use in placing blame. Open source, as it has grown, is broken. The larger it grows, the more likely it is that catastrophic events will occur. Given the potential for damage with this exploit, the fact that it was so limited is a blessing. It\u2019s also not limited to node.js or npm; there is just as much misplaced trust in sister ecosystems like Python\u2019s pypi and Ruby\u2019s gems\u200a\u2014\u200aand with Github as a service itself. Anyone can publish to these, and control can change without any notice. Even without a change of control, there\u2019s so much code that thoroughly vetting it all in the first place would grind any team to a halt. In order to meet timelines, developers install what they need to install, and security teams and automated tools just aren\u2019t able to adapt to the pace of ever-changing software.<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p class=\"excerpt\">The open-source ecosystem is broken Source: Exploiting Developer Infrastructure Is Ridiculously Easy That&#8217;s why Debian has its own repositories.<\/p>\n<p class=\"more-link-p\"><a class=\"more-link\" href=\"https:\/\/monodes.com\/predaelli\/2018\/12\/10\/exploiting-developer-infrastructure-is-ridiculously-easy\/\">Read more &rarr;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"Exploiting Developer Infrastructure Is Ridiculously Easy - that\u00ecs why Debian and Fedora have their own repositories.","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[171,50,218],"tags":[],"class_list":["post-5026","post","type-post","status-publish","format-standard","hentry","category-ethics","category-javascript","category-security"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6daft-1j4","jetpack-related-posts":[{"id":14284,"url":"https:\/\/monodes.com\/predaelli\/2025\/11\/11\/lets-demand-free-software-for-public-infrastructures\/","url_meta":{"origin":5026,"position":0},"title":"Let&#8217;s demand Free Software for public infrastructures!","author":"Paolo Redaelli","date":"2025-11-11","format":false,"excerpt":"I want to share here and endorse the post made by Jan Wildeboer on the Fediverse about \"EU Eyes Banning Huawei, ZTE Corp From Mobile Networks of Member Countries\": \u2026 Instead of banning, say, Chinese companies from delivering infrastructure components like the EU is pondering with Huawei and mobile networks,\u2026","rel":"","context":"In &quot;Ethics&quot;","block_context":{"text":"Ethics","link":"https:\/\/monodes.com\/predaelli\/category\/ethics\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":11626,"url":"https:\/\/monodes.com\/predaelli\/2024\/05\/05\/40-tools-for-ethical-hacking\/","url_meta":{"origin":5026,"position":1},"title":"40 tools for ethical hacking","author":"Paolo Redaelli","date":"2024-05-05","format":false,"excerpt":"I know many of them, but not everyone! Shame on me! Here are 40 tools for ethical hacking! Nmap: Network scanner used for network discovery and security auditing. Wireshark: Network protocol analyzer for packet inspection and troubleshooting. Metasploit: Penetration testing framework for exploiting vulnerabilities. John the Ripper: Password cracking tool\u2026","rel":"","context":"In &quot;Tricks&quot;","block_context":{"text":"Tricks","link":"https:\/\/monodes.com\/predaelli\/category\/documentations\/tricks\/"},"img":{"alt_text":"\ud83d\udd0d","src":"https:\/\/static.xx.fbcdn.net\/images\/emoji.php\/v9\/tc1\/1\/16\/1f50d.png","width":350,"height":200},"classes":[]},{"id":4827,"url":"https:\/\/monodes.com\/predaelli\/2018\/11\/04\/on-why-there-will-never-be-another-red-hat\/","url_meta":{"origin":5026,"position":2},"title":"On Why There Will Never Be Another Red Hat","author":"Paolo Redaelli","date":"2018-11-04","format":false,"excerpt":"Why There Will Never Be Another Red Hat: The Economics of Open Source \u2013 Andreessen Horowitz is a perfectly-sound article from a pure \"profit-only\" point of view. What the author misses is that Amazon infrastructure is overwhelmingly built on Free Software, that even companies like Microsoft and Oracle put lots\u2026","rel":"","context":"In &quot;Senza categoria&quot;","block_context":{"text":"Senza categoria","link":"https:\/\/monodes.com\/predaelli\/category\/senza-categoria\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":12266,"url":"https:\/\/monodes.com\/predaelli\/2025\/01\/15\/wordpress-is-in-trouble\/","url_meta":{"origin":5026,"position":3},"title":"WordPress is in trouble","author":"Paolo Redaelli","date":"2025-01-15","format":"link","excerpt":"WordPress is in trouble \ud83d\ude31 WordPress is in trouble January 11, 2025 Since I last wrote about WordPress, things have gone off the rails. This after a brief period when things were blissfully quiet. Matt Mullenweg stopped commenting for a while, though his company had launched WP Engine Tracker \u2014\u2026","rel":"","context":"In &quot;Ethics&quot;","block_context":{"text":"Ethics","link":"https:\/\/monodes.com\/predaelli\/category\/ethics\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":15509,"url":"https:\/\/monodes.com\/predaelli\/2026\/04\/19\/15509\/","url_meta":{"origin":5026,"position":4},"title":"Mozilla 'Thunderbolt' Is an Open-Source\u2026","author":"Paolo Redaelli","date":"2026-04-19","format":"link","excerpt":"Mozilla 'Thunderbolt' Is an Open-Source AI Client Focused On Control and Self-Hosting BrianFagioli writes: Mozilla's email subsidiary MZLA Technologies just introduced Thunderbolt, an open-source AI client aimed at organizations that want to run AI on their own infrastructure instead of relying entirely on cloud services. The idea is to give\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/monodes.com\/predaelli\/category\/software\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":11699,"url":"https:\/\/monodes.com\/predaelli\/2024\/06\/02\/casaos-a-simple-easy-to-use-elegant-open-source-personal-cloud-system\/","url_meta":{"origin":5026,"position":5},"title":"CasaOS &#8211; A simple, easy-to-use, elegant open-source personal cloud system","author":"Paolo Redaelli","date":"2024-06-02","format":false,"excerpt":"CasaOS is a simple, easy-to-use, elegant open-source personal cloud system Source: CasaOS - A simple, easy-to-use, elegant open-source personal cloud system","rel":"","context":"In &quot;Senza categoria&quot;","block_context":{"text":"Senza categoria","link":"https:\/\/monodes.com\/predaelli\/category\/senza-categoria\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/5026","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/comments?post=5026"}],"version-history":[{"count":0,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/5026\/revisions"}],"wp:attachment":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/media?parent=5026"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/categories?post=5026"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/tags?post=5026"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}