From 99261dfd65ccf5daec4a985e00851d2d814582de Mon Sep 17 00:00:00 2001 From: Dwi Siswanto Date: Fri, 27 Feb 2026 09:48:37 +0700 Subject: [PATCH] fix(headless): avoid cross-test chrome teardown races Drop global Chrome process sweeping from browser shutdown. The `previousPIDs` snapshot + delta kill logic is unsafe on shared/parallel runners: a test can classify another test's Chrome as "new" and kill it during `(*Browser).Close()`, triggering intermittent Rod panics (use of closed network connection). Signed-off-by: Dwi Siswanto --- pkg/protocols/headless/engine/engine.go | 7 ------- pkg/protocols/headless/engine/page_actions_test.go | 5 ++++- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/pkg/protocols/headless/engine/engine.go b/pkg/protocols/headless/engine/engine.go index 0d2a75786c..ff663528bf 100644 --- a/pkg/protocols/headless/engine/engine.go +++ b/pkg/protocols/headless/engine/engine.go @@ -15,7 +15,6 @@ import ( "github.com/projectdiscovery/nuclei/v3/pkg/types" fileutil "github.com/projectdiscovery/utils/file" osutils "github.com/projectdiscovery/utils/os" - processutil "github.com/projectdiscovery/utils/process" ) // Browser is a browser structure for nuclei headless module @@ -23,7 +22,6 @@ type Browser struct { customAgent string defaultHeaders map[string]string tempDir string - previousPIDs map[int32]struct{} // track already running PIDs engine *rod.Browser options *types.Options launcher *launcher.Launcher @@ -36,14 +34,11 @@ type Browser struct { // New creates a new nuclei headless browser module func New(options *types.Options) (*Browser, error) { var launcherURL, dataStore string - var previousPIDs map[int32]struct{} var err error chromeLauncher := launcher.New() if options.CDPEndpoint == "" { - previousPIDs = processutil.FindProcesses(processutil.IsChromeProcess) - dataStore, err = os.MkdirTemp("", "nuclei-*") if err != nil { return nil, errors.Wrap(err, "could not create temporary directory") @@ -135,7 +130,6 @@ func New(options *types.Options) (*Browser, error) { httpClientOnce: &sync.Once{}, launcher: chromeLauncher, } - engine.previousPIDs = previousPIDs return engine, nil } @@ -199,5 +193,4 @@ func (b *Browser) Close() { _ = b.engine.Close() b.launcher.Kill() _ = os.RemoveAll(b.tempDir) - processutil.CloseProcesses(processutil.IsChromeProcess, b.previousPIDs) } diff --git a/pkg/protocols/headless/engine/page_actions_test.go b/pkg/protocols/headless/engine/page_actions_test.go index 59ff75ef9e..bbd95de366 100644 --- a/pkg/protocols/headless/engine/page_actions_test.go +++ b/pkg/protocols/headless/engine/page_actions_test.go @@ -41,7 +41,10 @@ func TestActionNavigate(t *testing.T) { testHeadlessSimpleResponse(t, response, actions, 60*time.Second, func(page *Page, err error, out ActionData) { require.Nilf(t, err, "could not run page actions") - require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly") + require.NotNil(t, page, "page should not be nil") + info, infoErr := page.Page().Info() + require.NoError(t, infoErr, "could not fetch page info") + require.Equal(t, "Nuclei Test Page", info.Title, "could not navigate correctly") }) }