Skip to content

maint release - #2596

Merged
ehsandeep merged 11 commits into
mainfrom
dev
Sep 8, 2026
Merged

maint release#2596
ehsandeep merged 11 commits into
mainfrom
dev

Conversation

@ehsandeep

Copy link
Copy Markdown
Member

No description provided.

rivalsxninjax1 and others added 6 commits September 1, 2026 00:28
wappalyzer's display names often carry a vendor prefix that the CPE
dictionary's bare product name omits (e.g. 'Apache Tomcat' vs CPE
product 'tomcat'), or the reverse. The exact-match lookup in
lookupTechVersion can never bridge that gap, so the CPE version field
stays '*' even when the version is known.

Add a length-guarded substring fallback: if no exact key matches,
check whether a CPE product's lookup key is a substring of (or
contains) a detected technology's normalized name, requiring both
sides to be at least 5 chars to avoid false positives on short
generic keys.

Fixes #2550
CodeRabbit flagged two real issues in the substring-fallback approach:

1. False positives - 'react' is a character-for-character substring
   of 'preact', so the two would be wrongly conflated.
2. Nondeterminism - iterating a Go map in the substring fallback meant
   an ambiguous match could resolve differently across runs.

Replace substring containment with whole-word token matching:
technologyTokens() splits names on non-alphanumeric boundaries instead
of concatenating them, so 'react' and 'preact' never share a token.
buildTechVersionTokenIndex() builds the token->version map once and
drops any token that maps to conflicting versions, the same
ambiguity-safe pattern buildTechVersionMap already uses for exact
names - so results no longer depend on map iteration order.

Also excludes ~25 generic words (framework, suite, commerce, etc.)
that are too common across unrelated products to trust as a sole
match, and raises the minimum token length from 4 to 5.

Verified against the real wappalyzergo + awesome-search-queries
datasets: still recovers 58 of 91 previously-broken shared-CPE pairs,
with zero known false-positive collisions.
…tching

