Self-hosted service
trailofbits/eth-security-toolbox avatar
trailofbits/eth-security-toolbox

eth-security-toolbox: a container with the Ethereum security tools preinstalled

A Docker container preconfigured with all of the Trail of Bits Ethereum security tools.

731 stars120 forksDockerfileAGPL-3.0

At a glance

What is it?
The Ethereum Security Toolbox is a Docker image that bundles Echidna, Medusa, Slither, solc-select, Foundry and Vyper so a Solidity auditor does not install each one by hand. It has a lighter CI variant and a labelling scheme designed so a workflow can pin an exact image by digest.
Who is it for?
Adopt the eth-security-toolbox if you audit or fuzz Solidity code and want a reproducible environment where the tool versions are fixed, since pinning a nightly image by digest in CI is the pattern the project recommends and it saves hours of per-machine setup.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 59 days ago.
What is it written in?
Mainly Dockerfile, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The environment is the deliverable

The eth-security-toolbox repository contains scripts to create a Docker container preinstalled and preconfigured with the Trail of Bits Ethereum security tools. The primary language of the repository is the Dockerfile itself, and the top level is small: a Dockerfile, a motd, a LICENSE, a CODEOWNERS file and the README.

The tools that come from Trail of Bits are the ones that matter. Echidna is the property-based fuzz tester, Medusa is a fuzz tester based on go-ethereum, Slither is the static analysis tool, solc-select lets you switch between Solidity compiler versions quickly, and there is the building secure contracts repository with its documentation.

The third-party additions fill in the gaps around them. Foundry is a toolkit for Ethereum application development, Vyper is the Pythonic smart contract language for the EVM, and the Node side is handled by n, a Node version manager, with npm and Yarn and Python also present.

That combination is the point. Auditing a Solidity project is rarely a single tool run, it is a fuzzer, a static analyser, a compiler version that matches the target and a working Node environment for the build. Assembling that on every machine and every CI runner is the friction this image removes.

The project is AGPL-3.0 licensed, and the README says to contact Trail of Bits if you are looking for an exception to the terms. The default branch is master, the last push was on 2026-08-24, and there are no GitHub releases, because the artefact here is the container image rather than a source release.

Running the prebuilt image, or building it yourself

The quickstart uses the prebuilt container from GitHub Container Registry:

shell
docker pull ghcr.io/trailofbits/eth-security-toolbox:nightly
docker run -it ghcr.io/trailofbits/eth-security-toolbox:nightly

The alternative is to build the image from the source:

shell
git clone https://github.com/trailofbits/eth-security-toolbox.git
cd eth-security-toolbox
docker build -t eth-security-toolbox .

The Dockerfile is a multi-stage build and reading it tells you a lot about the design. Medusa is compiled from source in a golang 1.25 stage, where the repository is cloned, the latest tag is derived with git describe, and the binary is built with trimpath and stripped with the -s -w ldflags. Echidna is not built but pulled from a prebuilt image at ghcr.io/crytic/echidna/echidna:latest, and the binary is copied out with the executable bit set.

The base is ubuntu:jammy with the common tools installed, including bash-completion, curl, git, jq, python3-pip, python3-venv, sudo, unzip and wget. The n installer is fetched with curl, and the Dockerfile verifies it against an expected SHA-256 checksum and exits if the checksum does not match, with a message saying the N installer does not match the expected checksum. That check is the kind of thing that belongs in a build file and rarely does.

Node is then installed with n, npm and Yarn are added, and the final image copies the echidna and medusa binaries in with the root ownership. The medusa bash completion is generated at build time and written into /etc/bash_completion.d/, and the container's command is /bin/bash.

Switching Solidity compiler versions with solc-select

Several Solidity versions are preinstalled via solc-select, and by default solc corresponds to the latest release. The README shows both the version switch and the list of what is installed:

