Skip to content

YAML template schema

Applies to .yaml and .yml templates only. cxg deserializes the document with serde. It does not read comments, so an @id: annotation header in a YAML file does nothing — see Annotation header schema.

Metadata keys sit at the root of the document, beside the request sections.

Key Type Required Absent →
id string yes
name string yes
author author object yes
severity severity yes
description string yes
cve_ids list of string no empty list
cwe_ids list of string no empty list
cvss_score number no unset
tags list of string no empty list
language language yes
file_path string (path) no empty string
created string (RFC 3339 timestamp) no Utc::now at load time
updated string (RFC 3339 timestamp) no Utc::now at load time
version string no 1.0
confidence integer no unset
context_vars list of string no empty list
vuln_class string no unset
hypothesis_tags list of string no empty list
batch_group string no unset
auto_probe boolean no false
http list of http entry no unset
network list of network entry no unset
matchers list of matcher no unset
matchers-condition and / or no unset
flows list of flow no unset

Loaded by the pinned binary, from a template carrying keys this schema does not define:

Terminal window
$ cxg --disable-update-check --no-color template info schema-fixture-unknown-keys
[INF] Auto-update checks disabled
╔════════════════════════════════════════════════════════════════╗
║ Template Information ║
╚════════════════════════════════════════════════════════════════╝
ID: schema-fixture-unknown-keys
Name: Schema fixture
Language: Yaml
Severity: Info
Author: docs.bugb.io generator
Description: Carries keys this schema does not define, and an annotation header.

The template does not load, and at default verbosity nothing says so — it is absent from the library and from every scan. -v reports the reason.

Loaded by the pinned binary, from one fixture per required key — each omitting exactly that key — plus the malformed fixtures the sections below refer to:

Terminal window
$ cxg --disable-update-check --no-color -v template list
INFO cert_x_gen::template::manager: Discovered 11 templates
WARN cert_x_gen::template::engine: Failed to load template ./templates/author-as-string.yaml: YAML parse error: invalid type: string "docs.bugb.io generator", expected struct AuthorInfo
WARN cert_x_gen::template::engine: Failed to load template ./templates/missing-author.yaml: YAML parse error: missing field `author`
WARN cert_x_gen::template::engine: Failed to load template ./templates/missing-description.yaml: YAML parse error: missing field `description`
WARN cert_x_gen::template::engine: Failed to load template ./templates/missing-id.yaml: YAML parse error: missing field `id`
WARN cert_x_gen::template::engine: Failed to load template ./templates/missing-language.yaml: YAML parse error: missing field `language`
WARN cert_x_gen::template::engine: Failed to load template ./templates/missing-name.yaml: YAML parse error: missing field `name`
WARN cert_x_gen::template::engine: Failed to load template ./templates/missing-severity.yaml: YAML parse error: missing field `severity`
WARN cert_x_gen::template::engine: Failed to load template ./templates/time-as-scalar.yaml: YAML parse error: http[0].matchers: invalid type: integer `5`, expected struct Duration at line 11 column 7
WARN cert_x_gen::template::engine: Failed to load template ./templates/unknown-matcher-type.yaml: YAML parse error: http[0].matchers[0].type: unknown variant `dsl`, expected one of `status`, `word`, `regex`, `binary`, `time`, `size`, `hash`, `tls`, `dns`, `diff`, `custom` at line 11 column 15
WARN cert_x_gen::template::engine: Failed to load template ./templates/unknown-severity.yaml: YAML parse error: unknown variant `catastrophic`, expected one of `info`, `low`, `medium`, `high`, `critical`
INFO cert_x_gen::core: Loaded 1 templates from ./templates

Those are the loader’s own lines out of a longer output — template list also prints every template that did load. Each Failed to load line is serde’s error for one fixture. Three things are done to those lines and nothing else: the timestamp and thread id that prefix each one are removed, the failures are sorted by filename, and the lines about the unrelated template directory under $HOME are left out.

Asking for a template that failed to load says only that it does not exist:

Terminal window
$ cxg --disable-update-check --no-color template info schema-fixture-missing-author
[INF] Auto-update checks disabled
❌ No template found matching: schema-fixture-missing-author
Try: cxg search --query "schema-fixture-missing-author"

author is an object, not a string:

author:
name: CERT-X-GEN Security Team
email: security@example.com
Key Type Required
name string yes
email string no
github string no

author: Some Name is the most common way a template written for another scanner stops loading here, and the loader says so only under -v:

Failed to load template ./templates/author-as-string.yaml: YAML parse error: invalid type: string "docs.bugb.io generator", expected struct AuthorInfo

