ai_ctfer

agent
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 7 GitHub stars
Code Pass
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

AI CTFer: A fully automated AI agent for solving CTF challenges.

README.md

AI-CTFer

AI-CTFer solves individual CTF challenges using DeepSeek or OpenAI models
and a Docker sandbox. It supports resumable runs, local memory and knowledge
retrieval, and optional multi-agent collaboration.

Quick Start

Use Python 3.13 or newer with venv support and Bash on a Unix-like host.
The installer creates the project environment; it does not install Python or
Docker Engine. Docker must be available to execute challenge commands.

Install once from this repository's root:

bash scripts/install_cli.sh

The installer reuses or creates the project's shared .venv and adds an
ai-ctfer launcher to ~/.local/bin. No source .venv/bin/activate is needed
when using that launcher. If PATH needs adjusting, the installer prints the
line to use; it does not edit your shell configuration. An existing unrelated
command at the destination is preserved. Use --bin-dir PATH to choose another
installation location, or --python /path/to/python3.13 to select Python when
creating the environment.

Then enter any challenge directory:

cd /path/to/challenge
ai-ctfer i                 # Create challenge.yml if needed, then edit it.
ai-ctfer s                 # Start a new solve in this directory.
ai-ctfer r                 # Resume this challenge's latest run.

Full command names remain available: init, solve, resume, and clean
(short aliases: i, s, r, c). To work from another directory, use
ai-ctfer s /path/to/challenge or ai-ctfer r /path/to/challenge.

To use multiple agents for one challenge:

ai-ctfer s --multi-agent              # Supervisor + up to 2 Solvers + Verifier.
ai-ctfer s --workers 4                # Enable team mode with up to 4 Solvers.
ai-ctfer s --workers 1                # One Solver at a time, with a Verifier.
ai-ctfer r                            # Restores the saved single/team mode.

--workers N also enables team mode; N ranges from 1 to 4. The default
ai-ctfer s keeps the existing single-agent workflow. See
Multi-Agent Collaboration for task isolation,
verification, and recovery behavior.

For a checkout that already has its dependencies in .venv, ./ai-ctfer --help
also works directly from the repository root without installation into PATH.
Developer installation with python -m pip install -e ".[dev]" is still supported.

Set DEEPSEEK_API_KEY for model.name: deepseek, or OPENAI_API_KEY for
model.name: gpt, before solving real challenges.

The normal workflow is to install this CLI once, then run ai-ctfer s
inside a challenge directory containing only that challenge's attachments and
optional challenge.yml.

Minimal challenge.yml:

name: example-challenge
# category options: pwn, rev, crypto, web, forensics, misc, unknown
category: crypto
# Paste statement, flag format, remote endpoints, hints, and notes here.
# Keep description lines indented. ai-ctfer attempts to repair malformed YAML,
# but cannot identify every unindented line that is also valid YAML syntax.
description: |-
  Paste the challenge text here.
  nc example.com 31337
  Flag format: flag{...}

limits:
  max_steps: 50
  command_timeout_sec: 600
  max_output_chars: 50000

model:
  # name options: gpt, deepseek
  # gpt => gpt-6.1-sol with high reasoning
  # deepseek => deepseek-flash
  name: gpt

Put raw connection text directly in description, such as nc example.com 31337, example.com:31337, or an HTTP URL; the agent will parse host, port,
and protocol from context.

Model API Customization

Normal usage only needs model.name: deepseek or model.name: gpt in
challenge.yml.

Verified on 2026-10-21: gpt uses
GPT-6.1 Sol
with high reasoning; deepseek uses deepseek-flash, currently serving
DeepSeek-V4.1-Flash-1017.

To change models, API endpoints, or credentials, edit
model_providers.py:

  • MODEL_PROVIDERS controls which model.name values are accepted.
  • Each provider entry defines aliases, API-key environment variable, base_url,
    API model name, API style, optional reasoning effort, and generated sample
    comments.
  • api_style: "responses" uses client.responses.create(...).
  • api_style: "chat_completions" uses
    client.chat.completions.create(...).

Aliases select a provider entry, not a different API model within it. For
example, deepseek-v4-flash resolves to the deepseek entry's
api_model: deepseek-flash. To select a different API model, change that entry
or add a separate provider entry. Old gpt-5.5, gpt-5.5-xhigh, and
deepseek-v4-pro aliases have been removed; use gpt or deepseek to select
the updated defaults.

For example, the default DeepSeek entry looks like this:

"deepseek": {
    "aliases": ["deepseek", "deepseek-flash", "deepseek-v4-flash"],
    "api_key_env": "DEEPSEEK_API_KEY",
    "base_url": "https://api.deepseek.com",
    "api_model": "deepseek-flash",
    "api_style": "chat_completions",
    "reasoning_effort": None,
    "sample_comment": "deepseek => deepseek-flash",
},

The default OpenAI entry uses the Responses API:

"gpt": {
    "aliases": ["gpt", "openai", "gpt-6.1-sol", "gpt-6.1-sol-high"],
    "api_key_env": "OPENAI_API_KEY",
    "base_url": None,
    "api_model": "gpt-6.1-sol",
    "api_style": "responses",
    "reasoning_effort": "high",
    "sample_comment": "gpt => gpt-6.1-sol with high reasoning",
},

Then use any configured provider without editing schema or solver code:

model:
  name: gpt

Solving and Cleanup

By default, a single-agent solve run starts with an automatic planning phase.
Use --planning-steps 0 to skip it. The agent
may run a few exploratory commands, prints the selected plan, then starts
execution without waiting for confirmation. The plan is also saved as plan.md
in the run directory.

When a challenge is solved, the CLI prints the flag first, then writes
writeup.md and a solve/replay script such as solve.py or solve.sage into
the challenge directory. The writeup includes the elapsed solve time. Their
language follows ai-ctfer language.

Cleanup examples:

ai-ctfer clean .                 # default: --all
ai-ctfer clean . --runs          # only remove .ai-ctfer and ai-ctfer-notes.md
ai-ctfer clean . --image         # only remove ai-ctfer-sandbox:latest
ai-ctfer clean . --docker-cache  # only prune Docker build cache

Cleanup does not remove writeup.md or generated solve scripts in the challenge
directory. --runs removes all saved parent/child runs and memory archives under
.ai-ctfer. --docker-cache runs docker builder prune -f on the current Docker
builder, so it can remove unused build cache from other projects too. Default
clean and --all include this cache cleanup.

Tools and Run State

Agents can run sandbox commands, inspect and edit workspace files, retrieve
saved output, and use memory and knowledge tools automatically.

Runs are saved under <challenge>/.ai-ctfer/runs/<run>/. Inspect plan.md,
state.json, tools.jsonl, and artifacts/ for plans, progress, tool calls,
and output. Team workers keep their own logs and workspaces under
agents/<task-id>/run/. Keep the whole run directory for recovery:
state.json alone is not sufficient.

Memory, Skills, and Cases

Memory and local Skill/Case retrieval are enabled automatically. Read
ai-ctfer-notes.md in the challenge directory for exported notes. Later
single-agent runs reuse matching task memory; changed remote settings mark
remote-dependent observations stale. Recheck remote facts after service resets,
which cannot be detected from an unchanged address.

Team workers keep private memory. Resuming the parent restores it, but a new
team run does not automatically reuse earlier workers' private memory.

Skills provide reusable workflows; Cases provide method examples, not answers
to the current challenge. See the knowledge library guide
to add or maintain either. Successful runs emit case_draft.yaml in the run
directory for manual review; drafts are not automatically published as verified
Cases.

Durable Execution and Resume

Resume the latest run from the challenge directory, or select a challenge:

ai-ctfer r
ai-ctfer r /path/to/challenge

To select an older run, use its path, directory name, or run_id:

ai-ctfer resume /path/to/challenge/.ai-ctfer/runs/20261021_120000
ai-ctfer resume 20261021_120000 --workdir /path/to/challenge
ai-ctfer resume <run_id> --workdir /path/to/challenge

Resume restores the saved model, limits, language, planning settings, and
single/team mode. For teams, resume the parent run; it also restores worker
limits and child progress. Existing workspace edits are preserved, and new
files in the challenge directory are not imported.

The default selects the latest run without falling back to older runs if it
is invalid. Completed runs return saved results without executing tools again,
after checking ownership and saved evidence.

Before continuing an unfinished run, recovery checks the original attachments,
configuration, model settings, and executor identity. Changes can block resume,
including comments or formatting in challenge.yml and changes to a previously
used sandbox image.

Completed tool results are reused. If a tool started but no result was saved,
recovery stops with recovery_blocked rather than repeating an operation with
an unknown outcome. Inspect the saved evidence, workspace, and target before
starting another run; there is no force-replay option. In team mode, remote
command timeouts or executor transport failures also block further remote work,
while independent local work may continue. There is no CLI command to clear
that remote block.

Recovery restores saved progress, not live TCP connections, background
processes, or container state. Each command uses a temporary Docker container;
an abrupt host-process exit can leave a container that needs manual cleanup.

Multi-Agent Collaboration

Enable team mode with ai-ctfer s --multi-agent or ai-ctfer s --workers N.
A Supervisor assigns subproblems to isolated Solvers, merges their findings,
and asks an independent Verifier to check candidate solutions.

Option or setting Single-agent mode Team mode
--workers N Omit for single-agent mode. Enables team mode; 1–4 concurrent Solvers, default 2 with --multi-agent.
--max-steps / limits.max_steps Solving step budget. Supervisor decision budget; subtasks have separate budgets.
--planning-steps Initial planning budget. No separate planning phase; the Supervisor maintains the plan.
--model / model.name Solver model configuration. Same model configuration for all roles.
ai-ctfer r Resume the saved run. Resume the parent and its children; no team flag needed.

