CEL rule expressions
The CEL when and selector expressions in config documents: which kinds take them, where each is evaluated, what happens when one cannot be, every variable per context, the functions, the limits and examples.
CEL, the Common Expression Language, is how a config document writes a condition the typed fields cannot. A when field holds one expression that must return bool. One Go package, github.com/vulnetix/config-schemas/cel, compiles and evaluates every expression, in the config engine and in each service that runs the rules, and all of them run the same golden test vectors, so a rule gives the same answer wherever it runs.
when: severity == 'critical' && (kev || reachable)
Which kinds take CEL
13 fields in 8 of the 59 kinds take an expression. They are listed in each schema’s x-vulnetix.celFields, with the context the expression is compiled in. The other 51 kinds have none.
| Kind | Field | Context | Status |
|---|---|---|---|
AiFirewallPolicy |
spec.guardrails[].when |
request |
Applied by the engine |
ComplianceTarget |
spec.crypto.allow |
cbom |
Applied by the engine |
ComplianceTarget |
spec.crypto.appliesTo |
cbom |
Applied by the engine |
DetectionRuleFeed |
spec.selector.when |
cve |
Applied by the engine |
JailPolicy |
spec.rules[].when |
finding |
Applied by the engine |
PackageList |
spec.entries[].when |
package |
Applied by the engine |
RiskStrategy |
spec.rules[].when |
finding |
Applied by the engine |
SsvcPolicy |
spec.exploitation.active |
finding |
Applied by the engine |
SsvcPolicy |
spec.exploitation.poc |
finding |
Applied by the engine |
SsvcPolicy |
spec.automatable |
finding |
Applied by the engine |
SsvcPolicy |
spec.technicalImpact |
finding |
Applied by the engine |
SsvcPolicy |
spec.overrides[].when |
finding |
Applied by the engine |
Suppression |
spec.when |
finding |
Applied by the engine |
Each context has its own variables, listed below. A variable from another context is a type error. The event context is defined in the package, for Software Factory trigger conditions, but no released kind has a field in it: FactoryTrigger conditions are typed fields.
Where each expression is evaluated
The engine type-checks every expression when it plans a document, with the same package that evaluates it, so a stored expression normally compiles at run time too. Where it is then evaluated, and what happens when it cannot be, differs by kind:
| Kind and field | Evaluated | When the expression cannot be evaluated |
|---|---|---|
AiFirewallPolicy spec.guardrails[].when |
by the AI firewall gateway, for each request | The rule is skipped, named in the decision’s skipped list, and the gateway logs it. |
ComplianceTarget spec.crypto.allow, spec.crypto.appliesTo |
by the Vulnetix site API at every run of the target, once for each component of the newest CBOM of each repository in scope (at most 20000 components) | Fails closed for crypto.allow: a component it cannot be evaluated for is a violation, because an unassessed algorithm must not pass a policy. A crypto.appliesTo that fails leaves the component in scope. |
DetectionRuleFeed spec.selector.when |
by the Vulnetix site API at every publish of the feed, once for each candidate rule and CVE | The pair does not match. When every pair fails, the publish is refused. |
JailPolicy spec.rules[].when |
by the jail evaluator in the VDB API, which vulnetix jail and vulnetix scan --jail call, and by the Software Factory gate node for its COUNT rules |
In the VDB API a rule whose when does not compile, or uses a variable its rule kind lacks, is skipped with a warning, and a fact the expression errors on makes the rule indeterminate (vulnetix jail exits 3). In the factory gate the rule fails closed: it breaches, labelled “when could not be evaluated”. |
PackageList spec.entries[].when |
by the package firewall proxy, for each requested version, in evaluate() |
The entry is skipped and the proxy logs it. |
RiskStrategy spec.rules[].when |
by the ranking ladder in the Vulnetix site API, over the tenant’s open findings (at most 5000, most severe first) | Fails open. A rule that does not compile matches nothing and is logged. A finding the expression errors on does not match. |
SsvcPolicy spec.exploitation.active, spec.exploitation.poc, spec.automatable, spec.technicalImpact, spec.overrides[].when |
by the SSVC decision in the Vulnetix site API, on every decision and summary (the summary covers at most 5000 open findings, most severe first, cached for 60 seconds), and by the VDB API for the CLI scan and the remediation plan | The decision point takes its lower value and the decision is still made. An override that fails does not hold. |
Suppression spec.when |
by the suppression engine, over the findings a rule’s anchors have already matched | Fails open. A finding the expression errors on is not suppressed. |
JailPolicy
Jail evaluates when over the facts it already holds, and those do not carry every finding variable. A rule is skipped with a warning when its when does not compile, or names a variable the facts of its rule kind lack. Skipping reports a rule that is not running, rather than counting against a zero value and showing a green gate on missing evidence.
Rule kind |
Variables when may use |
|---|---|
VULN |
id, severity, cvss, kev, malicious, reachable, fixAvailability, direct, purl, ecosystem, labels, owner, criticality, now |
EOL |
id, severity, eol, direct, purl, ecosystem, labels, owner, criticality, now |
HYGIENE |
id, severity, cvss, labels, owner, criticality, now |
GOAL |
id, labels, owner, criticality, now |
labels, owner and criticality come from the asset record of the repository being assessed (RepositorySettings), and are empty for a repository with no record. epss, exploitMaturity, cwe and internetExposed are not available to jail rules. An expression over one of them type-checks, so plan accepts it, and the rule is then skipped with a warning when the gate runs. A fact the expression errors on is not counted, and the rule then reports indeterminate: vulnetix jail exits 3, which is neither a pass nor a breach.
The factory gate
A Software Factory gate node applies a JailPolicy to a scan’s findings. A COUNT rule with when counts only the scan’s finding items (at most 200, from scan/findings.json) at or above its severity floor for which the condition holds. Items carry id, severity, kind, KEV and package, and repo, labels, owner and criticality come from the run’s repository, so other finding variables read as zero values. The gate fails closed: when the condition cannot be evaluated, or when the scan kept fewer items than it found and the partial count does not already breach a GT or GTE threshold, the rule breaches and its label says why. A rule with onBreach: warn never breaches.
RiskStrategy
The ranking ladder is a SQL CASE and cannot run CEL, so each CEL rule is evaluated in Go over the tenant’s open findings, most severe first, at most 5000, and the result is cached for 60 seconds. A finding past the cap matches no CEL rule and falls to the rules after it, which is logged. A rule that does not compile matches nothing and is logged. A finding the expression errors on does not match: the rule fails open. labels, owner and criticality are filled from each finding’s repository asset record; when the records cannot be read, a rule over them matches nothing and the failure is logged.
Suppression
The suppression engine matches a rule’s anchors first, then asks which of the matched findings the when holds for, over the same facts the ranking ladder reads. An expression that errors on a finding does not select it, so the finding is not suppressed: the rule fails open, because an unevaluable condition never suppresses anything. The asset variables (labels, owner, criticality) are filled the same way as for the ranking ladder.
PackageList
The package firewall evaluates an entry’s when in evaluate() for the requested version. An entry with no when always applies. A conditional entry applies when its expression holds. An expression that fails to evaluate is logged and the entry skipped, so a broken condition neither blocks nor waives more than was declared.
The proxy has the version’s advisory signals (malware, CVSS, EPSS, CESS, KEV, EOL, exploit maturity, bad actor) but not its publish time or version lag, so ageDays reads -1 and versionLag reads 0. A conditional entry is judged only where the proxy has the version’s signals. The whole-package gates, the cooldown and version-lag waivers, the bad-actor waiver and deny injection for versions with no signal row skip it. A conditional allow entry still lets an allowlist_only package through to per-version filtering. Entries are stored in PackageFirewallListEntry.expr, which needs saas migration 20261225000000_firewall_rule_expr: until it runs, an apply that sets a when is refused with the migration’s name.
AiFirewallPolicy
The AI firewall gateway evaluates a guardrail’s when over the request: its provider, model and client, and the tools, MCP servers and skills it declares. A tool shown being invoked in replayed history is not on offer, so it does not count. A guardrail with no when always applies. A rule whose when fails to evaluate is skipped, named in the decision’s skipped list, and logged: the gateway does not block or flag on a condition it could not judge. Each list is bounded at 256 entries, and a larger request is judged on the first 256.
A guardrail of rule type expression takes no pattern: its when is its whole match, it blocks or flags, and it is judged on the capability plane with the tool, MCP server, skill and client lists before content is scanned. Guardrails are stored in AiFirewallGuardrail.expr, from the same migration as package list entries.
SsvcPolicy
The SSVC decision evaluates the policy’s expressions over the finding, with the repository’s asset record, whenever a decision or the summary is read, and the VDB API does the same for each vulnerability of a CLI scan and for the remediation plan when the tenant has stored a policy. An expression that fails to evaluate holds for nothing: the decision point takes its lower value (not exploited, not automatable, partial impact) and the decision is still made. An override whose when fails does not hold, so the table’s outcome stands. The summary decides at most 5000 open findings, most severe first, and is cached for 60 seconds per policy.
DetectionRuleFeed
The selector is evaluated at every publish, from the console or the engine. The candidates are the newest 5000 generated rules of the feed’s format: virtual patches for a block-lane format, countermeasures for a detect-lane one. Each rule is evaluated once per CVE it was written for, and selected when the condition holds for any of them. A rule with no CVE is evaluated once with an empty id and zero scores. A pair the expression errors on does not match; when every pair fails, the publish is refused. The published file holds the explicit entries first, then each selected rule not already among them, up to 500. Selected rules are never written as entries, so the next publish picks up new rules and new KEV listings without an edit to the feed.
How an expression is checked
| When | What happens |
|---|---|
POST /config/validate |
The schema checks that the field is a string of 1 to 4096 characters. |
| Plan | The expression is compiled and type-checked in its context. A failure is a blocking condition, invalid_cel, that names the rule and the position, and blocks the plan. The worst-case cost is estimated with every string and list at its bound, and an expression over the limit is refused. |
| Evaluation | An input past a variable’s bound is refused, and evaluation that goes past the cost limit stops. |
Comparisons between int and double are allowed, so cvss >= 7 type-checks. Equality between them is not: write cvss == 7.0. The cel-go extension libraries (strings, math, lists) are not loaded.
Error codes
| Code | When |
|---|---|
length |
The expression is longer than the limit. |
syntax |
It does not parse. |
type |
It does not type-check: an unknown variable, a variable from another context, or a comparison between the wrong types. |
result_type |
It type-checks to something other than bool. |
cost |
Its estimated cost at compile time, or its actual cost at evaluation, exceeds the limit. |
context |
An unknown context, or an input of the wrong context. |
input |
The input exceeds a variable’s bound. |
eval |
Evaluation failed, for example an invalid purl passed to matchesPurl. |
The codes are stable; the messages are not. Line and column are counted from 1.
Variables, functions and limits
The tables below are generated from the CEL environments themselves (go run ./cmd/celdoc in config-schemas). The top-level names are the variables: write severity, not finding.severity. Variables marked Derived are computed from the others. now is the time of evaluation unless the caller fixes it.
Context finding
| Variable | Type | Bound | Description |
|---|---|---|---|
id |
string |
256 chars | The advisory identifier, such as CVE-2024-3094 or a GHSA ID. |
aliases |
list(string) |
64 items of 256 chars | Other identifiers the advisory is known by. |
severity |
string |
64 chars | Lower case: critical, high, medium, low, or empty when unknown. |
cvss |
double |
CVSS base score, 0 to 10. 0 when unscored. | |
epss |
double |
EPSS probability, 0 to 1. | |
epssPercentile |
double |
EPSS percentile, 0 to 1. | |
kev |
bool |
Listed in any known-exploited catalogue: CISA KEV, VulnCheck KEV or EU KEV. | |
exploitMaturity |
string |
64 chars | The highest exploit tier, as the CLI --exploits gate grades it: poc, active, weaponized, or empty when none is known. |
exploitCount |
int |
Number of public exploits known. | |
reachability |
string |
64 chars | Lower case reachability verdict: direct, transitive, semantic, unreachable, or empty when not assessed. |
reachable |
bool |
Derived. True when reachability is direct, transitive or semantic, the same set the findings page counts as reachable. |
|
internetExposed |
bool |
The package is observed on internet-facing infrastructure. | |
eol |
bool |
The package version is end of life. | |
malicious |
bool |
The package is known malware. | |
fixAvailability |
string |
64 chars | available, partial, no_fix, or empty when unknown. |
direct |
bool |
The package is a direct dependency, not a transitive one. | |
purl |
string |
2048 chars | Package URL of the affected package, with version. |
ecosystem |
string |
64 chars | Package ecosystem, such as npm, pypi, golang, maven. |
cwe |
list(string) |
64 items of 64 chars | CWE identifiers, upper case with prefix: CWE-79. |
repo |
string |
512 chars | Repository full name, owner/name. |
branch |
string |
512 chars | Branch the finding was scanned on. |
path |
string |
1024 chars | File the finding came from, such as the manifest or lock file, relative to the repository root. |
labels |
map(string, string) |
50 keys, keys and values of 256 chars | The key/value labels of the repository the finding is in, as set on the repository’s asset record or in a RepositorySettings document: labels['tier'] == 'prod'. Empty when the repository has none, and in a runtime that does not know the repository’s asset record, so 'tier' in labels is false there. |
owner |
string |
512 chars | Who owns the repository: a team name, a user name or an email address, as set on its asset record. Empty when none is set. |
criticality |
string |
64 chars | How much the business depends on the repository: low, medium, high or critical. Empty when none is set, so criticality in ['high', 'critical'] is false for an unclassified repository. |
now |
timestamp |
The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs. |
Context package
| Variable | Type | Bound | Description |
|---|---|---|---|
purl |
string |
2048 chars | Package URL of the requested version. |
ecosystem |
string |
64 chars | Package ecosystem, such as npm, pypi, golang, maven. |
name |
string |
512 chars | Package name as the ecosystem writes it: @acme/tool, github.com/acme/tool, com.acme:tool. |
version |
string |
256 chars | Requested version. |
published |
timestamp |
When the version was published. The zero timestamp when unknown. | |
ageDays |
int |
Derived. Whole days from published to now. -1 when the publish time is unknown, so a cooldown rule never reads an unknown age as new. |
|
versionLag |
int |
How many releases are newer than this version. 0 for the newest, or when the lag is unknown. | |
malware |
bool |
The version is known malware. | |
cvss |
double |
Highest CVSS base score across the version’s advisories. | |
epss |
double |
Highest EPSS probability across the version’s advisories. | |
cess |
double |
Highest Coalition ESS score across the version’s advisories. | |
kev |
bool |
An advisory for the version is in a known-exploited catalogue. | |
eol |
bool |
The version is end of life. | |
exploitMaturity |
string |
64 chars | poc, active, weaponized, or empty when no exploit is known. |
badActor |
bool |
The publisher is a known bad actor. | |
now |
timestamp |
The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs. |
Context request
| Variable | Type | Bound | Description |
|---|---|---|---|
provider |
string |
256 chars | Provider slug, such as anthropic or openai. |
model |
string |
256 chars | Model slug as requested. |
client |
string |
256 chars | Calling client’s name, such as claude-code or codex. |
tools |
list(string) |
512 items of 256 chars | Tool names the request declares or calls, including flattened MCP tools such as mcp__github__create_issue. |
mcpServers |
list(string) |
128 items of 256 chars | Labels of the remote MCP servers the request wires in. |
skills |
list(string) |
256 items of 256 chars | Skill names the request offers. |
now |
timestamp |
The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs. |
Context event
| Variable | Type | Bound | Description |
|---|---|---|---|
event |
string |
64 chars | Trigger event name, such as pull_request.opened or push. |
base |
string |
64 chars | The event name before the first dot, such as pull_request. Derived from event when not sent. |
action |
string |
64 chars | The event name after the first dot, such as opened. Empty for push. |
repo |
string |
512 chars | owner/name on github.com, host/owner/name on other forges. |
number |
int |
Pull request or issue number, 0 when there is none. | |
subject |
string |
256 chars | What the delivery is about: pr:7, issue:12, release:v1.2.3, or empty. |
ref |
string |
512 chars | The pushed ref, for push. |
headBranch |
string |
512 chars | Branch the change is on. |
baseBranch |
string |
512 chars | Pull request target branch; the pushed branch for push. |
defaultBranch |
string |
512 chars | Repository default branch. |
author |
string |
256 chars | Pull request author, pusher, comment author or run actor. |
authorType |
string |
64 chars | user or bot. |
sender |
string |
256 chars | The delivery’s sender. |
senderType |
string |
64 chars | user or bot. |
labels |
list(string) |
100 items of 256 chars | Labels on the pull request or issue. |
draft |
bool |
The pull request is a draft. | |
origin |
string |
64 chars | same_repo or fork. An empty origin reads as same_repo. |
conclusion |
string |
64 chars | Conclusion of a check run, check suite or workflow run, or a deployment state: success, failure, cancelled and so on. |
reviewState |
string |
64 chars | approved, changes_requested, dismissed or commented on pull_request_review. |
paths |
list(string) |
1000 items of 1024 chars | Paths a push added, modified or removed. A caller with more than the bound sends the first 1000 and sets pathsTruncated. |
pathsTruncated |
bool |
paths is partial. |
|
deleted |
bool |
The push deleted its ref. | |
severity |
string |
64 chars | Lower case alert severity on dependabot_alert, code_scanning_alert and posture_finding. |
environment |
string |
512 chars | Deployment environment on deployment_status. |
packageType |
string |
64 chars | Published package type on registry_package: container, npm, maven and so on. |
properties |
map(string, list(string)) |
100 keys, 50 items each, of 256 chars | Repository custom property values, by property name. |
now |
timestamp |
The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs. |
Context cve
| Variable | Type | Bound | Description |
|---|---|---|---|
id |
string |
256 chars | CVE identifier. |
cvss |
double |
CVSS base score, 0 to 10. 0 when unscored. | |
epss |
double |
EPSS probability, 0 to 1. | |
kev |
bool |
Listed in a known-exploited catalogue. | |
published |
timestamp |
When the CVE was published. The zero timestamp when unknown. | |
kind |
string |
64 chars | Rule format: SNORT, SURICATA, MODSECURITY, NGINX, AWS_WAF, CLOUDFLARE_WAF, REGEX_L7, SIGMA, YARA, STIX, OPENIOC. |
confidence |
string |
64 chars | Confidence in the rule: HIGH, MEDIUM, LOW, or empty. |
falsePositiveRisk |
string |
64 chars | HIGH, MEDIUM, LOW, or empty. |
now |
timestamp |
The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs. |
Context cbom
| Variable | Type | Bound | Description |
|---|---|---|---|
name |
string |
512 chars | The component’s name as the inventory records it: AES-256-GCM, RSA-2048, ML-KEM-768, a certificate subject, or a library name. |
category |
string |
64 chars | algorithm, certificate, key or library. |
assetType |
string |
64 chars | The CycloneDX cryptographic asset type: algorithm, certificate, related-crypto-material, or empty for a library. |
oid |
string |
256 chars | The algorithm’s OID, such as 2.16.840.1.101.3.4.1.46, or empty when unknown. |
primitive |
string |
64 chars | The CycloneDX cryptographic primitive: ae, block-cipher, stream-cipher, hash, mac, kdf, drbg, signature, pke, kem, key-agree, xof, combiner, other, or empty. |
parameterSetIdentifier |
string |
256 chars | The parameter set: a key size such as 256, a curve such as P-256, or a named set such as ML-DSA-65. Empty when none. |
classicalSecurityLevel |
int |
Classical security strength in bits. 0 when unknown. | |
nistQuantumSecurityLevel |
int |
The NIST post-quantum security category, 1 to 5 (6 for a hybrid that meets the highest). 0 when the algorithm offers none, or when unknown. | |
pqcStatus |
string |
64 chars | quantum-safe, quantum-vulnerable, deprecated, hybrid, or empty when not assessed. |
quantumSafe |
bool |
Derived. True when pqcStatus is quantum-safe or hybrid, the set the Crypto Inventory counts as safe. |
|
deprecated |
bool |
Derived. True when pqcStatus is deprecated. |
|
standards |
map(string, string) |
20 keys, keys and values of 256 chars | Each standards body’s verdict on the algorithm, by body: standards['NIST'] is approved, deprecated, disallowed and so on. The bodies the catalogue knows include NIST, BSI and CNSA 2.0. Empty for a component with none. |
provider |
string |
512 chars | The library or implementation that provides it, such as openssl or golang.org/x/crypto. |
purl |
string |
2048 chars | Package URL of the providing library, when known. |
confidence |
string |
64 chars | How sure the detection is: high, medium, low, or empty. |
repo |
string |
512 chars | Repository full name, owner/name, of the scan the component was found in. |
branch |
string |
512 chars | Branch of that scan. |
now |
timestamp |
The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs. |
Functions
Available in every context, alongside the CEL standard library.
| Function | Description |
|---|---|
string.glob(pattern string) bool |
Glob match over the whole string. * is any run of characters except /, ** is any run including /, **/ is zero or more directories, ? is one character except /. Everything else is literal. The same dialect as factory trigger conditions. |
string.matchesPurl(pattern string) bool |
Package URL match. The pattern is a purl: without a version it matches every version, with one it matches that version only. A pattern whose name ends in /* or :* matches every package under that namespace, as package firewall allow entries do: pkg:npm/@acme/* covers pkg:npm/@acme/tool@1.0.0 but not pkg:npm/@acme-evil/tool. Qualifiers and subpaths are ignored. Names compare as written. An invalid purl or pattern is an evaluation error. |
semverCompare(a string, b string) int |
-1, 0 or 1 as a is lower than, equal to or higher than b in semantic version order. Precedence follows SemVer 2.0.0: pre-releases rank below the release and build metadata is ignored. A leading v is optional; the shorthands 1 and 1.2 are not versions. A value that is not a semantic version is an evaluation error; guard with isSemver. |
isSemver(v string) bool |
Whether v is a semantic version, with or without a leading v. |
When a rule cannot be evaluated
The library reports a compile or evaluation error and nothing more. What a rule does with it differs by runtime. The factory gate and a cryptography policy fail closed; every other rule fails open or is skipped.
| Runtime | Field | On an error |
|---|---|---|
| Jail (vdb-api) | JailPolicy rule when |
Does not fail closed. A rule whose when does not compile, or uses a finding variable the facts of its rule kind do not carry yet, is skipped with a warning and does not run. A fact the expression fails on leaves the rule indeterminate, so the verdict is indeterminate and the CLI exits 3; a breached rule elsewhere still wins, with exit 1. |
| Factory gate (vdb-site) | JailPolicy rule when, in a workflow gate node |
The only runtime that fails closed. A when that does not compile or fails on a finding makes the rule breach, and its label says it could not be evaluated. So does a scan that kept fewer findings than it found, unless the count over the kept ones already breaches. A rule with onBreach: WARN does not fail the gate. |
| Risk prioritisation (vdb-site) | RiskStrategy rule when |
Fails open. A finding the expression fails on does not match. A rule that does not compile is logged and matches nothing. |
| Suppression | Suppression when |
Fails open. A finding the expression fails on is not suppressed. A rule whose expression cannot be evaluated covers nothing in that run and the error is logged; every other rule applies as usual. |
| Package firewall | PackageList entry when |
The entry is skipped and the error is logged: a deny entry does not block and an allow entry does not waive, so a broken condition neither blocks nor waives more than was declared. |
| SSVC decision (vdb-site) | SsvcPolicy decision point expressions and overrides[].when |
The decision point takes its lower value (not exploited, not automatable, partial impact) and the decision is still made. An override that fails does not hold. |
| Cryptography policy (vdb-site) | ComplianceTarget crypto.allow and crypto.appliesTo |
Fails closed for allow: a component the expression cannot be evaluated for is reported as a violation, because an unassessed algorithm must not pass a policy. An appliesTo that fails leaves the component in scope. |
| AI firewall | AiFirewallPolicy rule when |
The rule is skipped and named in the decision’s skipped list with the error. The gateway does not block or flag on a condition it could not evaluate. |
Cost and length limits
| Limit | Value |
|---|---|
| Expression length | 4096 bytes |
| Estimated cost, checked at plan | 1000000 |
| Actual cost, checked at evaluation | 1000000 |
The estimate assumes every string and list is at its bound in the tables above, and evaluation refuses an input past a bound, so an expression that passes plan cannot exceed the limit when it runs. A single exists or all over a list is well inside it; a comprehension nested inside another over the same list usually is not.
Examples
Every expression below is in a released example, and a test in config-schemas compiles each one in its context.
| Kind | Context | Expression |
|---|---|---|
AiFirewallPolicy |
request |
client == 'codex' |
AiFirewallPolicy |
request |
'filesystem' in mcpServers && tools.exists(t, t.startsWith('mcp__filesystem__write')) |
ComplianceTarget |
cbom |
quantumSafe || (primitive in ['block-cipher', 'hash', 'mac'] && classicalSecurityLevel >= 128) |
ComplianceTarget |
cbom |
category == 'algorithm' && confidence != 'low' |
DetectionRuleFeed |
cve |
kind == 'SURICATA' && (kev || epss >= 0.5) && cvss >= 7.0 && falsePositiveRisk != 'HIGH' && now - published < duration('8760h') |
DetectionRuleFeed |
cve |
kev && confidence == 'HIGH' && kind == 'SIGMA' |
JailPolicy |
finding |
fixAvailability == 'available' && (kev || epss >= 0.1) |
JailPolicy |
finding |
epss >= 0.1 |
PackageList |
package |
!malware && !badActor |
PackageList |
package |
cvss < 9.0 && !kev |
PackageList |
package |
ageDays < 3 || versionLag > 5 |
RiskStrategy |
finding |
reachable && (epss >= 0.2 || exploitMaturity == 'active') |
RiskStrategy |
finding |
reachable && epss >= 0.2 |
SsvcPolicy |
finding |
kev || exploitMaturity in ['active', 'weaponized'] |
SsvcPolicy |
finding |
exploitMaturity == 'poc' || exploitCount > 0 |
SsvcPolicy |
finding |
cvss >= 9.0 || epss >= 0.5 |
SsvcPolicy |
finding |
[no, yes] |
SsvcPolicy |
finding |
cvss >= 9.0 || malicious |
SsvcPolicy |
finding |
[total] |
SsvcPolicy |
finding |
labels['pci'] == 'in-scope' && severity in ['critical', 'high'] |
SsvcPolicy |
finding |
!reachable && fixAvailability == 'no_fix' |
Suppression |
finding |
severity != 'critical' && !kev && repo == 'acme/storefront' |
Suppression |
finding |
!internetExposed |
A few more. Each compiles in the context named.
# finding: glob matches the whole string; * stops at /, ** does not
when: path.glob('services/**/package.json')
# finding: matchesPurl takes a purl pattern; a name ending /* covers a namespace
when: purl.matchesPurl('pkg:npm/@acme/*')
# finding: the repository's asset record (RepositorySettings labels, owner, criticality)
when: criticality in ['high', 'critical'] && labels['tier'] == 'prod'
# package: guard with isSemver before comparing
when: isSemver(version) && semverCompare(version, '2.0.0') < 0
# request: lists take exists, all and in
when: "'filesystem' in mcpServers && tools.exists(t, t.startsWith('mcp__filesystem__write'))"