Join our Newsletter — 33% off our NHI Course

What is the best way to reduce false positives and missed matches when writing Semgrep rules?

Use a two-step refinement loop. First, match the broad case with a simple pattern. Then add pattern-not clauses for safe cases and pattern-either clauses for legitimate variants. Test against real code, not only toy examples, because the value of the rule depends on how well it separates interesting code from acceptable code in practice.

Why This Matters for Security Teams

Semgrep rules fail in two common ways, they are too broad and flood reviewers with noise, or they are too narrow and miss the real variants in code. The practical goal is not to write a “clever” pattern, but to encode the security judgment you actually want enforced. That means separating the unsafe shape from the safe exceptions, then checking whether the rule still behaves sensibly across representative codebases.

For that reason, the best refinement loop is iterative: start with the simplest pattern that catches the target class, then tighten it only where the match set proves that you need exclusions or alternate forms. This is especially important in teams that rely on rules for triage, because a noisy rule is usually abandoned long before it matures into a reliable control. In practice, many security teams discover rule quality only after deployment, when reviewers have already lost trust in the findings.

How It Works in Practice

A strong Semgrep rule usually begins with a broad structural match. That first pass should be simple enough that you can explain it in one sentence, because complexity at the start tends to hide both false positive and blind spots. Once the broad case works, add pattern-not clauses to remove known safe cases, such as wrapper functions, validated inputs, or intentionally limited variants. Then use pattern-either when the same security issue appears in more than one legitimate syntax form.

The key is to refine by evidence, not intuition. Test the rule against real repositories, ideally code that includes both vulnerable examples and accepted patterns from your own environment. That is where edge cases appear, for example different helper methods, language idioms, or project-specific abstractions that toy examples never expose. A rule that looks precise in isolation can still fail badly when it meets the style and helper layers used in production code.

  • Begin with the minimum pattern that identifies the risky construct.
  • Add exclusions only after you can point to a concrete safe case.
  • Use pattern-either to cover equivalent variants, not to compensate for an unclear rule.
  • Retest after every change against real code and review the remaining false positives and misses.

This guidance breaks down when the codebase uses highly dynamic metaprogramming or framework abstractions that Semgrep cannot reliably resolve from syntax alone.

Common Variations and Edge Cases

Tighter rule logic often increases maintenance overhead, so teams have to balance precision against the cost of keeping patterns current. The right threshold depends on whether the rule is used for developer feedback, security review, or blocking enforcement. A review-only rule can tolerate a little more noise, but a gatekeeping rule needs a higher bar for precision because every false positive creates operational friction.

One common edge case is when a safe pattern and a risky pattern look almost identical at the syntax level. In those cases, a rule may need to key off surrounding context, not just the vulnerable line itself. Another is when multiple language features can express the same intent, which makes pattern-either useful but also easy to overuse. Best practice is evolving here: if the rule becomes hard to explain, it is usually too broad or too dependent on assumptions that are not visible in the code.

In security engineering terms, the most reliable Semgrep rules are the ones that reflect an actual reviewer decision: this shape is acceptable, that shape is not, and the difference can be defended in real code.

Standards & Framework Alignment

This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.

CIS Controls v8 and NIST CSF 2.0 set the governance and control requirements practitioners need to meet.

Framework Control / Reference Relevance
CIS Controls v8 8.2 — Audit Log Management Rule tuning needs real-code feedback to reduce alert noise and missed detections.
Recommendation — Validate rules against production-like code to reduce noisy findings and missed matches.
NIST CSF 2.0 DE.CM — Continuous Monitoring Semgrep rules function as continuous detection logic that must be measured in practice.
Recommendation — Measure rule precision and recall continuously against real repositories.

Practitioner Guidance

What to prioritise: Get the noise floor down before chasing rare edge cases. If reviewers cannot trust the first 10 results, the rule will not survive long enough to catch the 11th.

What to verify: Confirm that every exclusion you add removes a documented safe case, not just a test sample that happens to pass. The fastest way to weaken a rule is to encode convenience instead of policy.

Practitioner takeaway: Good Semgrep rules are less about syntax tricks and more about encoding a defensible security boundary that stays accurate when exposed to real code.