Rule Reference

All 61 review rules organized by layer.

Base Rules

13 rules that apply to every TypeScript and Python file. These catch universal code-quality problems regardless of framework or target.

  • floating-promise Promise created but never awaited or returned
  • state-mutation Direct mutation of state that should be immutable
  • empty-catch Catch block with no error handling logic
  • machine-gap State machine transition references a state that does not exist
  • cognitive-complexity Function exceeds the configured complexity threshold
  • dead-code Code that can never execute (after return, throw, or break)
  • unused-imports Imported binding is never referenced in the module
  • missing-return Code path exits a function without a return value when one is expected
  • type-any Explicit or inferred any type that weakens type safety
  • implicit-return Function returns undefined on some paths but a value on others
  • hardcoded-secret API key, token, or password literal embedded in source
  • no-eval Use of eval() or Function() constructor with dynamic input
  • console-in-prod console.log or console.debug left in production code

Security Rules — v1

8 rules covering the OWASP Top 10 surface: injection, XSS, deserialization, and cryptographic misuse.

  • injection Unsanitized user input flows into a shell command or system call
  • sql-injection Raw string concatenation in a SQL query instead of parameterized statements
  • xss User-controlled value rendered into HTML without escaping
  • unsanitized-html Raw HTML inserted via dangerouslySetInnerHTML or v-html without sanitizer
  • unsafe-deserialization Untrusted data passed to JSON.parse, pickle.loads, or yaml.load without validation
  • insecure-random Math.random() or random.random() used in a security-sensitive context
  • hardcoded-secret Credential literal found in source (also a base rule, upgraded to error in security context)
  • weak-hash Use of MD5 or SHA-1 for hashing where a collision-resistant algorithm is required

Security Rules — v2

6 rules for authentication, authorization, and concurrency vulnerabilities.

  • csrf-token-missing State-changing endpoint accepts requests without CSRF token validation
  • rate-limit-missing Public or auth endpoint has no rate-limiting middleware
  • auth-bypass Route handler reachable without authentication check
  • privilege-escalation User-controlled input determines access level without authorization guard
  • path-traversal File path constructed from user input without normalization or allowlist
  • race-condition Shared resource accessed concurrently without lock or atomic operation

Security Rules — v3

5 rules targeting modern attack vectors including prototype pollution, regex denial-of-service, and LLM prompt injection.

  • regex-dos Regular expression with catastrophic backtracking potential
  • missing-input-validation External input consumed without schema or type validation
  • prototype-pollution Dynamic property assignment on Object.prototype or via unchecked merge
  • information-exposure Stack trace, internal path, or debug data leaked in an error response
  • prompt-injection User-controlled text concatenated into an LLM prompt without boundary enforcement

Dead Logic

8 rules that detect code which compiles but can never affect runtime behavior. These are often symptoms of refactoring mistakes.

  • unreachable-code Statement after an unconditional return, throw, or break
  • always-true Condition that evaluates to true on every possible code path
  • always-false Condition that evaluates to false on every possible code path
  • unused-variable Variable declared and assigned but never read
  • dead-branch If/else or switch branch that can never execute
  • redundant-condition Condition already guaranteed by a parent guard or earlier check
  • impossible-type Type narrowing produces never, meaning the branch is unreachable
  • empty-block Block statement with no body (empty if, empty loop)

React Rules

6 rules active when the target is React, Next.js, Tailwind, or React Native. They catch hook misuse and rendering pitfalls.

  • async-effect useEffect callback is async (should return void, not a Promise)
  • render-side-effect Side effect executed during the render phase instead of inside useEffect
  • missing-dependency Reactive value used inside useEffect/useMemo/useCallback but missing from the dependency array
  • stale-closure Callback captures a stale variable because the dependency array is incomplete
  • hook-rules Hook called conditionally or inside a loop, violating the Rules of Hooks
  • missing-key List item rendered without a stable key prop

Next.js Rules

3 rules specific to the Next.js App Router model.

  • server-hook React hook called inside a Server Component (must be a Client Component)
  • hydration-mismatch Server-rendered HTML will differ from client hydration output
  • client-directive-missing Component uses hooks or browser APIs but is missing the 'use client' directive

Vue Rules

4 rules for Vue 2/3 and Nuxt projects.

  • vue-data-not-function data property is a plain object instead of a factory function (Vue 2)
  • vue-missing-key v-for list item missing a :key binding
  • vue-prop-mutation Child component directly mutates a prop instead of emitting an event
  • vue-lifecycle-deprecated Deprecated lifecycle hook used (beforeDestroy, destroyed in Vue 3)

Express Rules

3 rules for Express.js server applications.

  • express-missing-error-handler Express app has no 4-argument error-handling middleware registered
  • express-helmet-missing Express app does not use Helmet or equivalent security headers middleware
  • express-sync-io Synchronous fs or child_process call inside a route handler blocks the event loop

Prompt injection detection

Beyond the prompt-injection rule in Security v3, kern review detects 7 verified attack vectors from the OWASP LLM Top 10 (LLM01). Each vector is identified by taint-tracking user input through prompt construction paths.

  • indirect-prompt-injection Untrusted data (fetched content, DB rows) injected into a prompt without boundary markers
  • llm-output-execution LLM response passed directly to eval, exec, or shell without validation
  • prompt-injection User-controlled string concatenated into a system or user prompt
  • encoding-bypass Base64, hex, or unicode encoding used to smuggle instructions past input filters
  • delimiter-injection User input contains prompt delimiters (detected via the prompt-injection vector)
  • json-output-manipulation LLM JSON output parsed and used in control flow without schema validation
  • missing-output-validation LLM response consumed by application logic with no sanitization or type check

Example — detecting llm-output-execution:

// Flagged: LLM output flows into eval without validation
const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{ role: 'user', content: userInput }],
});

const code = response.choices[0].message.content;
eval(code);  // llm-output-execution (error, confidence: 0.97)

// Fix: validate and sandbox the output
const parsed = safeParseCode(code);
if (parsed.ok) {
  sandbox.run(parsed.value);
}

Severity levels

Every finding is assigned one of three severity levels. CI enforcement via --enforce fails on any error-level finding by default.

LevelMeaningExamples
errorMust fix. Security vulnerability, data loss risk, or guaranteed runtime failure.sql-injection, prompt-injection, auth-bypass, floating-promise
warningShould fix. Code smell, potential bug, or degraded maintainability.cognitive-complexity, missing-dependency, dead-branch
infoInformational. Style preference or low-risk observation.unused-imports, console-in-prod, empty-block

Confidence scores

Each finding includes a confidence score from 0 to 1 indicating how certain the analyzer is that the finding is a true positive.

  • 0.9 – 1.0 — High confidence. Pattern matched exactly with full taint-tracking or type evidence.
  • 0.7 – 0.89 — Medium confidence. Pattern matched but some context is ambiguous (e.g., dynamic import, indirect call).
  • 0.5 – 0.69 — Low confidence. Heuristic match that may be a false positive. Review manually.
  • Below 0.5 — Suppressed by default. Enable with --min-confidence=0 to see all findings.

Filter findings by confidence using the --min-confidence flag or the minConfidence config key:

# Only show findings with >= 80% confidence
kern review src/ --recursive --min-confidence=0.8