Skip to content

Conversation

@dwisiswant0
Copy link
Member

@dwisiswant0 dwisiswant0 commented Oct 30, 2024

Proposed changes

Close #5692

How has this been tested?

# tty1
/path/to/chrome --headless --remote-debugging-port=9222 --ignore-certificate-errors --ignore-ssl-errors
# tty2
go run cmd/nuclei/main.go -headless -t headless-template-1.yaml -u http://scanme.sh -cdp-endpoint "CHROME_DEVTOOLS_ENDPOINT_URL"

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

  • New Features

    • Added a CLI option to connect to a remote browser via a Chrome DevTools Protocol (CDP) endpoint.
  • Refactor

    • Initialization and shutdown now distinguish local vs. remote browser usage, skipping local launch and cleanup when a remote CDP endpoint is used.
  • Documentation

    • Updated HEADLESS docs across locales to document the new CDP endpoint option.

@auto-assign auto-assign bot requested a review from dogancanbakir October 30, 2024 13:19
@dwisiswant0
Copy link
Member Author

But I’m unable to connect to the CDP URL provided by finic:

[FTL] Could not create runner: websocket bad handshake: 400 Bad Request. Failed to open a WebSocket connection: invalid Sec-WebSocket-Key header: nil; Incorrect padding.

Not sure if this is an issue with go-rod or with finic. It needs further investigation, or maybe even a hacky workaround. I’ll try testing it via Playwright - if the issue can’t be reproduced there, I’ll go ahead and raise it as an issue in go-rod.

Copy link
Member Author

Choose a reason for hiding this comment

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

--flag=true eq to --flag=1 eq to --flag

@dwisiswant0
Copy link
Member Author

Works with browserless.

image

Seems like the issue is within finic.

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.

$ ./nuclei -u http://scanme.sh -cdp-endpoint "ws://localhost:3000" -headless -pt headless

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.3.5

		projectdiscovery.io

[INF] Current nuclei version: v3.3.5 (latest)
[INF] Current nuclei-templates version: v10.0.3 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 116
[INF] Templates loaded for current scan: 18
[INF] Executing 18 signed templates from projectdiscovery/nuclei-templates
[INF] Targets loaded for current scan: 1
[extract-urls] [headless] [info] http://scanme.sh [""]
[piratebay] [headless] [info] https://thepiratebay.org/search.php?q=user:{{user}}
[INF] Screenshot successfully saved at /Users/geekboy/Github/nuclei/screenshots/http:__scanme.sh.png
panic: invalid character 'T' looking for beginning of value

goroutine 72 [running]:
github.com/go-rod/rod/lib/utils.glob..func2({0x103f959c0?, 0x140181cc570?})
	/Users/geekboy/go/pkg/mod/github.com/go-rod/[email protected]/lib/utils/utils.go:68 +0x24
github.com/go-rod/rod/lib/utils.E(...)
	/Users/geekboy/go/pkg/mod/github.com/go-rod/[email protected]/lib/utils/utils.go:74
github.com/go-rod/rod/lib/cdp.(*Client).consumeMessages(0x1400043f680)
	/Users/geekboy/go/pkg/mod/github.com/go-rod/[email protected]/lib/cdp/client.go:148 +0x104
created by github.com/go-rod/rod/lib/cdp.(*Client).Start in goroutine 1
	/Users/geekboy/go/pkg/mod/github.com/go-rod/[email protected]/lib/cdp/client.go:76 +0x88

@dwisiswant0
Copy link
Member Author

dwisiswant0 commented Nov 3, 2024

@ehsandeep - If we look at the trace, it doesn't seem related to our source code - the underlying issue is in go-rod. Also, this panic wouldn't happen if we were using the system CDP.

$ go run cmd/nuclei/main.go -u http://scanme.sh -cdp-endpoint "ws://*********:9222/devtools/browser/************************************" -headless -pt headless

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.3.5

		projectdiscovery.io

[INF] Current nuclei version: v3.3.5 (latest)
[INF] Current nuclei-templates version: v10.0.3 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 116
[INF] Templates loaded for current scan: 18
[INF] Executing 18 signed templates from projectdiscovery/nuclei-templates
[INF] Targets loaded for current scan: 1
[piratebay] [headless] [info] https://thepiratebay.org/search.php?q=user:{{user}}
[extract-urls] [headless] [info] http://scanme.sh [""]

@dwisiswant0
Copy link
Member Author

We either need to tweak the Browserless container or there's something on our end that needs to be handled - but we need to figure out the root cause (template) that's triggering that panic.

@github-actions
Copy link

This pull request has been automatically marked as stale due to inactivity. It will be closed in 7 days if no further activity occurs. Please update if you wish to keep it open.

@github-actions github-actions bot added the Status: Stale This issue/PR has been inactive for a while and may be closed soon if no further activity occ label Jul 20, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 20, 2025

Walkthrough

A new cdp-endpoint CLI flag and CDPEndpoint option were added. The headless browser engine now conditionally uses the provided CDP WebSocket URL instead of launching a local Chrome instance; initialization and cleanup are skipped when connecting to a remote CDP endpoint.

Changes