shell
$ solc --version
solc, the solidity compiler commandline interface
Version: 0.8.22+commit.4fc1097e.Linux.g++
$ solc-select use 0.4.26
$ solc --version
solc, the solidity compiler commandline interface
Version: 0.4.26+commit.4563c3fc.Linux.g++

The installed list shows the spread of versions:

shell
$ solc-select versions
0.8.22 (current, set by /home/ethsec/.solc-select/global-version)
0.7.6
0.6.12
0.5.17
0.4.26

And you can install more from inside the container, with the global version moved as a side effect:

shell
ethsec@f95fb29a709d:~$ solc-select install 0.8.0
Installing solc '0.8.0'...
Version '0.8.0' installed.
ethsec@f95fb29a709d:~$ solc-select use 0.8.0
Switched global version to 0.8.0

The compiler version is a real variable in an audit, because a finding that reproduces on one version may not on another, and because a project pinned to an old pragma needs that old compiler. Having 0.4.26 through 0.8.22 available in one image removes the usual friction of matching the compiler to the target.

The Node side works the same way. The toolbox comes preinstalled with an LTS version of Node along with n, and other versions can be installed with it:

shell
$ sudo n 14
  installing : node-v14.21.3
       mkdir : /usr/local/n/versions/node/14.21.3
       fetch : https://nodejs.org/dist/v14.21.3/node-v14.21.3-linux-arm64.tar.gz
     copying : node/14.21.3
   installed : v14.21.3 (with npm 6.14.18)
$ node --version
v14.21.3

That example also shows the multi-architecture support, since the fetched archive is the linux-arm64 build.

The CI variant drops the conveniences on purpose

A variant of the image is published separately as ghcr.io/trailofbits/eth-security-toolbox/ci, and the README says it is meant to be slightly lighter and better suited to CI contexts such as GitHub workflow jobs. The usage is a container block in a workflow:

yaml
# workflow triggers, ...

jobs:
  tests:
    runs-on: ubuntu-latest
    container: ghcr.io/trailofbits/eth-security-toolbox/ci:nightly
    steps:
      # other steps ...
      - run: medusa fuzz # or any tool from the image

The differences between the two images are listed, and every one of them is a deliberate trade.

The CI container does not have a dedicated non-root user, and all the tools are installed under the root user. Most autocompletions are not installed. No solc binaries are preinstalled, though you may continue to use solc-select to install any binaries you need. And pyevmasm and the building secure contracts repository are not included.

The solc point deserves a note, because it looks like a downgrade and is arguably a simplification. In CI you usually want exactly one compiler version, the one the project pins, and installing it during the job with solc-select is more explicit than inheriting five versions from the base image. The non-root user is a different story, and it is a real reduction in isolation for a container that runs untrusted test code.

The main image exists to be used interactively, with a shell you land in, and the CI image exists to be used by a workflow, and the split reflects those two uses rather than an accident of maintenance.

The label scheme exists so you can pin something that does not move

Both images follow the same labelling convention, and the table is short enough to read as a specification:

| Label | Description |--------------------|-------------------------------------------------------- | `nightly-YYYYMMDD` | Image built from the code in `master` on day YYYY-MM-DD | `nightly` | Alias for the latest `nightly-YYYYMMDD` container image | `testing-BRANCH` | Image built when the tip of `BRANCH` was last updated | `edge` | Alias for `testing-master` | `TAG` | Image built when `TAG` was tagged | `latest` | Alias for the latest `TAG` container image

The recommendation that follows is the practical advice in the whole README. To keep tooling in CI predictable, pick a nightly-YYYYMMDD image and pin it by hash in your workflow file, then establish a process to review the changes and update the container reference on a regular cadence, so that you can continue to benefit from tool improvements.

The syntax for the pinned reference is:

yaml
container: ghcr.io/trailofbits/eth-security-toolbox/ci:nightly-YYYYMMDD@sha256:HASH_GOES_HERE

The hashes can be obtained from the container registry page.

