Skip to main content

Custom rule packs

Custom rules let you add your own patterns, such as an internal token format or a banned API. They are YAML and run with the built-in detectors on every scan.

vulkro scan . # picks up ./vulkro-rules.yaml
vulkro scan ./fixture --rules ./my-rules.yaml # test a rule file

Writing a rule​

vulkro-rules.yaml
rules:
# regex: an internal token committed to source
- id: corp-internal-token
languages: [javascript, typescript, python]
kind: regex
pattern: "intsk_[A-Za-z0-9]{32}"
message: "Internal corp token committed to source"
remediation: "Rotate the token and read it from an environment variable."
severity: critical
confidence: high

# ast: a real eval() call, not the word in a comment
- id: deny-eval-js
languages: [javascript]
kind: ast
pattern: '(call_expression function: (identifier) @fn (#eq? @fn "eval"))'
message: "eval() call: arbitrary code execution sink"
remediation: "Parse the input instead, for example with JSON.parse."
severity: high
  • kind: regex (default) matches text line by line (Rust regex syntax: no lookaround or backreferences).
  • kind: ast is a tree-sitter query, so comments and strings do not match. It needs exactly one entry in languages; write one rule per language.

Languages: python, javascript, typescript, go, java, c, cpp, php. Java takes regex rules only. Ruby, Kotlin and C# are refused with an error, because Vulkro does not analyse them.

FieldRequiredNotes
idYesUnique across every rule file loaded.
languagesFor astWhich files the rule reads; picks the grammar for ast.
kindNoregex (default) or ast.
patternYesRegex, or a tree-sitter query for ast.
messageYesShown on the finding as [<id>] <message>.
remediationYesWhat to do next.
severityNocritical, high, medium (default), low, info.
owasp_categoryNoFor example BrokenObjectPropertyAuth. Default SecurityMisconfiguration.
confidenceNohigh, medium (default), low.
cweNoA CWE number.

A rule that fails to parse is skipped with a warning on stderr. Check stderr after editing, and keep positive and negative fixtures to re-run.

Where rules come from​

A scan loads vulkro-rules.yaml at the project root (or the file named in VULKRO_RULES), plus anything passed with --rules <PATH> (a file or a directory) for that run. Installed packs under ~/.vulkro/rule-packs/ also run on every scan.

Rule packs​

vulkro rules list # packs in the registry
vulkro rules add acme/api-security # install after the signature verifies
vulkro rules add acme/api-security@1.2.0
vulkro rules installed
vulkro rules verify acme/api-security
vulkro rules remove acme/api-security

Importing existing rules​

vulkro rules import-semgrep <file>.yaml converts rules in that YAML format into a vulkro-rules.yaml next to the input. Simple patterns become regexes; compound shapes are skipped with a warning, so review the output.

See also: vulkro rules, Suppressions