Cohort / File(s) Change Summary
CLI flag
cmd/nuclei/main.go
Added cdp-endpoint (cdpe) CLI flag bound to options.CDPEndpoint.
Options struct
pkg/types/types.go
Added CDPEndpoint string field to Options.
Headless engine
pkg/protocols/headless/engine/engine.go
Refactored New and Close to: when CDPEndpoint is set, use it as the launcher URL and skip local Chrome launch, temp dir creation, musl detection, launcher setup, and local cleanup; otherwise preserve existing local launch and cleanup logic. Proxy and extra args apply only to local launches.
Documentation
README.md, README_CN.md, README_ES.md, README_ID.md, README_KR.md, README_PT-BR.md
Added or adjusted HEADLESS section entries to document -cdpe, -cdp-endpoint flag (formatting/content updates across locales).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant Engine
    participant Browser

    User->>CLI: nuclei --cdp-endpoint ws://host:port
    CLI->>Engine: Pass Options (CDPEndpoint set)
    alt CDP endpoint provided
        Engine->>Browser: Connect to provided CDP WebSocket URL
        Note right of Engine #f9f0c1: Skip temp dir creation\nSkip launching local Chrome
        User->>Engine: Perform headless actions
        Engine->>Browser: Send CDP commands over WebSocket
        User->>Engine: Close()
        Engine-->>Browser: Do not terminate remote browser (leave running)
    else No CDP endpoint
        Engine->>Engine: Create temp dir & configure launcher
        Engine->>Browser: Launch local Chrome process
        User->>Engine: Perform headless actions
        Engine->>Browser: Send CDP commands
        User->>Engine: Close()
        Engine->>Browser: Terminate Chrome process and cleanup
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective (issue #5692) Addressed Explanation
Add cdp-endpoint flag to accept a WebSocket/CDP URL for headless mode Flag and Options field added.
Use provided CDP WebSocket URL to connect to existing/remote browser Engine uses provided URL instead of launching Chrome.
Allow users to keep remote browser lifecycle external (skip terminating remote) Close() skips terminating remote browser when CDP endpoint used.
Remove chromium dependency / make base image scratch (optional) Local launch path and related launcher code remain; chromium removal not addressed.

Poem

I’m a rabbit by the CDP shore,
I hop to ws:// and ask for more. 🐇
No local launch, just websockets spun,
Commands go out — the tabs have fun.
I close my paws, the remote stays on.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "feat(headless): add cdp-endpoint option" succinctly and accurately describes the main change of adding the CDP endpoint flag to the headless mode, following conventional commit conventions and clearly indicating the feature scope.
Linked Issues Check ✅ Passed The changes add the CDPEndpoint field to the Options struct, bind it as a CLI flag, conditionally use the provided WebSocket URL in the headless engine initialization and cleanup logic, and update documentation accordingly, thereby fulfilling the objectives of issue #5692 to enable remote CDP endpoint connections in headless mode.
Out of Scope Changes Check ✅ Passed All code and documentation changes directly relate to introducing and supporting the cdp-endpoint option and its conditional handling in the headless engine, with no modifications detected outside the scope of the linked feature request.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dwisiswant0/feat/headless/cdp-endpoint-option

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fef94a and 0c8fb50.

📒 Files selected for processing (6)
  • README.md (1 hunks)
  • README_CN.md (1 hunks)
  • README_ES.md (1 hunks)
  • README_ID.md (1 hunks)
  • README_KR.md (1 hunks)
  • README_PT-BR.md (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • README_PT-BR.md
  • README.md

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

@dwisiswant0 dwisiswant0 removed the Status: Stale This issue/PR has been inactive for a while and may be closed soon if no further activity occ label Jul 21, 2025
Copy link
Member

@dogancanbakir dogancanbakir left a comment

Choose a reason for hiding this comment

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

  • build fails
  • merge conflict

@dwisiswant0 dwisiswant0 force-pushed the dwisiswant0/feat/headless/cdp-endpoint-option branch from e725cd3 to 9fef94a Compare September 8, 2025 10:28
@dwisiswant0
Copy link
Member Author

@Deamhan
Copy link
Contributor

Deamhan commented Nov 1, 2025

Very cool and useful functionality, I hope it'll become part of upstream. The only missing thing here is no incognito mode which could be highly useful. Currently upstream has the following from (called from executeRequestWithPayloads)

func (b *Browser) NewInstance() (*Instance, error) {
browser, err := b.engine.Incognito()
if err != nil {
return nil, err
}

and it's not configurable. If we switch to something like

func (b *Browser) NewInstance() (*Instance, error) {
var browser *rod.Browser
if b.options.HeadlessNoIncognito {
// Use the existing browser directly instead of creating an incognito instance
browser = b.engine
} else {
var err error
browser, err = b.engine.Incognito()
if err != nil {
return nil, err
}
}

we could get much more flexible result. Of course it can be added separetely. Correct me if I'm wrong :-)

@dwisiswant0
Copy link
Member Author

[...] The only missing thing here is no incognito mode which could be highly useful. [...]

Since we’re connecting via Chrome DevTools Proto URL (browser’s already live), flags don’t take effect after launch [and are not controllable from the source], right? They’re static, hence any flag changes won’t apply.

I’m not 100% certain. AFK rn, will PoC later to confirm.

@Deamhan
Copy link
Contributor

Deamhan commented Nov 6, 2025

Since we’re connecting via Chrome DevTools Proto URL (browser’s already live), flags don’t take effect after launch [and are not controllable from the source], right? They’re static, hence any flag changes won’t apply.

I’m not 100% certain. AFK rn, will PoC later to confirm.

I was talking about request.go#L115 - as I see for such requests we create a new instance of browser based on existing one instance.go#L30 no matter if it's provided CDP or not - correct me if I'm wrong. If we want to use the same instance a minor modification is required like I mentioned before - something like avoid of browser, err = b.engine.Incognito(). For production usecase I added this modification and the result works like a charm :-)

@dogancanbakir dogancanbakir marked this pull request as draft November 25, 2025 04:07
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.

[FEATURE] Add cdp-endpoint Option for Controlling WebSocket Endpoint in Headless Mode

6 participants