--workers counts Solvers only. Solver subtasks default to 12 steps and a
300-second soft deadline per execution attempt, assigned by the Supervisor.
Deadlines do not forcibly terminate an in-flight model request. Cancellation
is cooperative; there are no standalone CLI pause or cancel commands.

Each worker has its own workspace, logs, and checkpoint. Progress labels such
as [solver:factor-a] and [verifier:verify-2] identify concurrent output.
Completed child work is reused on resume; failed tasks can receive follow-up
assignments.

Local investigations can run in parallel with networking disabled. Remote
tasks run exclusively within the same parent run; separate CLI invocations do
not share that coordination. Agents cannot share live processes or persistent
TCP sessions.

A team publishes a flag only after an independent Verifier reports support
with its own command evidence and the host's evidence checks pass. The model
still interprets what the check proves; this does not guarantee acceptance by
a competition platform.

On success, the CLI exports the selected solution and writeup. Team script
export selects solve.py, solve.sage, or exploit.py from the chosen worker's
workspace root. Other entry-point names, nested scripts, and helper dependencies
are not automatically exported. Keep agents/<task-id>/run/work/ when the
solution depends on those files. If no eligible script exists, the fallback
only preserves the result and is labelled accordingly.

Docker

Challenge shell commands run through Docker. Install Docker Engine using the
official instructions for your platform.
This repository does not include a Docker Engine installation script.

After installing Docker, check CLI dependencies, credentials, and Docker daemon
access:

ai-ctfer doctor --strict

doctor does not build the sandbox image, run a container, or call the model.
Its strict mode also requires at least one configured provider's API-key
environment variable to be set; that does not validate the key or guarantee it
belongs to the provider selected for a particular challenge. To exercise the
sandbox without an API key, use ai-ctfer smoke --fake-llm after Docker is ready.

Single-agent commands have network access enabled for both remote and
no-remote challenges. In team mode, subtasks declared local use Docker's
network-disabled mode; remote subtasks retain network access and are serialized.
For RSA triage it includes rsa_factordb, a small helper that queries FactorDB
and decrypts when n, e, and c are available.

Offline Tests

Install the test dependencies once from the repository root; the normal CLI
installer does not include pytest:

.venv/bin/python -m pip install -e ".[dev]"

Then run the offline regression suite:

PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 \
AI_CTFER_CONFIG_DIR="$PWD/.pytest-tmp-config" \
.venv/bin/python -m pytest tests --basetemp=.pytest-tmp-tests -q

The suite uses simulated models/executors and local fixtures; it does not
require API keys or Docker.

Smoke Tests

After Docker is available, run a free fake-LLM smoke test:

ai-ctfer smoke --fake-llm

To exercise a real model and the sandbox on the generated smoke challenge:

ai-ctfer smoke --real-llm

Smoke tests create a temporary challenge and do not read the current directory's
challenge.yml. Real smoke uses DEFAULT_MODEL_PROVIDER from
model_providers.py (currently gpt, requiring OPENAI_API_KEY); the smoke
command has no --model option.

These smoke commands check the single-agent sandbox/model path.

Q&A

Why does Docker say permission denied?

ai-ctfer uses the current user to run Docker. It does not use sudo or do
any privilege escalation internally. If this fails:

docker run --rm hello-world

then Docker-backed commands will fail too, including:

  • ai-ctfer solve .
  • ai-ctfer smoke --fake-llm
  • ai-ctfer clean . --image
  • ai-ctfer clean . --docker-cache
  • ai-ctfer clean . --all

Local cleanup still works without Docker permission:

ai-ctfer clean . --runs

The usual fix is to add your user to the docker group:

sudo usermod -aG docker "$USER"
newgrp docker
docker run --rm hello-world

If newgrp docker does not refresh the session cleanly, log out and log back
in, then rerun:

ai-ctfer doctor --strict

Running sudo ai-ctfer solve . can work, but it is not recommended because
generated files may become owned by root.

Why does clean fail with unable to delete ai-ctfer-sandbox:latest?

This means Docker still has a container that references the sandbox image. The
container may be stopped, but Docker still keeps the image locked until that
container is removed.

Check which containers are using the image:

docker ps -a --filter ancestor=ai-ctfer-sandbox:latest

If the listed containers are old ai-ctfer sandbox containers and you do not
need them anymore, remove them and rerun image cleanup:

docker rm -f <container-id>
ai-ctfer clean . --image

For a one-shot cleanup of all containers based on this image:

docker ps -aq --filter ancestor=ai-ctfer-sandbox:latest | xargs -r docker rm -f
ai-ctfer clean . --image

When using default clean, --all, or explicitly combining --runs with
--image, local run cleanup happens before image removal. An image-removal
error does not undo that cleanup. With --image alone, run logs and
ai-ctfer-notes.md are left in place.

Reviews (0)

No results found