RITA: hunting command and control in Zeek logs
Real Intelligence Threat Analytics (RITA) is a framework for detecting command and control communication through network traffic analysis.
At a glance
- What is it?
- RITA is a GPL 3 licensed Go framework that ingests Zeek network logs and looks for command and control behaviour in them, with beaconing detection, long connection detection, DNS tunnelling detection and threat intel feed checking, a scoring model you can adjust, and a terminal interface driven by a query language of its own. The judgement is that the architecture is right for a hunting tool, a ClickHouse store with a containerised pipeline around it, and that the install path is a shell script rather than a package.
- Who is it for?
- RITA fits a blue team that already runs Zeek and wants the traffic turned into a shortlist of connections worth looking at, because the detections run over the whole dataset and the scores make the output sortable.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A framework for hunting command and control
RITA stands for Real Intelligence Threat Analytics, and it is an open source framework for network traffic analysis, brought to you by Active Countermeasures and sponsored by Black Hills InfoSec.
The input is Zeek logs, in TSV or JSON format, and the readme is explicit that RITA requires Zeek to generate those network logs. If Zeek is not already installed, the readme points at a containerised Zeek with a start command, so the first thing to get working is the sensor rather than the analysis.
The four features are the whole product. Beaconing detection searches for signs of beaconing behaviour in and out of your network, which is the periodic callback that characterizes most command and control channels. Long connection detection makes it easy to see the connections that have been talking for a long time. DNS tunnelling detection looks for DNS based covert channels, which is the technique that survives a proxy that only permits name resolution. And threat intel feed checking queries feeds to find suspicious domains and hosts.
The framing is hunting rather than blocking. The readme points at AC-Hunter as the next step for hunting automation, futuristic visualisations and data enrichment, which tells you where the authors think RITA stops.
The project is GPL 3 licensed, written in Go, with a home page on the vendor's site, releases at 5.1.0 in September 2025, 5.1.1 in January 2026 and 5.1.2 in May 2026, and the last push on 2026-10-15.
Scoring is the part you tune
The configuration section is short and points at a document, and the document is about scoring, which tells you what the tool considers important.
The detections produce scores rather than verdicts. A connection gets a beacon score, and the search syntax compares that score numerically, and the sort syntax orders by it. The configuration file is where the thresholds live, and the readme says to see the configuration documentation for the details on adjusting scoring.
That is the right shape for a hunting tool. A binary answer to the question of whether a connection is malicious is only useful if you trust the detector completely, and a score is more useful than a verdict because the analyst decides where the threshold is, which is a decision that depends on the environment. A quiet office and a data centre with a lot of software updating itself have very different sensible thresholds.
The configuration is a file in a human format rather than a YAML or JSON document, and the repository carries two of them, config.hjson and default_config.hjson, plus a config directory. HJSON is the format, and it is in the dependency list, so the configuration is commented JSON with a friendlier syntax, which is a reasonable choice for a file an analyst is expected to edit.
The other configuration inputs are the threat intel feeds and a list of HTTP extensions, and the compose file mounts both as volumes into the container, so updating a feed is a file replacement rather than a rebuild.
The install is a tarball and a script
The quick start is three steps, and the first one is a requirement.
RITA requires Docker Engine with the Compose plugin, and the readme points at the recommended system requirements document before anything else. Then you download the RITA installer for the desired version from the releases page, uncompress the tarfile, and run the install script:
tar -xf rita-<version>-installer.tar.gz
./rita-<version>-installer/install_rita.shThere is no package manager entry and no container to run yourself, because the tool is a stack rather than a binary. What the script lays down is visible in the compose file in the repository, and it is three services.
There is RITA itself, built from the image published under the GitHub container registry, with a build section so it can be built locally, and it waits for the database to be healthy before it starts. There is a syslog-ng container, which is the piece that receives log data, exposed on the standard syslog port, and there is a ClickHouse server, which is the store.
The ClickHouse service has a health check that pings the HTTP interface, and both its HTTP and its native ports are published on the loopback address only, which is a detail worth copying, because the native port is the one you do not want reachable from the network.
The supported platforms are narrow and modern, CentOS 9 Stream, Rocky 9, RHEL 9 and Ubuntu 22.04 and 24.04, all on amd64.
Datasets, rolling imports and the rebuild flag
Data enters through the import command, and the naming is straightforward once you know the two flags.
rita import --database=mydatabase --logs=~/mylogsThe database argument is the name you would like to give the dataset, and the logs argument is the path to the Zeek logs you want to import. The command walks the directory and brings the connection records in.
The third flag is the interesting one. For datasets that should accumulate data over time, where the logs contain network information that is current, meaning less than twenty four hours old, you use the rolling flag when you create the dataset and on every subsequent import into it. The most common case the readme gives is importing logs from a Zeek sensor on a cron job every hour.
And then the warning, which is the kind of detail that prevents a silent wrong answer. For datasets that contain more than twenty four hours of logs but are themselves more than twenty four hours old, you import the top-level directory of the set of logs without the rolling flag, because importing those logs with the rolling flag may result in incorrect results.
The reason is in the name. Rolling means the dataset is treated as a window of recent activity, and the scoring of a beacon or a long connection depends on how much history is in the dataset, so feeding a rolling dataset a week of old logs changes the arithmetic underneath.
There is a third flag for the other kind of problem. The rebuild flag destroys and recreates a dataset, which is what you want when a previous import was wrong and you do not want the old rows.
A GitHub-style search language over the results
RITA follows a GitHub-style search syntax, where each field is written as a field name, a colon and a value, and the criteria are separated by spaces.
src:192.168.88.2 dst:165.227.88.15 beacon:>=90 sort:duration-descSo the search is a filter over the connections in the dataset, and the example combines a source address, a destination address, a minimum beacon score and a sort. The syntax is deliberately familiar, because the people who write these searches are used to filtering a list of things with a text query.
The fields are few and each one is a column in the result. Severity is one of critical, high, medium or low. The source is an IP address, and the destination is an IP address or a fully qualified domain name. The beacon score is a whole number compared with the usual operators. Duration is a string, an hour and minute figure like the example in the table, and it is compared the same way. The subdomain count is a whole number, and the threat intel flag is true or false.
The sort syntax is a field with a column and a direction, ascending or descending, and the columns you can sort by are severity, beacon, duration and subdomains. Sorting by duration and by beacon score are the two that answer the operational question, which is which connection has been talking for a long time and which one is the most regular.
The results are shown in a terminal interface, and there is a way out of it for scripting. The view command takes a stdout flag, or the short form, and prints the results as CSV instead of drawing them, and the readme is careful about the order of the arguments, the flag has to come before the name of the dataset.
ClickHouse behind a Bubble Tea interface
The dependency list describes the architecture, because each library is doing one of the jobs.
The store is ClickHouse, through its Go client, which is the right choice for a tool that asks analytical questions over a large set of connection records, and the compose file gives it a persistent volume. The configuration is HJSON, the environment is read with godotenv, the command line is urfave/cli, the logging is zerolog, and the input validation is the standard validator package.
The terminal interface is the Charm libraries, bubbletea for the program loop, bubbles for the widgets and lipgloss for the styling. That trio is why the interface can be a full screen table with a search bar and still feel like a native terminal program, and the readme's colour section is about the same layer, since the interface is colourful by default and the only requirement is that the TERM variable is set to xterm-256color, with the interface adjusting to a light or a dark terminal theme and a link to the Catpuccin themes for people who want to go further.
Progress reporting during an import is the other terminal-facing piece, with a progress bar library in the list, and the file system abstraction is there so the importer can be tested without touching a disk.
The tests are worth noting. The Makefile has separate targets for the unit tests, the integration tests, the database tests, the command tests and the viewer tests, and the integration and database tests carry a thirty minute timeout, because they run against a real ClickHouse brought up by testcontainers, with dedicated modules for the ClickHouse and the Compose images.
A static binary in a small Alpine image
The build produces one static binary and one very small image, and the Dockerfile shows both.
The builder stage is a Go image on Alpine, and the arguments for the target operating system and architecture are passed in so the same Dockerfile builds for every platform. The dependencies are copied before the source so that the module download is cached separately from the code, and the build itself runs through the Makefile with cgo disabled, which is what makes the binary static and the final image free of a C library.
The runtime stage is plain Alpine with the binary copied in and an entry point of that binary, and it is worth noticing what is not there. There is no shell script and no configuration file, because the compose file mounts the configuration, the threat intel feeds and the environment from the host, so the image contains the program and nothing else.
The Makefile is the other half of the build story. The version is taken from the most recent git tag and injected into the binary with a linker flag, which is how the tool reports which build it is, and the linker flags also ask for a static binary. The test targets split the suite the way the architecture splits it, with the unit tests excluding the integration, database, command and viewer directories, and the slower suites each given a generous timeout because they need containers.
The project is GPL 3 licensed, and it is an open source project from a company that sells a commercial tool in the same space.
Editorial conclusion
RITA fits a blue team that already runs Zeek and wants the traffic turned into a shortlist of connections worth looking at, because the detections run over the whole dataset and the scores make the output sortable. It is the wrong choice if you do not have Zeek logs, since the tool consumes them rather than capturing traffic, and it is the wrong choice if you need something you can install with one package manager command, because the install is a tarball and a shell script that lays down containers and configuration. Before you deploy it, read the system requirements document, and be careful with the rolling import flag, since the readme warns that using it on logs more than a day old gives incorrect results.
Frequently asked questions
What is RITA?
It is a GPL 3 licensed Go framework for network traffic analysis that ingests Zeek logs in TSV or JSON and searches them for command and control behaviour, with beaconing detection, long connection detection, DNS tunnelling detection and threat intel feed checking.
How do I install RITA?
You need Docker Engine with the Compose plugin. Then download the RITA installer tarball for your version from the releases page, uncompress it with tar, and run the install script inside the extracted directory, which lays out the containers, the configuration and the ClickHouse database.
What is the rolling flag for in rita import?
It is for datasets that accumulate data over time, where the logs are less than twenty four hours old, and it is used when the dataset is created and on every later import. The readme warns that importing logs older than a day with the rolling flag may give incorrect results, and that rebuilding a dataset from scratch is done with the rebuild flag.
How do I search RITA results?
With a GitHub-style syntax where each criterion is a field, a colon and a value, separated by spaces, for example src, dst, beacon with a comparison, and a sort field with a column and a direction. The results can be printed as CSV instead of drawn in the terminal by passing the stdout flag to the view command before the dataset name.
Official sources
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.
[](https://hysenlabs.com/projects/activecm-rita)Was this useful?