The reasoning behind this is the reason a nightly image exists at all. A fuzzing tool that changes under you turns a reproducibility problem into a moving target, so the project publishes daily builds with immutable names and tells you to pin one. The cost is that you own the update cadence, which is exactly the work the recommendation asks you to institutionalise rather than skip.

Where the toolbox is the wrong choice

The first wrong case is a host without Docker, or a policy that forbids containers. Everything here is delivered as an image, and the tools inside are the Trail of Bits projects themselves, which are Go, Python and Rust programs that you can install individually. The image is a convenience wrapper and nothing in it is only available there, so a restrictive environment can still have Slither and Echidna, just with more setup.

The second is a one-off audit. If you are checking one contract, a fuzzer that needs a container image of a gigabyte is a large step for a small job, and the individual tools install quickly enough on their own.

The third is a long-lived production pipeline where the tooling has to be pinned for years. The label scheme gives you immutability, but the recommended workflow is a regular review cycle, and the upstream tools move quickly. For a pipeline that must produce the same result in two years, a frozen internal image built from pinned upstream commits is a better answer than a pinned nightly that nobody updates.

The fourth is a security review of the container itself. The image installs its Node version manager with a checksum check, which is good practice, but the image runs a shell as root in the CI variant, pulls a prebuilt Echidna from a moving latest tag, and compiles Medusa from whatever the tag resolution gives on build day. If the threat model includes the build pipeline, you want to build the image yourself from a reviewed commit and pin the base image by digest, and the toolbox is then a starting Dockerfile rather than the artefact you run.

The alternative worth weighing is a language-native toolchain. Foundry, Hardhat and ApeWorX each install their own compiler versions, test harness and coverage tooling, and a Foundry or Hardhat project already contains most of what the toolbox provides. The toolbox is the better answer when you are auditing a project that is not already wired to one of those, or when you want several tools side by side on a codebase you did not write.

Editorial conclusion

Adopt the eth-security-toolbox if you audit or fuzz Solidity code and want a reproducible environment where the tool versions are fixed, since pinning a nightly image by digest in CI is the pattern the project recommends and it saves hours of per-machine setup. Keep away if you need the tools on a host without Docker, since everything here is delivered as a container image, or if you need the CI variant's conveniences, because that image drops the non-root user, the autocompletions, the preinstalled solc binaries, pyevmasm and the building secure contracts repository. Before you pin an image, read the label table in the README, since the nightly alias moves every day and the pinned by hash line is the only reproducible reference.

Frequently asked questions

What does the eth-security-toolbox image contain?

It ships Echidna, the property-based fuzz tester, Medusa, the go-ethereum based fuzz tester, Slither for static analysis, solc-select for switching compiler versions, the building secure contracts repository, and third-party tools including Foundry, Vyper, n as a Node version manager, npm, Yarn and Python.

How do I run the Ethereum Security Toolbox?

Pull the prebuilt image with docker pull ghcr.io/trailofbits/eth-security-toolbox:nightly and start it with docker run -it, or build it yourself by cloning the repository and running docker build -t eth-security-toolbox .. The image's command is a bash shell, so you land in an interactive session.

What is the difference between the CI variant of the toolbox and the main image?

The CI variant is slightly lighter. It has no dedicated non-root user and installs everything as root, most autocompletions are absent, no solc binaries are preinstalled so you use solc-select instead, and pyevmasm and the building secure contracts repository are not included.

How should I pin the toolbox image in a CI workflow?

The README recommends picking a nightly-YYYYMMDD image and pinning it by hash, in the form container: ghcr.io/trailofbits/eth-security-toolbox/ci:nightly-YYYYMMDD@sha256:HASH_GOES_HERE, and then reviewing and updating the reference on a regular cadence, since the nightly alias moves every day.

Official sources

  1. Issues
  2. License: AGPL-3.0
  3. README
  4. trailofbits/eth-security-toolbox on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/trailofbits-eth-security-toolbox.svg)](https://hysenlabs.com/projects/trailofbits-eth-security-toolbox)

Was this useful?