Skip to content

fix(clustering): updated cluster failure handling#6843

Merged
ehsandeep merged 3 commits intoprojectdiscovery:devfrom
bf-rbrown:dev
Mar 4, 2026
Merged

fix(clustering): updated cluster failure handling#6843
ehsandeep merged 3 commits intoprojectdiscovery:devfrom
bf-rbrown:dev

Conversation

@bf-rbrown
Copy link
Contributor

@bf-rbrown bf-rbrown commented Feb 6, 2026

Proposed changes

Summary

This fixes #6842

  • Fix -matcher-status not printing [failed] output for clustered templates that use matchers-condition: and
  • Add equivalent fallback logic to ClusterExecuter that already existed in TemplateExecuter
  • Enrich synthetic failure events with proper URL-parsed fields for consistent output

Root Cause

Two issues combined to cause this:

1. ClusterExecuter failure condition too strict (pkg/templates/cluster.go)

The condition for writing failure events was result == nil && !matched. When matchers-condition: and is used and any matcher fails, operators.Execute() returns early with a non-nil Result struct but matched=false. Since result was non-nil, the nil check failed and the failure was silently dropped. For matchers-condition: or (default), operators.Execute() returns nil on failure, so failures were reported correctly. The fix relaxes the condition to only check !matched.

2. Protocol error paths not invoking the callback

When a protocol request fails early (connection error, validation error, etc.), most implementations returned an error without invoking the callback. This meant the executor had no event to report as [failed]. Added callback invocations on error paths across all protocols. For HTTP specifically, the error path previously only invoked the callback when interactsh (OOB) URLs were present -- to register the request for later OOB correlation. Since the fix requires the callback to always fire on error regardless of interactsh usage, the interactsh-specific gating was removed.

Synthetic Failure Events

