Skip to content

confidence scoring#7506

Open
Mzack9999 wants to merge 9 commits into
devfrom
nuclei-confidence
Open

confidence scoring#7506
Mzack9999 wants to merge 9 commits into
devfrom
nuclei-confidence

Conversation

@Mzack9999

@Mzack9999 Mzack9999 commented Jun 25, 2026

Copy link
Copy Markdown
Member

Adds a deterministic 0-100 detection confidence score and a low/medium/high tier to every finding, independent of severity.

  • scores each match from matcher composition, rewarding stronger techniques, content over metadata, corroboration across distinct evidence classes, negative guards and multi pattern matchers
  • pins out of band interactsh confirmation to certain and downweights metadata only dsl matchers
  • optional -cob flag sends one per host control request and lowers confidence on catch all (likely false positive) responses
  • covers all protocols and workflows, validated against the full public template corpus
  • surfaced in jsonl, screen, markdown, sarif and pdf output

Closes #7505

Summary by CodeRabbit

  • New Features
    • Added a new confidence scoring system with low, medium, high tiers plus confidence scores.
    • Added a --confidence-baseline (-cob) option to run per-host catch-all checks and adjust confidence.
    • Displayed confidence in screen output, JSON results, PDF reports, formatted report descriptions, and SARIF exports.
  • Bug Fixes
    • Improved confidence accuracy by accounting for out-of-band confirmations and catch-all baseline matches, producing more reliable low-confidence labeling.
  • Tests
    • Added unit tests covering confidence tiering, corroboration, negative match behavior, baseline caching, and export formatting.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5338f994-5c6b-4845-9482-721723b27dca

📥 Commits

Reviewing files that changed from the base of the PR and between 187d855 and e3864b6.

📒 Files selected for processing (5)
  • internal/runner/runner.go
  • pkg/output/output.go
  • pkg/protocols/http/request.go
  • pkg/protocols/protocols.go
  • pkg/types/types.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • pkg/output/output.go
  • internal/runner/runner.go
  • pkg/protocols/http/request.go
  • pkg/protocols/protocols.go
  • pkg/types/types.go

Walkthrough

Adds deterministic confidence scoring, an optional per-host baseline probe for catch-all matches, and confidence tier/score propagation into result events and report outputs.

Changes

Confidence scoring and baseline detection

