Automate First, Reason Second: How Claude and I Won the 2026 Huntress CTF

November 2, 2026

We won the 2026 Huntress CTF: AI Arena, out of 1,602 teams, and cleared every challenge (561 of 561).

The challenge-by-challenge writeups are in a public repo: 2026-Huntress-CTF-Writeups on GitHub. This page explains the idea that made the month work: have AI build fast automation for anything repeatable, and keep AI agents on standby for anything that needs reasoning. Automation is faster and costs far fewer tokens. Agents handle the problems the automation can’t read. We used AI in two ways: Claude wrote the automation, building it from each day’s challenge history and from predictions about the next day, and Claude’s agents did the reasoning.

The AI Arena

Every October, Huntress runs a 30-day CTF for Cybersecurity Awareness Month. This year’s event started from a premise most CTFs avoid: frontier models can solve most traditional CTF challenges with ease. Instead of banning AI, Huntress encouraged it and gave players a daily token allotment.

When everyone has AI, having it isn’t the edge. The edge is how you deploy it: AI to build the fast path, and AI to reason where the fast path ends. There’s a time and place for each.

The design: three layers

I was team captain, and I set the strategy and the rules. Claude built the system we played with: the solvers, the opener, the agent definitions, and the guardrails. I directed, reviewed, and decided what it was allowed to do. What we ended up with was a three-layer system.

Layer 0: scheduled jobs and hooks. Scheduled jobs ran every night and every morning to validate that we were ready for the next release. On multiple occasions this layer caught something that would have cost us the morning. It includes one end-to-end check that Claude itself launches and that the whole setup runs, so Layer 0 spends a small number of tokens. The opener in Layer 1 spends none.

The clearest case came after Day 27. A change to one of the automations passed CI and went into the next day’s run. CI didn’t catch the problem. The Day 28 morning preflight did, because it runs the real opener in a test before release. We fixed it before the challenges dropped, and it still cost us about 10 minutes at release. Without that early start, it would have stopped us for over an hour.

Layer 1: an opener that needs no agent. The opener is a launcher plus a library of per-challenge solvers. Layer 0 launched it before each release. At release time it played every lane with solvers Claude and I had already built, and wrote a handoff file per lane. The solvers make no model calls. The opener also ran a small proposer: a Sonnet process at low effort, with no tools, that suggested answer candidates for any question a solver left empty. Those candidates were probed as unsure answers, never submitted as plain ones.

Layer 2: agents already waiting. Before the first handoff file appeared, a set of background agents was loaded from those definitions: seven lane agents, two for the web lane, and a wire agent that watched the server’s contract for changes. They worked only on what Layer 1 couldn’t finish: the day’s new component, or a lane Layer 1 stopped on. A main thread monitored and delegated. It didn’t derive answers.

The agents were organized by role, not by task. Five agent definitions (lane-owner, lane-standby, lane-complex, lane-simple and lane-wire) each had their own model, effort level and permissions. Three skills covered the day’s playbook, the speed run and launch testing. Instead of one long CLAUDE.md, context lived in eight path-scoped rule files that loaded only when an agent touched the matching files. I designed those roles and rules with Claude, and the structure kept every agent’s job narrow.

The files were the interface between the layers. Layer 1 wrote them, and Layer 2 read them. When the automation got stuck, nobody had to notice and start a session. The agent was already there.

Each day had five core lanes (warmups, mobile, script analysis, metadata forensics, binary reverse engineering) plus a live-target web lane from Day 19. Each lane ran in three modes: an untimed base, a Time Trial, and a Mastery.

Time Trial and Mastery windows are seconds long, so no clock was ever started by hand. That alone makes the case for automating them.

The daily loop

The system improved every day because each day ended with the same three steps:

  1. Writeups. Agents wrote up every challenge we solved.
  2. A retroactive review. We reviewed what happened: what the opener closed, what the agents had to pick up, and why.
  3. Prediction analysis. From the history so far, Claude predicted what tomorrow’s challenges might look like, found the shapes we hadn’t built solvers for yet, and built them before the next release.

That loop is why Layer 1 kept closing more ground. Each day’s agent work became tomorrow’s automation, so the agents handled what was new, and the automation handled what we had already seen.

The forecasts were imperfect. Each night, Claude wrote a prediction for the next day’s challenges. From Day 5 to Day 31 we had a forecast for 117 of 148 lane-days (this count includes the web lane). On 38 of them, the forecast was right and the opener closed all three modes with no agent. That’s the conservative number, with six broad forecasts removed. Counting forecasts that got the right family of challenge but not the specifics, it’s 54. Metadata was the hardest lane to predict, with forecast misses on 10 days, and no day had every lane forecast correctly and closed by the opener. These numbers show the forecast and the result together. They don’t prove the forecast caused the result. What the forecasts did was move work from the morning to the night before, when there was time to build it.

How I decided where to use AI

Understanding the when, where, how and why is what separates just solving with AI from solving with minimal token spend, minimal time and maximum results. These are the questions that helped us take first.

