Install and scan something
Install the binary, fetch templates, and read a real finding on a target you control.
Cert-X-Gen is a security scanner that keeps the evidence behind every finding. Start a target you control, scan it, and read what it saw:
mkdir -p cxg-demo/data && cd cxg-demoecho 'customer-export.csv placeholder' > data/customer-export.csvpython3 -m http.server 8899 --bind 127.0.0.1# in a second terminalcxg scan --scope http://127.0.0.1:8899 --templates directory-listing-common-pathsFindings by Severity: CRITICAL: 0 HIGH: 0 MEDIUM: 1 LOW: 0 INFO: 0
TOTAL: 1Truncated to the severity block. The run also prints a scan id, a duration, and the target and template counts.
MEDIUM: 1 is the finding. scan-results.json is why you can act on it: it
holds the request that triggered the finding, the whole response body cxg matched
against, and which conditions fired.
{ "severity": "medium", "confidence": 85, "title": "Directory Listing Exposure (Common Paths)", "evidence": { "request": "GET http://127.0.0.1:8899/data/\n", "response": "<!DOCTYPE HTML>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Directory listing for /data/</title>\n</head>\n<body>\n<h1>Directory listing for /data/</h1>\n<hr>\n<ul>\n<li><a href=\"customer-export.csv\">customer-export.csv</a></li>\n</ul>\n<hr>\n</body>\n</html>\n", "matched_patterns": [ "status:200", "Directory listing for" ],Keeping the whole response body is what makes a finding auditable weeks later. You read what the scanner saw, rather than trusting that it matched something.
Read your first scan runs the scan above and reads back every part of it. Each finding carries these fields:
| Field | What it holds |
|---|---|
severity, confidence |
How serious the template’s author judged it, and how sure the check is |
title, description |
What was found, in the template author’s words |
evidence.request |
The exact request that triggered it |
evidence.response |
The full response body cxg matched against |
evidence.matched_patterns |
Which conditions fired |
cwe_ids, cve_ids, cvss_score |
Set when the template provides them |
remediation |
How to fix it, when the template says |
Results go to scan-results.json by default, and one run can write JSON, SARIF,
CSV, HTML, and Markdown at the same time, so the same scan feeds a pipeline and a
person.
Most checks are straightforward: send a request, look for something in the response. YAML describes those well, and a YAML template stays readable to anyone on your team.
Some checks need to do more than match text. Cert-X-Gen lets a template be an ordinary program instead. A template written as a program can:
Take an exposed .git directory. A template can fetch /.git/HEAD, read which
branch it points at, fetch that branch, and check that it resolves to a real
commit. Three requests, each one deciding the next. If any step fails the
template stays quiet, so what you get is a confirmed finding rather than a maybe.
Write your first template builds that check step by step, and why polyglot templates covers when the extra power is worth its cost, because a code template needs its language installed wherever the scan runs.
Cert-X-Gen runs two pipelines. They start from different things, so the one you reach for depends on what you already have.
flowchart TB
subgraph SCAN["cxg scan"]
direction LR
A["a target you can reach"] --> C(["run every template<br/>that applies"])
B["templates"] --> C
C --> D["findings, each with the<br/>request and response"]
end
subgraph PENTEST["cxg pentest"]
direction LR
E["a running app"] --> G(["write probes,<br/>then try to confirm them"])
F["its source, and a guardlink<br/>threat model"] --> G
G --> H["a verdict for each<br/>suspected exposure"]
end
SCAN ~~~ PENTEST
class D,H emphasis
| What you are doing | Reach for | Why |
|---|---|---|
| Sweeping web applications and services for known issues | cxg scan |
Select templates by tag, severity, or exact ID |
| Scanning hosts and networks | cxg scan |
--scope takes hosts, domains, URLs, and CIDR ranges |
| Testing an application whose source you have | cxg pentest |
Starts from exposures a developer marked in the code, not from guesswork |
| Testing an Electron desktop app | cxg pentest --target-type electron |
Drives the app over the Chrome DevTools Protocol and probes its IPC channels |
| Confirming blind SSRF or injection | --oast-interactsh |
cxg owns the callback host and polls it, so a hit is proof rather than a lead |
| Gating a build | Exit codes and --ci |
An expired session fails the job loudly instead of scanning logged out |
| Writing a check nothing else can express | cxg template |
The check is a program, so it can parse, compute, and chain requests |
Desktop application support means Electron, only under cxg pentest, and
never under cxg scan. --target-type takes web and electron and nothing
else; Tauri is not supported, because it exposes no CDP endpoint on macOS or
Linux.
Three things surprise people. Each one is covered in full elsewhere.
Install and scan something
Install the binary, fetch templates, and read a real finding on a target you control.
Write a check in code
Build the .git detection above in Python, validate it, and run it through
the engine.
Run a whitebox pentest
Turn a guardlink threat model into probes, and let cxg try to confirm or rule out each one against a running app.
Look up a flag
Every command, flag, and default, generated from the binary’s own --help.
See what it can find
Every shipped check, by category, severity, target kind, or the weakness it looks for, with the long-form case behind the differentiated ones.
Send a check back
The template corpus is open source and takes contributions. See what it asks of a check, and why the bar sits there.
These docs describe Cert-X-Gen 1.3.0, released 2026-08-13. The generated
reference comes from that release’s published binary, which is the same asset the
install steps download. The release binary, cargo install cert-x-gen, the
Homebrew tap, the install script, and the Docker image all serve 1.3.0.