Layer / File(s) Summary
Scoring model and matcher classification
pkg/operators/confidence.go, _typos.toml
Adds confidence tiers, matcher classification helpers, and the operator scoring algorithm.
Scorer validation
pkg/operators/confidence_test.go
Tests confidence tiers, corroboration, negative matchers, multi-pattern bonuses, protocol-part classification, and score boundaries.
Baseline cache and HTTP probe
pkg/protocols/common/baseline/*, pkg/protocols/http/baseline.go
Adds per-host baseline caching, HTTP control requests, baseline replay, and cache tests.
Baseline option and execution wiring
cmd/nuclei/main.go, internal/runner/runner.go, pkg/types/types.go, pkg/protocols/protocols.go, pkg/protocols/http/request.go
Adds the confidence-baseline option, propagates the cache through execution, and marks baseline matches.
Result confidence propagation and output
pkg/output/*, pkg/protocols/protocols.go, pkg/protocols/http/operators_test.go, pkg/reporting/*
Computes confidence metadata, applies out-of-band and baseline overrides, serializes results, and renders confidence in screen, report, PDF, and SARIF outputs.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: dogancanbakir

Poem

I hop through matches, whiskers bright,
From low to high I judge each byte.
A baseline nibble, then a rabbit grin,
Catch-alls fade, confidence beams in. 🐇

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The _typos.toml OpenVAS spelling allowlist update appears unrelated to confidence scoring and the linked issue scope. Move the typo configuration change to a separate PR unless it is required for the confidence-scoring feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 58.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and directly describes the main change: confidence scoring.
Linked Issues check ✅ Passed The PR adds deterministic confidence scoring, tiers, baseline control requests, and out-of-band certainty as requested by #7505.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch nuclei-confidence

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
pkg/protocols/http/baseline.go (1)

74-83: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Control request is not tied to the scan context.

retryablehttp.NewRequest here is built without a cancellable context, so on scan shutdown an in-flight baseline probe won't be cancelled (it will rely solely on the client's transport timeout). Consider threading input's context if available, to fail fast on cancellation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/protocols/http/baseline.go` around lines 74 - 83, The baseline probe in
the control request path is not using the scan’s cancellable context, so
in-flight requests can outlive shutdown. Update the request creation in the
baseline helper around retryablehttp.NewRequest to use the context from input
(or the scan context carried by the caller) when building the GET request, so
the extra control request is cancelled promptly on scan termination. Keep the
change localized to the baseline request flow and preserve the existing
rate-limit and client.Do behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/output/format_screen.go`:
- Around line 12-22: The screen confidence rendering in
StandardWriter.confidenceColor currently collapses all values to
low/medium/high, which hides the numeric 0–100 score on CLI output. Update the
screen formatting path that calls confidenceColor so it preserves and displays
the original confidence value (for example, by passing through the numeric score
or rendering both tier and score) instead of normalizing everything to the tier
label. Use the confidenceColor helper and any caller in the screen output flow
to make sure distinct scores like low (0) and low (10) remain distinguishable.

In `@pkg/output/output.go`:
- Around line 210-211: The ConfidenceScore field in output serialization is
incorrectly tagged with omitempty, which drops valid zero values from JSON.
Update the ConfidenceScore definition in the output model so that
Operators.Confidence() can serialize a legitimate 0 score for
matcher-less/extraction-only findings, while still preserving nonzero scores;
keep the change focused on the ConfidenceScore field and related JSON output
behavior.

In `@pkg/reporting/format/format_utils.go`:
- Around line 259-267: The confidence formatting logic in formatConfidence and
the PDF exporter is incorrectly treating a score of 0 as unset, which hides
valid weakest findings. Update the conditional in formatConfidence in
format_utils.go and the matching confidence rendering in pdf.go to include any
non-negative score, so 0 is formatted as part of the confidence output. Keep the
existing tier capitalization and formatting behavior, but ensure the score check
no longer excludes 0.

---

Nitpick comments:
In `@pkg/protocols/http/baseline.go`:
- Around line 74-83: The baseline probe in the control request path is not using
the scan’s cancellable context, so in-flight requests can outlive shutdown.
Update the request creation in the baseline helper around
retryablehttp.NewRequest to use the context from input (or the scan context
carried by the caller) when building the GET request, so the extra control
request is cancelled promptly on scan termination. Keep the change localized to
the baseline request flow and preserve the existing rate-limit and client.Do
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1bdeaa5f-2ce5-4373-929f-6b5dc7401758

📥 Commits

Reviewing files that changed from the base of the PR and between 2d84075 and 187d855.

📒 Files selected for processing (19)
  • _typos.toml
  • cmd/nuclei/main.go
  • internal/runner/runner.go
  • pkg/operators/confidence.go
  • pkg/operators/confidence_test.go
  • pkg/output/format_screen.go
  • pkg/output/output.go
  • pkg/protocols/common/baseline/baseline.go
  • pkg/protocols/common/baseline/baseline_test.go
  • pkg/protocols/http/baseline.go
  • pkg/protocols/http/operators_test.go
  • pkg/protocols/http/request.go
  • pkg/protocols/protocols.go
  • pkg/reporting/exporters/pdf/pdf.go
  • pkg/reporting/exporters/sarif/sarif.go
  • pkg/reporting/exporters/sarif/sarif_test.go
  • pkg/reporting/format/format_utils.go
  • pkg/reporting/format/format_utils_test.go
  • pkg/types/types.go

Comment on lines +12 to +22
// confidenceColor colorizes the confidence tier for screen output.
func (w *StandardWriter) confidenceColor(confidence string) string {
switch confidence {
case "high":
return w.aurora.BrightGreen(confidence).String()
case "medium":
return w.aurora.BrightYellow(confidence).String()
default:
return w.aurora.BrightBlack(confidence).String()
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Screen output drops the numeric confidence score.

The new bracket only renders low|medium|high, so distinct findings like low (0) and low (10) become indistinguishable on the CLI even though this feature is supposed to surface the deterministic 0–100 score there too.

Suggested fix
-// confidenceColor colorizes the confidence tier for screen output.
-func (w *StandardWriter) confidenceColor(confidence string) string {
-	switch confidence {
+// confidenceColor colorizes confidence text using the tier color.
+func (w *StandardWriter) confidenceColor(text, tier string) string {
+	switch tier {
 	case "high":
-		return w.aurora.BrightGreen(confidence).String()
+		return w.aurora.BrightGreen(text).String()
 	case "medium":
-		return w.aurora.BrightYellow(confidence).String()
+		return w.aurora.BrightYellow(text).String()
 	default:
-		return w.aurora.BrightBlack(confidence).String()
+		return w.aurora.BrightBlack(text).String()
 	}
 }
@@
 	if output.Confidence != "" {
+		label := output.Confidence + " (" + strconv.Itoa(output.ConfidenceScore) + ")"
 		builder.WriteString("[")
-		builder.WriteString(w.confidenceColor(output.Confidence))
+		builder.WriteString(w.confidenceColor(label, output.Confidence))
 		builder.WriteString("] ")
 	}

Also applies to: 67-70

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/output/format_screen.go` around lines 12 - 22, The screen confidence
rendering in StandardWriter.confidenceColor currently collapses all values to
low/medium/high, which hides the numeric 0–100 score on CLI output. Update the
screen formatting path that calls confidenceColor so it preserves and displays
the original confidence value (for example, by passing through the numeric score
or rendering both tier and score) instead of normalizing everything to the tier
label. Use the confidenceColor helper and any caller in the screen output flow
to make sure distinct scores like low (0) and low (10) remain distinguishable.

Comment thread pkg/output/output.go
Comment on lines +210 to +211
// ConfidenceScore is the 0-100 score (QoD-style) behind Confidence.
ConfidenceScore int `json:"confidence-score,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Serialize 0 confidence scores instead of omitting them.

Operators.Confidence() legitimately returns 0 for matcher-less/extraction-only findings, so omitempty drops a valid score from JSON output and forces downstream consumers to guess whether the score was 0 or never computed.

Suggested fix
-	ConfidenceScore int `json:"confidence-score,omitempty"`
+	ConfidenceScore int `json:"confidence-score"`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// ConfidenceScore is the 0-100 score (QoD-style) behind Confidence.
ConfidenceScore int `json:"confidence-score,omitempty"`
ConfidenceScore int `json:"confidence-score"`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/output/output.go` around lines 210 - 211, The ConfidenceScore field in
output serialization is incorrectly tagged with omitempty, which drops valid
zero values from JSON. Update the ConfidenceScore definition in the output model
so that Operators.Confidence() can serialize a legitimate 0 score for
matcher-less/extraction-only findings, while still preserving nonzero scores;
keep the change focused on the ConfidenceScore field and related JSON output
behavior.

Comment on lines +259 to +267
func formatConfidence(event *output.ResultEvent) string {
tier := event.Confidence
if tier != "" {
tier = strings.ToUpper(tier[:1]) + tier[1:]
}
if event.ConfidenceScore > 0 {
return fmt.Sprintf("%s (%d)", tier, event.ConfidenceScore)
}
return tier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't treat 0 as an unset confidence score.

0 is a valid result from Operators.Confidence(), so the > 0 guard renders weakest findings as just Low instead of Low (0). That breaks the advertised 0–100 contract in report text. The same pattern also needs fixing in pkg/reporting/exporters/pdf/pdf.go Line 199-Line 201.

Suggested fix
 func formatConfidence(event *output.ResultEvent) string {
 	tier := event.Confidence
 	if tier != "" {
 		tier = strings.ToUpper(tier[:1]) + tier[1:]
 	}
-	if event.ConfidenceScore > 0 {
+	if tier != "" {
 		return fmt.Sprintf("%s (%d)", tier, event.ConfidenceScore)
 	}
-	return tier
+	return ""
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func formatConfidence(event *output.ResultEvent) string {
tier := event.Confidence
if tier != "" {
tier = strings.ToUpper(tier[:1]) + tier[1:]
}
if event.ConfidenceScore > 0 {
return fmt.Sprintf("%s (%d)", tier, event.ConfidenceScore)
}
return tier
func formatConfidence(event *output.ResultEvent) string {
tier := event.Confidence
if tier != "" {
tier = strings.ToUpper(tier[:1]) + tier[1:]
}
if tier != "" {
return fmt.Sprintf("%s (%d)", tier, event.ConfidenceScore)
}
return ""
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/reporting/format/format_utils.go` around lines 259 - 267, The confidence
formatting logic in formatConfidence and the PDF exporter is incorrectly
treating a score of 0 as unset, which hides valid weakest findings. Update the
conditional in formatConfidence in format_utils.go and the matching confidence
rendering in pdf.go to include any non-negative score, so 0 is formatted as part
of the confidence output. Keep the existing tier capitalization and formatting
behavior, but ensure the score check no longer excludes 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

confidence scoring

1 participant