The numbers

Layer 1 went live on Day 5, so I’m counting Days 5 through 31: 27 days, 5 core lanes, 135 lane-days.

The opener closed 75 of 135 lane-days (56%) entirely on its own: all three modes, no agent, and no proposer.

By individual mode, it banked 63%:

ModeBanked by the opener
Base70%
Time Trial62%
Mastery56%

By lane:

LaneDays closed fully by the openerModes banked by the opener
Warmups20 of 2770 of 81
Mobile17 of 2758 of 81
Script analysis16 of 2755 of 81
Metadata forensics11 of 2735 of 81
Binary reverse engineering11 of 2736 of 81

On Days 11 and 27, the opener closed all five lanes, every mode, with no agent involved.

How I counted. Each mode is attributed to whoever owned it at the first correct submission, not to the final state. Counting by final state overcounts, because an agent that resumes a lane also ends in “done.” The web lane ran on a separate opener, and I don’t have a comparable figure for it, so it isn’t in these numbers. Days 1 through 4 predate Layer 1 and are excluded.

Why the automation could be trusted

The opener followed one rule that was never relaxed: never guess. A solver answers plainly only for a fact read directly from the bytes, under a name the judge has already accepted. Everything else is an unsure candidate probed off the clock, or nothing. The judge only banks a submission if every answer in it is right, so one wrong answer sinks the batch.

That rule is what let us leave the automation unattended.

Where automation wins

Automation wins wherever a challenge has a known shape. The warmups lane is the clearest case: the opener closed 20 of 27 days there completely. Base mode, the most standard form of each challenge, was banked by the opener 70% of the time.

Where agentic reasoning wins

The data shows where the solvers ran out: the metadata and binary lanes (11 of 27 days each) and Mastery mode (56%). Those are the places where a challenge stops following a known shape and needs a hypothesis.

Day 23 shows both halves, and what goes wrong. The day’s new component was SQLite page geometry, and no solver for it existed yet. The opener banked all five bases in nine seconds and closed the Warmups and Binary Time Trials on its own. Every other timed mode needed an agent to write a reader for the new component during the run, and those closes came anywhere from 15 minutes to nearly five hours after release.

The Metadata Forensics Time Trial was the long one. One answer, the member names inside a nested zip, had to be in sorted order, and it was wrong in every batch. For about 4.7 hours the agents chased more elaborate theories about why the judge was rejecting our answers instead of isolating that single value. The Time Trial closed at 4 hours 52 minutes and the Mastery at 4 hours 56 minutes. The postmortem changed the build: pre-built breadth on every lane, and a format-candidate system that tries several answer formats instead of committing to one.

The pattern: the opener handled what we had already seen, and agents handled what was new.

Why standby agents mattered

Because an agent was already waiting on each lane, an automation failure cost seconds, not a human decision. Layer 1 could be narrow and fast. It didn’t have to be right every time. It only had to know when it was stuck.

Agents were also constrained by design:

It wasn’t perfect, as Day 23 shows.

Token spend

Some players called this year’s event “pay to win.” In my experience it wasn’t. Days 1 through 3 ran on Homebase using Huntress’s token allotment. After Huntress released a way to pair directly with the Game Master, I switched to my local setup on a personal $20/month Claude plan and stayed on it for the rest of the event.

The design did most of the work:

  1. The solvers spent no tokens. 56% of lane-days closed with no agent and no proposer.
  2. Agents ran only when automation couldn’t finish, so tokens went to the work only reasoning could do.
  3. Effort was pinned per role. On Day 5, every session ran at maximum effort, and thinking took 63 to 94 percent of each agent’s time. After that we set effort per agent: medium for most, high for the one agent that builds new readers. The agents ran on Claude Opus 5.5.

The takeaway

There’s a time and place for each. Sometimes asking AI to build you a repeatable automation saves more time and tokens than asking AI to do the job every time. Agents earn their cost on the problems that need reasoning.

What I’d do differently

If this event were played again, I’d spend more time before Day 1 preparing for the challenge areas we hadn’t seen yet, and I’d make the solvers we already had faster and cheaper to run, in both time and tokens. Day 23 is the clearest reason: the lane lost most of a morning because the reader for a new component didn’t exist yet. Layer 1 also went live on Day 5, so the first four days ran without it. I’d build it first.

Disclosure

Claude Code built this setup, working with me. It wrote the opener, the solvers, and the agent definitions, and it ran the lane agents during the event. The solvers make no model calls when they run, but Claude wrote them. My part was direction: the strategy, the rules and limits, reviewing the work, and leading the team. This post is about how to use AI well, not a case for using less of it.

Repository layout

Days 1 through 3 were played on a Homebase VM that has since been shut down, so their working files aren’t on disk. Those writeups rest on later cumulative re-asks that graded correct.

Writeups cover methods and solutions. Flags and credentials are not included.

Thanks

Thank you to my teammates, and to the Huntress team for building and running this event. Congratulations to the other teams at the top of the board.