ARTEX: a self-hosted AI penetration testing system in Go
AI 自主渗透测试系统 | 百度“agent+”攻防挑战赛冠军项目
At a glance
- What is it?
- ARTEX wraps LLM agents around a PostgreSQL-backed asset graph and a human approval gate, shipping as a single Go binary or a Docker Compose stack. It is a serious tool for authorized red-team work, and its review model has limits worth knowing before you point it at anything.
- Who is it for?
- Adopt ARTEX if you run authorized engagements against scoped assets, want the agent's tool calls gated by a human approval queue, and are willing to run PostgreSQL and keep a start.sh daemon alive. Do not adopt it if you need unattended scanning of third-party systems, if you cannot supply an LLM key, or if you expect the review model to reason about an agent's history: the README states history is deliberately withheld.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 19, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What ARTEX is and who it is built for
ARTEX is described in its README as an AI autonomous penetration testing system with a Go backend and a Next.js frontend. The repository is Autumn-27/ARTEX, the primary language is Go, and the module path in go.mod is github.com/Autumn-27/artex. The project's own description calls it the winning entry of Baidu's "agent+" attack and defense challenge, which tells you the intended audience: security engineers who already understand recon workflows and want an agent to drive them.
The system is not a scanner you point at a host and forget. It maintains an asset graph, runs exploration tasks against assets in that graph, records findings, and routes tool calls through an approval layer. The screenshots listed in the README cover a dashboard with token consumption and an activity stream, a task list, per-task execution sessions showing tool calls, an exploration graph, findings, assets, a force-directed asset coverage map, traffic recording, a human-in-the-loop chat, agent management, LLM configuration, an intercept approval queue, and backend logs. That is the shape of an operations console, not a CLI wrapper.
The audience follows from that layout. If you are running authorized engagements and want a persistent record of what an agent did, which asset it touched, and who approved the call, ARTEX is aimed at you. If you want a one-shot vulnerability scan, the surrounding machinery is overhead.
How the agent loop, asset graph and approval queue fit together
The architecture visible from the repository layout splits into a Go server (server/, cmd/, agent/, guard/, intercept/, llmpool/, report/, traffic/, selfupdate/) and a Next.js frontend under web/. The agent depends on github.com/Autumn-27/norma v0.4.0, referred to in the README as the Norma SDK, and the approval hook that ARTEX uses comes from that SDK.
Data flows through PostgreSQL. The docker-compose.yml sets ARTEX_PG_DSN to a postgres:// URL against the postgres:16-alpine service, and the README states that artex re-runs schema.sql idempotently on every start, with ADD COLUMN and CREATE INDEX IF NOT EXISTS statements, so migrations happen on restart rather than through a separate migration command. A separate SQLite dependency (modernc.org/sqlite) appears in go.mod, and the README mentions SQLite files living under ./data alongside jwt.key.
Assets can be imported rather than collected from scratch. The README documents an asset sync page that pulls from ScopeSentry, another project by the same author, letting you select targets and asset types (domain, subdomain, IP, port, site, endpoint) by project or task, then merge them into ARTEX's asset graph. For teams already running ScopeSentry, that removes a duplicate collection step.
The approval layer is the interesting part. When a tool call enters scope and does not match an existing rule, it can be sent to a model for review. The README is explicit about what that review model receives: a version 4 JSON payload with the working directory, a short background, the full tool name and JSON parameters including the interactive shell session ID. It does not receive historical commands, historical execution results, historical approval reasons, or call correlation markers. Background is capped at 4,000 bytes and truncated with a marker; current call parameters are not truncated. The model returns JSON with decision (allow, ask, deny) and comment, and all three decisions must explain the actual operation, the consequence of success, and the rule that matched. Malformed or incomplete JSON falls through to the configured model failure policy.
That design is a deliberate trade-off. Withholding history keeps the review payload small and prevents an agent from laundering intent through its own prior messages. It also means the reviewer cannot tell whether a write is creating a new object or overwriting one, which the README acknowledges: when ownership cannot be determined from current parameters, the review policy decides, and the background's own claims are not treated as proof.
Installing ARTEX and running a first task
The README documents five installation paths. The recommended one is the install script, which detects or installs Docker and then offers a choice between an all-Docker deployment and a locally compiled run.
git clone https://github.com/Autumn-27/ARTEX.git
cd ARTEX
./install.shIn the all-Docker path the script asks for a Postgres password (pressing enter generates a random one), writes .env, and runs docker compose up -d. In the local path it asks which database to use, generates config.json, compiles a single binary with the frontend embedded, and starts it. Either way the UI comes up on http://localhost:8787, and the first visit routes to /setup where you set the administrator password.
If you prefer the manual Compose route, the README gives this sequence. Note that POSTGRES_PASSWORD is required by docker-compose.yml, which uses the ${POSTGRES_PASSWORD:?} form to fail fast when it is missing.
git clone https://github.com/Autumn-27/ARTEX.git
cd ARTEX
cp .env.example .env
# fill POSTGRES_PASSWORD, optionally ANTHROPIC_API_KEY
docker compose up -dThe image autumn27/artex ships with ripgrep, curl, vim, npm, nmap and a preinstalled Playwright MCP and Chromium, so the container can drive a browser without downloading it at first run. The ./skills and ./data directories are bind-mounted, which means edits to skills take effect without rebuilding the image and data survives container recreation.
Exploration needs an LLM. The README says to set ANTHROPIC_API_KEY or OPENAI_API_KEY, or configure the provider in the UI. The .env.example also exposes ARTEX_LLM_PROVIDER, ARTEX_LLM_MODEL, ARTEX_LLM_BASE_URL and ARTEX_LLM_PROXY if you are pointing at a non-default endpoint.
One operational detail deserves attention before you start. The README warns against running ./artex directly and says to use start.sh or start.bat instead. The script is a supervisor: it decides whether to relaunch the process based on its exit code, and the in-page one-click update depends on it to swap binaries. Running the binary directly means an update leaves you with no process. For a background deployment the README suggests nohup ./start.sh >artex.log 2>&1 &.
Where the review model and the approval hook break down
Two limitations are stated outright in the README, and both matter in practice.
The first concerns call correlation. The README says the current Norma SDK approval hook does not include a call ID, so ARTEX can only associate a result with a request when it can uniquely match the tool request event within the current run. Concurrent calls with identical parameters cannot be uniquely matched, and in that case the record shows as unassociated rather than being attributed to the wrong call. That is the correct failure mode, but it means an audited approval record can legitimately lack its execution result. If your workflow depends on a complete request-to-result chain, parallel calls with the same arguments will produce gaps.
The second concerns what the reviewer can know. Because history is withheld, the model judges each call on its current parameters and a bounded background. The README states that object ownership cannot be inferred from self-reported background, and that ordinary read-only actions are not escalated to a human merely because history is absent. So the approval gate is not a general-purpose safety net. It is a per-call policy check, and any decision that genuinely requires remembering earlier actions is outside what it can do.
There is also a scope boundary. The README says official default rules, tool interception scope and priority are unchanged, and only calls that are in scope and unmatched by rules reach an enabled model review. If the model is not enabled, the previous behavior applies. So enabling the model review widens coverage, but the underlying scope rules still decide what is seen at all.
Finally, the backup story deserves a caveat. Upgrades preserve the pgdata volume, ./data and ./skills, and the README says database migrations need no manual step. But it also notes that the database schema does not roll back, so reverting to artex.old returns the binary, not the schema.
ARTEX compared with a plain LLM agent plus shell access
The obvious alternative is what most teams start with: give a general-purpose coding agent a shell, a list of targets, and a prompt. That approach has real advantages. There is nothing to deploy, no PostgreSQL to run, no asset graph to populate, and no approval queue to configure. For a one-off engagement against a handful of hosts, the setup cost of ARTEX is hard to justify.
The difference in approach is where state lives. A plain agent keeps context in the conversation window; when the window fills or the session ends, the exploration history goes with it. ARTEX persists assets in PostgreSQL, records findings, and stores approval decisions with the model input and its fingerprint. The README notes that details for all model decisions, including automatic allows, are saved with the actual JSON submitted and its fingerprint, and that older v1/v2/v3 snapshots keep the fields sent at the time and are labeled as legacy. A record that only has a fingerprint is explicitly flagged as unrecoverable rather than reconstructed from current data.
That persistence is the reason to choose ARTEX over a bare agent, and it is also the reason the approval queue exists. A bare agent with shell access has no interception layer at all: the model decides and the command runs. ARTEX inserts a rule check and an optional model review before execution, with a human decision available for the ask path. Whether that gate is worth the deployment complexity depends on whether you need to show someone, later, what was approved and on what basis.
A second practical difference is the toolchain. The Docker image preinstalls nmap, dnsutils, netcat, whois, telnet, Playwright MCP and Chromium. A bare agent needs those installed and maintained in whatever environment it runs in.
Upgrades, licence status and what the one-click update actually does
The README documents three upgrade paths. The in-page one, from the version and update card at /system/settings, downloads the current platform's release package, compares it against the release's SHA256SUMS, runs a -h smoke test on the new binary, stages it as artex.new, exits, and lets start.sh or start.bat relaunch and complete the swap. If checksum or smoke validation fails, the staged file is discarded and the current version keeps running. If the new version fails to start three times in a row, it rolls back to artex.old automatically, leaving the failed binary as artex.failed for inspection.
Two constraints on that mechanism are stated plainly. Development builds do not get updates: when the version is dev or a git describe string with a suffix, the update is disabled so a release cannot overwrite a locally built binary. And under Docker, the update swaps only the program, not the image, so the Playwright and nmap toolchain inside the image does not move, and docker compose up -d rebuilds the container back to the image's bundled version. Upgrading the image itself still requires docker compose pull artex && docker compose up -d artex. If GitHub access needs a proxy, the same settings page has a global proxy that the update path uses, and the README says updates download only from GitHub domains over enforced HTTPS.
The update interrupts running tasks, since it restarts the process. The README says to do it when idle.
On licensing, the repository metadata I have does not include a licence identifier, and the README does not state one. The go.mod file lists dependencies under their own licences, including pgx, jwt, dnsx, go-mitmproxy, modernc.org/sqlite and the Norma SDK. Because no project licence is declared in what I can see, you should confirm the terms in the repository before deploying ARTEX commercially or redistributing the binary. That is a factual gap, not a legal opinion, and it is worth resolving early if the deployment is for a client.
Editorial conclusion
Adopt ARTEX if you run authorized engagements against scoped assets, want the agent's tool calls gated by a human approval queue, and are willing to run PostgreSQL and keep a start.sh daemon alive. Do not adopt it if you need unattended scanning of third-party systems, if you cannot supply an LLM key, or if you expect the review model to reason about an agent's history: the README states history is deliberately withheld. Before trusting it, verify three things in your own environment: that the asset sync from ScopeSentry lands in the graph you expect, that the approval hook actually matches call IDs on your Norma SDK version, and that a rollback after a bad update leaves your database intact.
Frequently asked questions
What is ARTEX?
ARTEX is an AI autonomous penetration testing system with a Go backend and a Next.js frontend, described in its README as the winning entry of Baidu's agent+ attack and defense challenge. It maintains an asset graph in PostgreSQL, runs exploration tasks against those assets, and routes tool calls through a rule check and an optional model review before execution.
How do I install ARTEX?
The README recommends cloning the repository and running ./install.sh, which detects or installs Docker and lets you choose an all-Docker or locally compiled deployment. Alternatively you can copy .env.example to .env, set POSTGRES_PASSWORD, and run docker compose up -d, which serves the UI on http://localhost:8787.
Does ARTEX need an LLM API key to work?
Exploration requires an LLM, and the README says to configure ANTHROPIC_API_KEY or OPENAI_API_KEY, either in the environment or in the UI. The .env.example also exposes ARTEX_LLM_PROVIDER, ARTEX_LLM_MODEL, ARTEX_LLM_BASE_URL and ARTEX_LLM_PROXY for pointing at a different endpoint.
Can ARTEX review an agent's previous commands when deciding on an approval?
No. The README states the review model receives only the current call's parameters, the working directory, and a background capped at 4,000 bytes, and that historical commands, execution results and approval reasons are not sent. Object ownership cannot be inferred from the background's own claims.
What happens if an ARTEX update fails partway through?
The README says a failed checksum or smoke test causes the staged artex.new file to be discarded and the current version to keep running, and that a new version failing to start three consecutive times rolls back to artex.old. The database schema is not rolled back when you revert the binary.
Community notes