# Rule IDs

> The closed list of 30 rule ids every finding carries as rule_id — what each one means, its default SARIF level, and where the id is used (policy rules, inline markers, SARIF).

CommitBrief docs · v1.x · Reference

Canonical URL: https://commitbrief.com/docs/1.x/rules/

---

A **rule id** is the stable name of the kind of problem a finding describes, written
`<category>.<rule>` — for example `sec.injection` or `correctness.error-handling`. Every
structured finding carries one in its `rule_id` field, next to a
[`fingerprint`](/docs/1.x/output-formats#field-reference). Requires v1.19.0 or later.

> **Key facts.** The list is closed: 30 ids, listed below. The model must pick exactly one.
> An empty or unknown value becomes `general.other` — it is not a parse error and triggers no
> retry. Ids are never removed or renamed, so a policy file, an inline marker or a baseline
> that names one keeps working across releases. New ids are added, never repurposed.

## Where a rule id is used

| Surface | How |
|---------|-----|
| `--json` | `findings[].rule_id` — see [Output formats](/docs/1.x/output-formats). |
| [Policy gate](/docs/1.x/policy-gate#rules--deny-and-allow-by-rule) | `rules.deny` / `rules.allow` take ids or `<category>.*`. |
| [Inline suppression](/docs/1.x/signal-control#inline-suppression) | `commitbrief-ignore[sec.injection]: reason` silences that rule only. |
| [Baseline](/docs/1.x/signal-control#baseline) | The fingerprint of a finding is a hash of file, rule id and symbol. |
| [SARIF](/docs/1.x/sarif) | `results[].ruleId`, and `tool.driver.rules[]` lists all 30. |

## The 30 rules

Categories: `sec` (security), `correctness`, `concurrency`, `perf`, `api`, `test`, `arch`,
`maint`, `style`, `docs`, `general`.

| Rule id | Default level | What it means |
|---------|---------------|---------------|
| `sec.injection` | error | Untrusted input reaches a query, shell, template or interpreter without neutralisation (SQL, command, LDAP, template) |
| `sec.xss` | error | Untrusted data is written into HTML or JS without context-appropriate escaping |
| `sec.path-traversal` | error | A user-controlled path reaches the file system without being confined |
| `sec.ssrf` | error | A user-controlled URL or host is requested server-side without an allowlist |
| `sec.hardcoded-secret` | error | A credential, key or token literal is present in source |
| `sec.authz` | error | An authentication or authorisation check is missing or can be bypassed |
| `sec.unsafe-deserialization` | error | Untrusted bytes are deserialised into objects or code |
| `sec.crypto-misuse` | warning | Weak algorithm, poor randomness, fixed IV or salt, or disabled TLS verification |
| `sec.data-exposure` | warning | A secret or personal data is written to a log, an error or a response |
| `correctness.nil-deref` | error | A value that may be nil, null, undefined or None is dereferenced |
| `correctness.logic-error` | warning | A condition, operator or flow does not do what the code intends |
| `correctness.boundary` | warning | Off-by-one, empty, overflow or other boundary cases are handled wrongly |
| `correctness.error-handling` | warning | An error is ignored, swallowed, wrapped wrongly or not propagated |
| `correctness.resource-leak` | warning | A file, connection, lock or goroutine is not released on every path |
| `correctness.api-misuse` | warning | A library or standard-library API is called against its contract |
| `concurrency.race` | error | Shared state is accessed concurrently without synchronisation |
| `concurrency.deadlock` | error | Lock ordering or a channel wait can block forever |
| `perf.algorithmic` | warning | Asymptotically poor algorithm or repeated work on a hot path |
| `perf.n-plus-one` | warning | A per-item query or IO call inside a loop |
| `perf.allocation` | note | Avoidable memory allocation or copying on a hot path |
| `api.breaking-change` | warning | A public interface or contract changes incompatibly |
| `test.missing` | note | No test covers the changed behaviour |
| `test.flaky` | warning | Test depends on time, order, randomness or network (the static flaky pre-pass also produces this) |
| `arch.boundary-violation` | warning | The change violates a declared architectural constraint (`architecture.json`) |
| `maint.complexity` | note | Structure is hard to follow and could be simplified |
| `maint.duplication` | note | Logic that should be shared has been copied |
| `maint.dead-code` | note | Unreachable or unused code |
| `style.naming` | note | Misleading or inconsistent identifier |
| `docs.mismatch` | note | A comment or document contradicts the code |
| `general.other` | note | None of the above (the fallback) |

**Default level** is the SARIF level the rule is published with (`error`, `warning` or
`note`). It describes the rule, not the individual finding: a finding's own
[severity](/docs/1.x/severity) decides the `level` of its SARIF result.

## Two ids also produced without the model

Both ids are in the closed list the model chooses from, so a review can label a finding with
either. They are also produced deterministically:

- `test.flaky` comes from the [flaky-test detector](/docs/1.x/flaky-tests) as well.
- `sec.hardcoded-secret` comes from [`commitbrief leaks`](/docs/1.x/leaks) as well. Those
  `leaks` findings carry no `fingerprint`.

A policy entry on either id therefore covers both sources. `rules.allow: [sec.hardcoded-secret]`
or `rules.allow: [sec.*]` also waives a hardcoded credential the model reported in a review,
and `rules.deny: [test.flaky]` also blocks a flaky-test finding the model reported.

## When the model picks the wrong id

The id is a model judgement, so it can be wrong. A finding that fits none of the 30
definitions lands in `general.other`. With `--verbose` (and without `--quiet`), the number of
findings that fell back to `general.other` is written to stderr as a debug record, so you can
see how often it happens on your code.

Because rule ids are a model's classification, treat a `rules.deny` entry as a strong signal,
not a proof: it blocks on whatever the model labelled, and it will not block on a problem the
model labelled differently or did not report.