Authors: Yun Zheng Hu
Introduction
Today Fox-IT is publicly releasing its full Cobalt Strike Beacon Corpus, containing 56,843 raw beacons and their parsed configurations, from 190,182 sightings collected from 30,604 unique IP addresses running a Team Server (the Cobalt Strike command-and-control server that beacons connect back to) between 4 July 2018 and 29 September 2026, over eight years of beacon data. The corpus is available on Hugging Face: https://huggingface.co/datasets/fox-srt/cobaltstrike-beacon-corpus
Back in March 2022 we published Mining Data from Cobalt Strike Beacons. That post covered 128,340 beacon sightings collected from July 2018 to February 2022, and it introduced our Python project dissect.cobaltstrike for parsing them.
Since then, public scanning for Team Servers has become routine, and Cobalt Strike has shipped versions 4.6 through 4.13. Researchers have regularly asked us for an updated dataset. And here it is, a large, consistent, long-running dataset for the infosec community to build on. The corpus includes the raw beacon payloads, not just our parsed output, so anyone can reproduce our results or improve on them.
We also see publishing this corpus as an act of preservation. C2 infrastructure is short-lived, as the median Team Server is reachable for just 14 days, and the beacons it serves vanish with it. Eight years of collection captures things that can no longer be observed today, like the waves of cracked 4.0 builds or the adoption of leaked versions. By publishing the raw beacons alongside the parsed data, we keep that record available for anyone to study, long after the servers themselves are gone.
What’s in the corpus
The corpus is published on Hugging Face as two Parquet files:
| File | Size | Rows | Contents |
|---|---|---|---|
| beacons.parquet | 52 MB | 190,182 | Every sighting of a beacon, with collection metadata, network context and the parsed beacon configuration. |
| payloads.parquet | 9.7 GB | 56,843 | The raw beacon payloads, wrapped in CaRT as an extra safety layer so the samples are neutered until you deliberately unpack them. |
All beacons were downloaded directly from internet-facing Team Servers, mostly on TCP ports 80 and 443 (HTTP and HTTPS) and UDP port 53 (DNS), with a small number on other ports. We deliberately didn’t include samples from other sources such as VirusTotal, so the corpus reflects the Cobalt Strike landscape as it was visible on the internet.
How we collected it
The collection method matches our 2022 post. We fingerprint likely Team Servers on the internet, then request a beacon payload from each one using a URI that passes Cobalt Strike’s checksum8 check. Every beacon that comes back is parsed with dissect.cobaltstrike, which decodes the configuration block. The result is stored as a sighting.
- Discovery: candidate hosts from our own internet-wide scanning. As in 2022, we’re keeping our fingerprints private so they stay effective; writing your own is left as an exercise for the reader.
- Download: x86 beacons over HTTP(S) and DNS.
- DNS: for DNS listeners we’re not publishing that fingerprint either, but it’s not rocket science. The beacon is fetched as a series of TXT record lookups sent over UDP port 53 directly to the Team Server’s DNS listener.
- Parse: Use
dissect.cobaltstriketo parse the beacon and export the configuration - Enrich: TLS certificate data captured at collection time (where available) and GeoIP/ASN via historical GeoIP databases.
Note that there might be some small gaps in the collection due to automation issues that we did not catch in time.
Getting started
Most research only needs the beacons.parquet dataset. The payloads.parquet dataset containing raw beacon payloads is only required if you want to re-parse the beacons or look into the ones that failed parsing.
I’m a big fan of DuckDB (and SQLite), and over time I’ve become fond of SQL for querying data as well. DuckDB is very fast, and AI assistants are very good at writing SQL queries. These days, that beats hand-writing pandas code and the matching matplotlib charts. That’s why I recommend exploring the data with DuckDB, for example in a Jupyter notebook.
An example of using DuckDB to query the dataset on Hugging Face directly:
SELECT watermark,
count(*) AS sightings,
count(DISTINCT collected_from_ip) AS servers,
min(collected_on) AS first_seen,
max(collected_on) AS last_seen
FROM 'hf://datasets/fox-srt/cobaltstrike-beacon-corpus/data/beacons.parquet'
GROUP BY watermark
ORDER BY sightings DESC
LIMIT 20;

Take a look at our Jupyter notebook in the Hugging Face repository as a starting point. It contains every query and chart from the sections below, so you can rerun them or adapt them to your own research questions.
A first look at the data
Here are a few quick results to show what the corpus can answer. They’re a starting point, not a full analysis. As with our 2022 post, we invite researchers to explore the data; see also “Research ideas” below.
Old versions never die