TemplateExecuter already had a fallback that synthesized a fake failure event when no callback was received. Two improvements were made to it:

  • Enriched the existing fake event in TemplateExecuter (pkg/tmplexec/exec.go): The original event only set TemplateID, Info, Type, Host, and Error. The Host field was set to the raw input string (e.g. https://example.com:443), which could produce malformed output. Now uses GetJsonFieldsFromURL to properly parse the input and populate Host, Port, Scheme, URL, Path, TemplatePath, and Timestamp.

  • Added equivalent fallback to ClusterExecuter (pkg/templates/cluster.go): ClusterExecuter had no fallback at all -- if the callback was never invoked, clustered templates produced no matcher-status output. Added the same pattern: track whether the callback fires via atomic.Bool, and if not, synthesize a failure event per operator in the cluster with properly parsed URL fields.

Proof

Before (templates with matchers-condition: and missing from output):

# Run where template 2 and 3 are clustered
$ nuclei -t ./template1.yaml,./template2.,./template3.yaml -matcher-status -silent -target https://example.com
[./template1.yaml] [failed] [http] [medium] example.com

After (all templates reported):

# Run where template 2 and 3 are clustered
$ nuclei -t ./template1.yaml,./template2.yaml,./template3.yaml -matcher-status -silent -target https://example.com
[template-1] [failed] [http] [medium] example.com
[template-2] [failed] [http] [info] example.com
[template-3] [failed] [http] [info] example.com

Before (template output not returned or is minimized):

# templates clustered return no output
$ nuclei -t ./template1.yaml,./template2 -matcher-status -silent -target https://example.com
[no output]

# Isolated runs return minimized output
$ nuclei -t ./template1.yaml --matcher-status -target https://oast3.pro:443 -jsonl -silent | jq -Sc 'keys'
["error","host","info","matcher-status","template-id","timestamp","type"]

After (all templates/fields reported):

# templates clustered now return output
$ nuclei -t ./template1.yaml,./template2.yaml --matcher-status -silent -target https://oast3.pro:443
[template-1] [failed] [http] [info] oast3.pro
[template-2] [failed] [http] [info] oast3.pro

# Isolated runs return full keys
$ nuclei -t ./template1.yaml --matcher-status -silent -jsonl -target https://oast3.pro:443 | jq -Sc 'keys'
["error","host","info","matcher-status","port","request","scheme","template-encoded","template-id","template-path","timestamp","type","url"]

Before (unit tests):

$ go run ../cmd/integration-test/ -protocol matcher-status 
2026/02/06 11:46:02 Could not connect to Docker: Get "http://unix.sock/_ping": dial unix /var/run/docker.sock: connect: no such file or directory
2026/02/06 11:46:02 Could not start resource: dial unix /var/run/docker.sock: connect: no such file or directory
[✓] Test "protocols/http/get.yaml" passed!
[✓] Test "protocols/network/net-https.yaml" passed!
[✓] Test "protocols/headless/headless-basic.yaml" passed!
[✓] Test "protocols/javascript/net-https.yaml" passed!
[✓] Test "protocols/websocket/basic.yaml" passed!
[✓] Test "protocols/dns/a.yaml" passed!
[✘] Test "protocols/http/matcher-status-and.yaml,protocols/http/matcher-status-and-cluster.yaml" failed: unexpected number of results: 0 (expected 2)

After

$ go run ../cmd/integration-test/ -protocol matcher-status
2026/02/06 11:44:01 Could not connect to Docker: Get "http://unix.sock/_ping": dial unix /var/run/docker.sock: connect: no such file or directory
2026/02/06 11:44:01 Could not start resource: dial unix /var/run/docker.sock: connect: no such file or directory
[✓] Test "protocols/http/get.yaml" passed!
[✓] Test "protocols/network/net-https.yaml" passed!
[✓] Test "protocols/headless/headless-basic.yaml" passed!
[✓] Test "protocols/javascript/net-https.yaml" passed!
[✓] Test "protocols/websocket/basic.yaml" passed!
[✓] Test "protocols/dns/a.yaml" passed!
[✓] Test "protocols/http/matcher-status-and.yaml,protocols/http/matcher-status-and-cluster.yaml" passed!

Checklist

  • Pull request is created against the dev branch
  • All checks passed (lint, unit/integration/regression tests etc.) with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Summary by CodeRabbit

  • Bug Fixes

    • Consistent error reporting added across many protocols (DNS, file, headless, HTTP, JavaScript, network, SSL, WebSocket, WHOIS), improving diagnostics and observable failure events during template execution.
    • Improved cluster/template fallback: when per-operator callbacks are missed, the system now generates detailed fallback failure events to ensure failures are reported.
  • Tests

    • Added an HTTP matcher-status test harness to expand coverage for HTTP matching scenarios.

@auto-assign auto-assign bot requested a review from dogancanbakir February 6, 2026 17:54
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

Walkthrough

Adds matcher-status error reporting across many protocols and cluster/template execution: emits structured callback events on error paths and generates synthetic failure events when per-operator callbacks were not invoked; also adds an integration test validating matcher-status for clustered templates with AND-condition matchers.

Changes

Cohort / File(s) Summary
Integration Test
cmd/integration-test/matcher-status.go
Adds HTTP test harness and httpMatcherStatusAnd to verify matcher-status behavior for clustered templates using matchers-condition: and.
Cluster & Template Execution
pkg/templates/cluster.go, pkg/tmplexec/exec.go
Tracks whether per-operator callbacks ran; when not and matcher-status is enabled, generates detailed synthetic failure events (includes template metadata and URL fields) and emits them to output.
Protocol Error Callbacks (bulk)
pkg/protocols/.../{code/code.go, dns/request.go, file/request.go, headless/request.go, javascript/js.go, network/request.go, ssl/ssl.go, websocket/websocket.go, whois/whois.go}
Systematically invoke the provided matcher-status callback on error paths, wrapping host/input and error into InternalWrappedEvent/InternalEvent to surface failures to matcher-status for many protocols.
HTTP Protocol Refinement
pkg/protocols/http/request.go
Changed error handling to always invoke the callback (using InternalWrappedEvent), removing conditional behavior tied to interactsh/DSL, ensuring consistent error reporting across HTTP requests.
Manifest
go.mod
Minor dependency/import adjustments referenced by other changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through templates, sniffed the trace,
Found silent failures hiding in a clustered place.
I thumped my paw, rang callbacks far and near,
Now every miss is spotted — loud and clear.
Hop, patch, and celebrate with a carrot cheer! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR comprehensively addresses all requirements from issue #6842: fixes cluster failure condition logic, ensures protocol error paths invoke callbacks consistently, adds fallback synthetic failure event generation, enriches output with full JSON fields, and includes integration tests.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fix issue #6842: clustering failure handling, callback invocations across protocol modules, synthetic event generation, and related integration tests. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The PR title directly describes the main change: updating cluster failure handling to fix clustered template matcher-status reporting.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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 and usage tips.

@bf-rbrown
Copy link
Contributor Author

I thought I fixed the change that is erroring; I'm investigating.

@bf-rbrown bf-rbrown marked this pull request as draft February 6, 2026 20:32
@bf-rbrown
Copy link
Contributor Author

Okay, I reverted the call backs; but my fix for the clustered output is still valid.

@bf-rbrown bf-rbrown marked this pull request as ready for review February 6, 2026 21:08
@auto-assign auto-assign bot requested a review from dwisiswant0 February 6, 2026 21:08
@dwisiswant0
Copy link
Member

The failing integration test is flaky and doesn't seem to be related to this change at all.

@dwisiswant0 dwisiswant0 changed the title fix(clustering): updated cluster failure handling and mock output fix(clustering): updated cluster failure handling Feb 10, 2026
Copy link
Member

@dwisiswant0 dwisiswant0 left a comment

Choose a reason for hiding this comment

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

Banger.

@bf-rbrown
Copy link
Contributor Author

Banger.

Thank you!

Is there anything else you need from me to get this over the finish line?

@bf-rbrown
Copy link
Contributor Author

@dwisiswant0 good afternoon! Sorry for the ping. I just wanted to checkin on this one. Is it waiting on something from me?

@bf-rbrown
Copy link
Contributor Author

Good afternoon, @dogancanbakir! I just wanted to check in on this ask 😄.

Copy link
Member

@ehsandeep ehsandeep left a comment

Choose a reason for hiding this comment

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

@bf-rbrown apologies for the delay, and thanks for helping improve this feature.

@ehsandeep ehsandeep merged commit 51205f8 into projectdiscovery:dev Mar 4, 2026
16 of 19 checks passed
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.

[BUG] clustered templates does not report failed matches for templates with matchers-condition set to and

3 participants