← cd ../posts

Building a SOAR Platform From Scratch: TheHive, Cortex, MISP, and Shuffle in Docker

May 17, 2026 #blue-team Informational 5 min read
Building a SOAR Platform From Scratch: TheHive, Cortex, MISP, and Shuffle in Docker — cover

Most "build your own SOC" tutorials stop at docker compose up and call it a day. This is what actually happens when you try to wire together TheHive, Cortex, MISP, and Shuffle into a working incident response platform, including the bugs nobody warns you about.

Introduction

There is a particular kind of cybersecurity project that looks impressive on a resume but never quite gets built. SOAR platforms tend to sit in that category. The components are open source. The documentation exists. The architecture diagrams are everywhere. And yet most people who try to stand one up end up with a half-working stack, give up, and write "experience with TheHive" on their resume anyway.

I decided to actually build it end to end. The goal was not to learn that TheHive ingests alerts or that Cortex runs analyzers. That is documentation reading. The goal was to discover the hundred small things that the documentation does not mention, and to come out the other side with a screenshot of real threat intelligence flowing through a platform I built myself. This is what happened.

The Stack

The setup uses TheHive 5.2 as the case management platform, Cortex 3.1.8 for IOC enrichment, MISP for threat intelligence storage, and Shuffle as the orchestration engine. Underneath that sits Cassandra as TheHive's database, Elasticsearch as the index backend, MinIO for attachment storage, and MariaDB plus Redis for MISP. Total container count is twelve. Total RAM budget is around fifteen gigabytes, which is uncomfortably tight but workable.

Everything runs in Docker Compose. The whole stack starts with two commands. That is the part the tutorials get right.

What the Tutorials Do Not Tell You

The Elasticsearch stored scripts problem. TheHive uses JanusGraph under the hood, which in turn uses Elasticsearch as its index. On first boot, JanusGraph tries to install stored scripts into Elasticsearch for indexing operations. Default Elasticsearch 7.17 configurations often disable stored scripts entirely. The result is that TheHive boots, retries ten times, fails ten times, crashes, gets restarted by Docker, and repeats this forever. The error message buried in the logs is "cannot put stored script, stored scripts are not enabled." The fix is one line in the compose file: script.allowed_types=inline,stored. Without that line you can wait an hour for a platform that will never start.

The Cortex docker-in-docker job directory. Cortex spawns analyzer containers on demand by talking to the Docker daemon on the host. Each analyzer reads its input from a shared job directory. The problem is that the obvious docker-compose configuration uses a named volume for this directory, which only Cortex itself can see. When Cortex starts an analyzer container, the analyzer mounts an empty version of that directory, finds no input file, tries to parse stdin as JSON, and crashes with a JSONDecodeError on line one column one. The fix is to bind-mount the host's actual /tmp/cortex-jobs path rather than using a named volume, so the spawned analyzer container can see the same files Cortex sees.

Container hostname versus localhost. When configuring the link between TheHive and Cortex through TheHive's admin UI, the natural instinct is to enter http://localhost:9001 because that is the URL you used in your browser. This will not work. TheHive is itself inside a container, and localhost inside that container means the TheHive container itself, not Cortex. The correct URL is http://cortex:9001, using the Docker network's service name. This is obvious in retrospect and not obvious the first time you encounter it.

Cortex super-admin cannot run analyzers. The super-admin user in Cortex exists in a special organisation called cortex and can only manage other organisations and users. Trying to run an analyzer as super-admin produces "Insufficient rights to perform this action." You need to create a separate organisation, then a separate user inside that organisation with the analyze role, then generate that user's API key, and use that key for everything analyst-related. The platform enforces a clean separation between platform administration and security operations, which is good practice but jarring on day one.

The Payoff

Once those problems are solved, the platform does what the marketing claims. A Python script can POST a phishing alert to TheHive's API and it appears in the analyst UI within seconds, complete with extracted observables. The analyst can click on an IP, run the AbuseIPDB analyzer, and get back real reputation data: country code, ISP, abuse confidence score, reporting history, attack categories. The pipeline that took commercial SOAR vendors years to build is sitting on a laptop running on Docker.

The first time real threat intelligence comes back through the platform, it feels disproportionately good. Three reports against a Russian cloud IP, categorised as Brute Force and Web App Attack, sourced from researchers in the United States, Germany, and Brazil. None of this data is impressive in isolation. The fact that it flowed automatically from a fake phishing alert through case creation through enrichment through display in an analyst dashboard, on infrastructure I assembled myself, is what makes it portfolio-worthy.

What You Learn That You Cannot Get From Documentation

The actual skill being developed during a build like this is not knowledge of any single tool. It is the ability to diagnose problems across a system of interacting components. When TheHive cannot connect to Cassandra, the error appears in TheHive's logs but the cause might be Cassandra's heap size, the Docker healthcheck timing, the network configuration, or a Java version mismatch. Working through that diagnostic process repeatedly is the same skill that working in a real SOC requires.

There is also a quieter lesson about open source security tooling. The free stack is genuinely capable. The bugs are real but solvable. The community knowledge required to solve them is scattered across GitHub issues from 2021, forum posts in three languages, and the occasional blog entry that mostly works. The willingness to assemble that knowledge into a working system is itself the differentiator.

Conclusion

A working SOAR platform on your laptop is not a credential. Anyone can run docker compose up. The credential is the ability to talk through the hour you spent diagnosing the stored scripts error, the moment you realised localhost was wrong, the decision to use a bind mount rather than a named volume. That is the experience that translates to a SOC role, and it is the experience that the resume bullet "experience with TheHive" never actually conveys. The platform is the artifact. The debugging is the skill.

← cd ~