Skip to content

Fix custom detector verification: add configurable success ranges, and inconclusive state#4821

Open
shahzadhaider1 wants to merge 8 commits intotrufflesecurity:mainfrom
shahzadhaider1:INS-408-custom-detectors-verification-logic-update
Open

Fix custom detector verification: add configurable success ranges, and inconclusive state#4821
shahzadhaider1 wants to merge 8 commits intotrufflesecurity:mainfrom
shahzadhaider1:INS-408-custom-detectors-verification-logic-update

Conversation

@shahzadhaider1
Copy link
Copy Markdown
Contributor

@shahzadhaider1 shahzadhaider1 commented Mar 17, 2026

Summary

Fixes two issues with custom detector verification that caused false negatives and poor resilience against transient failures:

  • Configurable success status codes: Wired up the existing but unused successRanges field on VerifierConfig. Users can now specify status codes (e.g. "403") or ranges (e.g. "200-299") that count as verified. Defaults to 200 only when no ranges are configured (backward compatible). Validation via ValidateVerifyRanges is now called during detector initialization.
  • Inconclusive state via SetVerificationError: Network failures and timeouts now call result.SetVerificationError(err) instead of silently leaving Verified = false. This marks the result as "unknown" (inconclusive) rather than definitively unverified, preventing false negatives. A subsequent verify config that responds with a clear non-success status will clear the error via ClearVerificationError(). This matches the three-state model used by built-in detectors (Slack, SendGrid, OpenAI, etc.) and integrates with the existing --results=unknown filtering in the engine.

Changes

  • pkg/custom_detectors/custom_detectors.go: success ranges check, verification error handling, isStatusInRanges helper
  • pkg/detectors/detectors.go: added ClearVerificationError() method on Result
  • pkg/custom_detectors/custom_detectors_test.go: tests for success ranges, verification error on network failure, error clearing on definitive rejection, invalid range validation

Checklist:

  • Tests passing (make test-community)?
  • Lint passing (make lint this requires golangci-lint)?

Note

Medium Risk
Changes custom detector verification semantics (what counts as verified and how failures are reported), which can affect scan results and downstream filtering, but is scoped and covered by new tests.

Overview
Custom webhook verification for custom detectors now treats HTTP success as configurable status codes/ranges via successRanges (single codes like 403 or inclusive ranges like 200-299), defaulting to 200 when unspecified.

Verification now records inconclusive outcomes: network/timeout errors call Result.SetVerificationError, while definitive non-success responses clear any prior error; verified responses also clear prior errors. This adds Result.ClearVerificationError() and introduces targeted tests for range matching, default behavior, error setting/clearing across multiple verifier configs, and invalid range validation.

Reviewed by Cursor Bugbot for commit 4386c31. Bugbot is set up for automated code reviews on this repo. Configure here.

@shahzadhaider1 shahzadhaider1 requested a review from a team March 17, 2026 16:27
@shahzadhaider1 shahzadhaider1 requested a review from a team as a code owner March 17, 2026 16:27
}

// ClearVerificationError resets the verification error to nil.
func (r *Result) ClearVerificationError() {
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.

I do not understand the purpose of this? Why would we want to add a verification error to the result and than remove it later? In which scenarios this will be useful?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@shahzadhaider1 shahzadhaider1 changed the title Fix custom detector verification: add retry, configurable success ranges, and inconclusive state Fix custom detector verification: add configurable success ranges, and inconclusive state Mar 27, 2026
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

// Clear any previous verification error (e.g. from an earlier
// config that had a network failure) since this endpoint gave
// a clear answer.
result.ClearVerificationError()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Non-success statuses all treated as definitive rejection

Medium Severity

Every HTTP response not matching successRanges unconditionally calls ClearVerificationError(), treating it as a definitive rejection. However, transient server errors (500, 502, 503, 429, etc.) don't actually indicate the credential is invalid — they're inconclusive, just like network failures. Built-in detectors (e.g. abstract.go) call SetVerificationError for unexpected status codes and only treat specific codes like 401 as definitive. This gap means server-side transient errors produce false negatives instead of the "unknown/inconclusive" state the PR intends to introduce.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Valid point. The counterargument is that for custom detectors (unlike built-in ones like OpenAI/SendGrid), we don't know the webhook's API contract; successRanges is the only thing the user defines, so anything outside it could be argued as "not success."

That said, there's a real gap: if a secret was verified as live in scan 1, and scan 2 hits a 429/5xx from the webhook, the current code marks it as definitively not verified; a false negative on a live secret. These status codes are universally understood as transient, not credential-validity answers, so treating them as inconclusive does make sense.

A clean fix could be adding an inconclusiveRanges config alongside successRanges, keeping it fully user-controlled without us making assumptions. Curious what the team thinks.

// Network failure / timeout: mark as inconclusive.
result.SetVerificationError(err)
continue
}
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.

Getting past this condition, we can clear the verification error since we're either getting a success or failure status after this point.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good observation. ClearVerificationError() does get called for every HTTP response, regardless of status. We could consolidate it above the status check. I kept it in both branches for readability; each documents a different reason for clearing (verified vs definitive rejection)--but happy to move it up if you feel strongly.

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.

4 participants