fix(cpe): substring fallback for vendor-prefix mismatches (#2550)
* fix: retry over https when a plaintext probe is rejected for missing TLS

Ports above 1024 are probed as plain HTTP first, and the scheme retry
only fires on a transport error. A TLS listener answers a plaintext
request with a perfectly valid HTTP 400 saying TLS is required, so
err == nil, the retry never happens, and a TLS-only service is reported
as plain http with a 400 and no title or technologies.

Detect that response and reuse the existing scheme retry. Only the
distinctive server phrasings count (nginx, Netty, Apache, HAProxy); a
bare "400 Bad Request" is a legitimate HTTP answer and is left alone, so
the extra request is limited to targets that already told us to use TLS.

Downstream this mattered: consumers that persist the probed scheme were
recording TLS-only ports as http assets, and every HTTP-based scan of
those targets then ran over plaintext and matched nothing.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* refactor: fold the TLS retry test into runner_test.go

Tests for runner.go belong in runner_test.go; a per-scenario file drifts
away from the code it covers. Also cut the four-line preamble on the
retry down to the one fact that is not already on the next line.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* fix(test): check the error from server.Serve

errcheck flagged the unchecked Serve in the TLS-only test listener. It
always returns io.EOF there, since the listener yields a single
connection, so discard it explicitly.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* refactor: let the TLS handshake decide the scheme, not the error text

Matching the server's rejection wording only worked for the phrasings we
had seen; nginx, Netty, Apache and HAProxy each word it differently and
a titleless 400 matched nothing. Trigger the upgrade on the shape of the
exchange instead — a plaintext probe answered 400 — and let the TLS
handshake settle it: if TLS works the port is https, and if it does not
the existing scheme fallback recovers the original http result.

This also stops the upgrade consuming the single retry budget, so a
target whose https attempt fails is no longer left without a result.

Drops respondsOnlyOverTLS and its signal list.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* docs: cut the TLS upgrade comment to the fact that is not in the code

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* fix(test): read the request before the listener answers

TestPlainHTTPPortStaysHTTP wrote its 400 on accept, before the client
had finished sending. Go discards a reply that arrives on a channel it
has not spoken on ("unsolicited response"), so the result went missing
and the assertion saw zero results. It passed locally on timing luck and
failed on all three CI runners.

Read the request head first, with a deadline so a silent client cannot
park the goroutine. The TLS listener's plaintext branch had the same
dependency and is fixed alongside.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* fix: do not attempt the TLS upgrade in unsafe mode

Unsafe mode bypasses the scheme fallback, so the upgrade had nothing to
fall back to: a plain HTTP service answering 400 lost its result
entirely rather than being reported as http. The rfc-path integration
tests cover exactly that shape and caught it.

Verified locally: `-unsafe` against a plain HTTP 400 went from 0 results
back to 1, and both integration tests pass.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* chore: restore ports_optimization_test.go to dev

Removing the string-matching test left a trailing blank-line diff, which
is noise in review. The helper it covered is gone with the phrase list,
so both ports_optimization files are unchanged from dev now.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* fix: keep the plaintext response until the HTTPS attempt succeeds

Review found that the upgrade discarded a successful HTTP 400 before
trying HTTPS, and the error path then issued a fresh HTTP request rather
than restoring it. A transient, one-shot or rate-limited service could
answer once, fail the HTTPS attempt, fail the repeat request, and vanish
from the output despite having been reachable.

Hold the plaintext response and restore it on any HTTPS failure, so no
second HTTP request is made and nothing is lost.

An earlier revision gated the upgrade on a TLS handshake preflight. That
is dropped: the HTTPS request opens with the same handshake, so the
preflight only duplicated it on the success path, and dialling outside
the client bypassed transport.Proxy and CONNECT while reimplementing
CustomIP and TLS impersonation. Going through the normal client path
inherits all of it.

Tests: a cleartext service that answers 400 exactly once and refuses
afterwards, and one whose TLS handshake succeeds before it closes
without an HTTP response. Both must still be reported as http.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* fix: restore the URL alongside the retained plaintext response

Review found that the restore left URL as the object built for the failed
HTTPS attempt, so SupportHTTP2 received protocol "http" with an https
URL, and the stored-response filename hashed the https form for a result
reported as http. URL is cloned before the upgrade and restored with the
response; the comment claiming resp, req and protocol were the whole of
the downstream state was wrong and is corrected.

Adds the handshake-success-then-close test that the previous message
claimed was present and was not: TLS completes, the connection closes
without an HTTP response, and the cleartext service answers only once.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* test: cover restored scheme in HTTP/2 probe

* fix: address PR review comments
* chore: require a tlsx version that exists on GitHub

tlsx v1.3.1 and v1.3.2 are cached in the Go module proxy but their tags
were deleted from GitHub, so anyone whose GOPRIVATE or GONOSUMDB routes
projectdiscovery modules around the proxy cannot resolve them:

    go: github.com/projectdiscovery/tlsx@v1.3.2: invalid version:
        unknown revision v1.3.2

v1.3.0 is a live tag whose commit is a descendant of the one v1.3.2
pointed at, so this loses nothing - the two share an identical go.mod
hash.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* chore: drop the stale tlsx v1.3.2 go.sum entries

go.sum still carried hashes for the version that was replaced, which
left the module graph inconsistent and failed lint with "no go files to
analyze: running `go mod tidy` may solve the problem".

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 0fe5b680-5ba5-43e6-b354-43d4388aaf9c

* chore: require tlsx v1.4.0

v1.4.0 is the first tlsx release whose GitHub tag and module-proxy record
agree, so it resolves on both fetch paths. It supersedes v1.3.0 (tag moved
after publication) and v1.3.1/v1.3.2 (tags deleted), all of which left dev
unbuildable for anyone whose GOPRIVATE bypasses the proxy.

Claude-Session: https://claude.ai/code/session_015AKXsNzjd3HjGMq4B8JCNH
Claude-Local-Session: claude --resume 6d6d6d7c-ada6-47f9-8739-1b416e252b29
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 893df2db-94ee-4ada-b5fb-6f67252c9a62

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

dependabot Bot and others added 5 commits September 8, 2026 18:54
…12 updates (#2592)

Bumps the projectdiscovery group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/projectdiscovery/cdncheck](https://github.com/projectdiscovery/cdncheck) | `1.2.50` | `1.2.51` |
| [github.com/projectdiscovery/clistats](https://github.com/projectdiscovery/clistats) | `0.1.5` | `0.1.6` |
| [github.com/projectdiscovery/dsl](https://github.com/projectdiscovery/dsl) | `0.8.21` | `0.8.22` |
| [github.com/projectdiscovery/fastdialer](https://github.com/projectdiscovery/fastdialer) | `0.5.18` | `0.5.19` |
| [github.com/projectdiscovery/goflags](https://github.com/projectdiscovery/goflags) | `0.1.76` | `0.2.1` |
| [github.com/projectdiscovery/rawhttp](https://github.com/projectdiscovery/rawhttp) | `0.1.91` | `0.1.92` |
| [github.com/projectdiscovery/retryablehttp-go](https://github.com/projectdiscovery/retryablehttp-go) | `1.3.24` | `1.3.25` |
| [github.com/projectdiscovery/useragent](https://github.com/projectdiscovery/useragent) | `0.0.108` | `0.0.109` |
| [github.com/projectdiscovery/utils](https://github.com/projectdiscovery/utils) | `0.11.2` | `0.11.3` |
| [github.com/projectdiscovery/wappalyzergo](https://github.com/projectdiscovery/wappalyzergo) | `0.2.95` | `0.2.96` |



Updates `github.com/projectdiscovery/cdncheck` from 1.2.50 to 1.2.51
- [Release notes](https://github.com/projectdiscovery/cdncheck/releases)
- [Commits](projectdiscovery/cdncheck@v1.2.50...v1.2.51)

Updates `github.com/projectdiscovery/clistats` from 0.1.5 to 0.1.6
- [Release notes](https://github.com/projectdiscovery/clistats/releases)
- [Commits](projectdiscovery/clistats@v0.1.5...v0.1.6)

Updates `github.com/projectdiscovery/dsl` from 0.8.21 to 0.8.22
- [Release notes](https://github.com/projectdiscovery/dsl/releases)
- [Commits](projectdiscovery/dsl@v0.8.21...v0.8.22)

Updates `github.com/projectdiscovery/fastdialer` from 0.5.18 to 0.5.19
- [Release notes](https://github.com/projectdiscovery/fastdialer/releases)
- [Commits](projectdiscovery/fastdialer@v0.5.18...v0.5.19)

Updates `github.com/projectdiscovery/goflags` from 0.1.76 to 0.2.1
- [Release notes](https://github.com/projectdiscovery/goflags/releases)
- [Commits](projectdiscovery/goflags@v0.1.76...v0.2.1)

Updates `github.com/projectdiscovery/hmap` from 0.0.101 to 0.0.102
- [Release notes](https://github.com/projectdiscovery/hmap/releases)
- [Commits](projectdiscovery/hmap@v0.0.101...v0.0.102)

Updates `github.com/projectdiscovery/networkpolicy` from 0.1.47 to 0.1.48
- [Release notes](https://github.com/projectdiscovery/networkpolicy/releases)
- [Commits](projectdiscovery/networkpolicy@v0.1.47...v0.1.48)

Updates `github.com/projectdiscovery/rawhttp` from 0.1.91 to 0.1.92
- [Release notes](https://github.com/projectdiscovery/rawhttp/releases)
- [Commits](projectdiscovery/rawhttp@v0.1.91...v0.1.92)

Updates `github.com/projectdiscovery/retryablehttp-go` from 1.3.24 to 1.3.25
- [Release notes](https://github.com/projectdiscovery/retryablehttp-go/releases)
- [Commits](projectdiscovery/retryablehttp-go@v1.3.24...v1.3.25)

Updates `github.com/projectdiscovery/useragent` from 0.0.108 to 0.0.109
- [Release notes](https://github.com/projectdiscovery/useragent/releases)
- [Commits](projectdiscovery/useragent@v0.0.108...v0.0.109)

Updates `github.com/projectdiscovery/utils` from 0.11.2 to 0.11.3
- [Release notes](https://github.com/projectdiscovery/utils/releases)
- [Changelog](https://github.com/projectdiscovery/utils/blob/main/CHANGELOG.md)
- [Commits](projectdiscovery/utils@v0.11.2...v0.11.3)

Updates `github.com/projectdiscovery/wappalyzergo` from 0.2.95 to 0.2.96
- [Release notes](https://github.com/projectdiscovery/wappalyzergo/releases)
- [Commits](projectdiscovery/wappalyzergo@v0.2.95...v0.2.96)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/cdncheck
  dependency-version: 1.2.51
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/clistats
  dependency-version: 0.1.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/dsl
  dependency-version: 0.8.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/fastdialer
  dependency-version: 0.5.19
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/goflags
  dependency-version: 0.2.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/hmap
  dependency-version: 0.0.102
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/networkpolicy
  dependency-version: 0.1.48
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/rawhttp
  dependency-version: 0.1.92
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/retryablehttp-go
  dependency-version: 1.3.25
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/useragent
  dependency-version: 0.0.109
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/utils
  dependency-version: 0.11.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
- dependency-name: github.com/projectdiscovery/wappalyzergo
  dependency-version: 0.2.96
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: projectdiscovery
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(ci): update CodeQL actions

* ci: validate CodeQL workflow changes
…0 in the external group (#2576)

chore(deps): bump github.com/PuerkitoBio/goquery in the external group

Bumps the external group with 1 update: [github.com/PuerkitoBio/goquery](https://github.com/PuerkitoBio/goquery).


Updates `github.com/PuerkitoBio/goquery` from 1.12.0 to 1.13.0
- [Release notes](https://github.com/PuerkitoBio/goquery/releases)
- [Commits](PuerkitoBio/goquery@v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: github.com/PuerkitoBio/goquery
  dependency-version: 1.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: external
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@ehsandeep
ehsandeep merged commit 4b6a9a9 into main Sep 8, 2026
6 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.

5 participants