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 cxg 1.3.0, 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 cxg 1.3.0, 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.