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
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 (Rustregexsyntax: no lookaround or backreferences).kind: astis a tree-sitter query, so comments and strings do not match. It needs exactly one entry inlanguages; 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.
| Field | Required | Notes |
|---|---|---|
id | Yes | Unique across every rule file loaded. |
languages | For ast | Which files the rule reads; picks the grammar for ast. |
kind | No | regex (default) or ast. |
pattern | Yes | Regex, or a tree-sitter query for ast. |
message | Yes | Shown on the finding as [<id>] <message>. |
remediation | Yes | What to do next. |
severity | No | critical, high, medium (default), low, info. |
owasp_category | No | For example BrokenObjectPropertyAuth. Default SecurityMisconfiguration. |
confidence | No | high, medium (default), low. |
cwe | No | A 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