Each Cobalt Strike release takes over from the last, but old versions linger. Cobalt Strike 4.0 dominated most of 2020, 4.1–4.2 drove the early 2021 peak of about 3,000 beacons a month, 4.3–4.4 led from mid-2021 through 2022, and 4.5–4.8 took over in 2023. Since 2024, 4.9 and 4.5–4.8 have shared the lead, while 4.10+ remains a small share. Volume has since dropped to around 200 beacons a month, partly because fewer servers stage their beacon, which brings us to the next graph.
No beacon for you

Our collection relies on beacon staging, meaning a Team Server can serve its beacon as a downloadable payload to anyone who requests the right URI or DNS record. Operators can turn this off (the host_stage option in the Malleable C2 profile), and disabling it is common OPSEC advice. To measure how much this affects our beacon collection, we counted two numbers per month:
- The unique Team Servers (ip:port) confirmed by our high-confidence HTTP fingerprint
- The unique Team Servers (ip:port) that handed out a beacon over HTTP(S)
These are monthly totals, not a server-by-server match. On average, the Team Servers that handed out a beacon were only about 32% of those we fingerprinted, and that share has drifted down from around 40% in 2023 to 20–25% in 2026. In other words, because not every server hands out a beacon, the corpus shows only part of the Cobalt Strike landscape, and that part is getting smaller. Disabled beacon staging is the most likely reason, but not the only one. Servers can go offline between fingerprinting and download or block our scanners, and our fingerprint doesn’t catch every Team Server.
The dashed sections mark months when beacon collection wasn’t running, because of an automation error that went unnoticed for a while.
The short life of a Cobalt Strike Team Server

The median Team Server was reachable for 14 days. 35% were seen on a single day only, just 14% were still serving a beacon after three months, and only 2% after a year.
We identify a Team Server by its public key and C2 domains from the beacon configuration (or its IP address when the configuration contains no domains), so a server that moves to a new IP is still counted once. This allows us to measure how long a Team Server typically stays online. Identifying servers by public key alone or by ip:port gives almost the same result, a median lifetime of 14–15 days. These are first-to-last-sighting spans, so a server may have been online before our first and after our last sighting. Servers still active in the last 30 days are left out.
It’s always DNS

Most public scanning focuses only on HTTP(S) beacons, but we’ve also collected DNS beacons since 2020 (apart from the months when our automation broke). DNS beacons have declined much less steeply than HTTP(S) ones, perhaps because they get far less attention in public research and OPSEC advice, so fewer operators think to lock them down. After a peak in 2022, they have mostly hovered around 100 a month since 2024, with a median of 120 over the whole period.
Parse me if you can
The corpus also includes 128 unique beacons (0.23%) that we downloaded but couldn’t parse. Note that the corpus doesn’t contain HTML pages or other responses that were unlikely to be a beacon. We excluded those before publishing. At first glance, most are beacons with custom modifications that dissect.cobaltstrike can’t parse yet. And some payloads from the early years aren’t Cobalt Strike at all, but Metasploit Meterpreter payloads. We’ve deliberately left them in for researchers to analyse. You can find all unparsed beacons with: WHERE config_json IS NULL
The unparsed count used to be higher, but we managed to bring that down. We noticed some operators customised their beacon configs, for example by shuffling the order of the configuration settings or changing their type values, which broke our parser (and probably most others). The corpus helped us find these cases, so we made the config scanning of dissect.cobaltstrike independent of layout and added many other features and fixes along the way. See the dissect.cobaltstrike v1.3.0 release notes.
Research ideas
Some other research questions that could be answered using the corpus:
- Clustering: Group operators by config features (watermark, SPAWNTO/PROCINJ hash, C2 profile, certificate, sleep/jitter, specific beacon modifications)
- Classification: Separate red team from criminal infrastructure. Build and publish labelled subsets.
- Infrastructure: Top hosting providers that are hosting a Cobalt Strike Team Server.
- Certificates: Pivot on x509 reuse across servers and time or find how many are running the default Cobalt Strike keystore certificate.
- Benchmarks: Use the corpus as a shared test set for config extractors and ML models.
- Parser failures: 128 beacons can’t be parsed by
dissect.cobaltstrike. Figure out why.
Over to you
Eight years of Cobalt Strike beacons are now one download away on Hugging Face. Run your own queries, pick up one of the research ideas above or come up with your own, dig into the beacons we couldn’t parse, and share what you find.
Before you start, read the Limitations section on the dataset card. The raw payloads are real Cobalt Strike beacons, so handle them like any other malware sample.