One of info, low, medium, high, critical.

Unlike the annotation header — where an unrecognised severity silently becomes Medium — an unrecognised value here fails the load:

Failed to load template ./templates/unknown-severity.yaml: YAML parse error: unknown variant `catastrophic`, expected one of `info`, `low`, `medium`, `high`, `critical`

One of yaml, python, rust, shell, javascript, c, cpp, java, go, ruby, perl, php. Required, and it is metadata: it does not change which engine loads the file, which is decided by the file extension.

HTTP request specification

Key Type Required Absent →
method string no GET
path list of string no unset
headers map of string to string no empty map
body string no unset
matchers list of matcher no unset
matchers-condition and / or no unset

Only GET and POST are sent; any other method is skipped with a warning. A request with no path is sent to /.

Network/TCP request specification

Key Type Required Absent →
protocol string no tcp
port integer yes
payloads list of string no empty list
matchers list of matcher no unset
matchers-condition and / or no unset

Escape sequences \r\n, \n, \r and \t in a payload are interpreted before it is written to the socket.

A list of matchers, each identified by its type key. Matchers may sit at the root of the template or inside an http or network entry; an entry’s own matchers win over the template’s.

The set is closed — these 11 types and nothing else:

Terminal window
$ cxg --disable-update-check --no-color -v template list
WARN cert_x_gen::template::engine: Failed to load template ./templates/unknown-matcher-type.yaml: YAML parse error: http[0].matchers[0].type: unknown variant `dsl`, expected one of `status`, `word`, `regex`, `binary`, `time`, `size`, `hash`, `tls`, `dns`, `diff`, `custom` at line 11 column 15

That is the engine listing them itself, from a fixture using a type it does not have.

Status code matcher

Key Type Required Absent →
status list of integer yes

Word matcher

Key Type Required Absent →
words list of string yes
condition and / or no or
part response part no body

Regex matcher

Key Type Required Absent →
regex list of string yes
group integer no unset

Binary matcher

Key Type Required Absent →
binary list of string yes

Time-based matcher

Key Type Required Absent →
condition time condition yes
time {secs: <integer>, nanos: <integer>} yes

A duration is a map, not a number of seconds:

- type: time
condition: greater
time: {secs: 5, nanos: 0}

time: 5 does not load:

Failed to load template ./templates/time-as-scalar.yaml: YAML parse error: http[0].matchers: invalid type: integer `5`, expected struct Duration at line 11 column 7

Size matcher

Key Type Required Absent →
condition size condition yes
size integer yes

Hash matcher

Key Type Required Absent →
algorithm hash algorithm yes
hash string yes

TLS/SSL matcher

Key Type Required Absent →
versions list of string no unset
ciphers list of string no unset
vulnerabilities list of string no unset

DNS matcher

Key Type Required Absent →
record_type string yes
pattern string no unset
value string no unset

Diff matcher (compare with baseline)

Key Type Required Absent →
baseline string yes
threshold integer yes

Custom matcher (code-based)

Key Type Required Absent →
language string yes
code string yes

Match condition

Value Meaning
and All matchers must match
or At least one matcher must match

Response part to match against

Value Meaning
body Match against response body
header Match against response headers
all Match against entire response
data Match against raw data (for network protocols)

Time-based condition

Value Meaning
greater Greater than threshold
less Less than threshold

Size-based condition

Value Meaning
greater Greater than threshold
less Less than threshold
equal Equal to threshold

Hash algorithms

Value Meaning
md5 MD5 hash
sha1 SHA1 hash
sha256 SHA256 hash
sha512 SHA512 hash
blake3 Blake3 hash

Flow definition

Key Type Required Absent →
name string yes
steps list of flow step yes
depends_on list of string no empty list
condition string no unset
optional boolean no false
description string no unset

Each step is identified by its action key.

HTTP request

Key Type Required Absent →
method string yes
path string yes
headers map of string to string no empty map
body string no unset
store string no unset

Set variable

Key Type Required Absent →
name string yes
value string yes

Extract from response

Key Type Required Absent →
from string yes
pattern string yes
store string yes

Check condition

Key Type Required Absent →
condition string yes
message string no unset

Wait/sleep

Key Type Required Absent →
duration_ms integer yes

What the engine requires of a loaded template

Section titled “What the engine requires of a loaded template”

Checked after the document deserializes, when the template is validated:

Template must have either 'http', 'network', or 'flows' defined

Deserialized by src/engine/yaml/mod.rs, over the types in src/types.rs, src/matcher.rs and src/flows.rs, at v1.3.0.