Repository navigation
Conversation
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.16.4 to 0.16.6. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.16.4...0.16.6) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.16.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [pytest-env](https://github.com/pytest-dev/pytest-env) from 1.7.0 to 1.7.1. - [Release notes](https://github.com/pytest-dev/pytest-env/releases) - [Commits](pytest-dev/pytest-env@1.7.0...1.7.1) --- updated-dependencies: - dependency-name: pytest-env dependency-version: 1.7.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [lxml](https://github.com/lxml/lxml) from 6.1.2 to 6.1.3. - [Release notes](https://github.com/lxml/lxml/releases) - [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt) - [Commits](lxml/lxml@lxml-6.1.2...lxml-6.1.3) --- updated-dependencies: - dependency-name: lxml dependency-version: 6.1.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [mkdocstrings-python](https://github.com/mkdocstrings/python) from 2.0.7 to 2.0.8. - [Release notes](https://github.com/mkdocstrings/python/releases) - [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md) - [Commits](mkdocstrings/python@2.0.7...2.0.8) --- updated-dependencies: - dependency-name: mkdocstrings-python dependency-version: 2.0.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.13.4 to 2.13.5. - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/v2.13.5/HISTORY.md) - [Commits](pydantic/pydantic@v2.13.4...v2.13.5) --- updated-dependencies: - dependency-name: pydantic dependency-version: 2.13.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.7.0 to 2.8.0. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](urllib3/urllib3@2.7.0...2.8.0) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.8.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.13.0 to 2.14.0. - [Release notes](https://github.com/jpadilla/pyjwt/releases) - [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst) - [Commits](jpadilla/pyjwt@2.13.0...2.14.0) --- updated-dependencies: - dependency-name: pyjwt dependency-version: 2.14.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [uvicorn](https://github.com/Kludex/uvicorn) from 0.52.4 to 0.53.0. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](Kludex/uvicorn@0.52.4...0.53.0) --- updated-dependencies: - dependency-name: uvicorn dependency-version: 0.53.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* telerik: overhaul, drop rau_crypto shellout Refactor into per-technique async methods, replace RAU_crypto.py subprocess loop with native badsecrets-primitive payload builder. Add CVE-2017-9248 oracle probe (dp_cryptomg quick_check port) and DialogHandler known-key spray (PBKDF1_MS + PBKDF2 via badsecrets keylists). Standardize FINDING name values on CVE + handler. Config: exploit_rau (renamed from exploit_RAU_crypto), try_known_keys, probe_dialoghandler_oracle, include_machinekeys. Deps: drop deps_ansible + pycryptodome, add badsecrets. * telerik: real dp_cryptomg find_baseline, default path first Replace KDF-fingerprint shortcut for the DialogHandler oracle probe with the actual dp_cryptomg find_baseline algorithm: iterate the 3^4 byte combinations of [0x00, 0x6b, 0x08] as GET ?dp=<b64> payloads and read for 'Index was outside the bounds of the array' / 'String was not recognized as a valid Boolean'. On hit, emit CRITICAL/CONFIRMED. Reorder DH exploit: try known-key spray first (definitive, recovers the actual keys); only fall back to the byte-oracle baseline probe if no key matches. Oracle probe is gated to PBKDF1_MS mode since the CVE-2017-9248 patch moved to PBKDF2 specifically to defeat it. DialogHandler discovery tries the default path (Telerik.Web.UI. DialogHandler.aspx at root) sequentially first; the handler is global and this produces a less confusing finding URL. Only fan out to the extended candidate list if the default misses. * telerik: safe RAU default-keys probe with fake-version payload Detect CVE-2017-11317 exploitability without uploading a file. Send default-keys payloads targeting a fake assembly version (9999.9.999); if the server responds with 'Could not load file or assembly', crypto succeeded and .NET rejected the bogus version before any file write. Emit HIGH/HIGH 'Telerik RAU Default Keys Accepted' finding. Try each (KDF, HMAC) combination pre-patch targets can use: PBKDF1_MS no-HMAC (pre-2017), PBKDF1_MS with HMAC (2017.1.118 - 2018.1.117), PBKDF2 with HMAC (2018.2+). First hit exits. exploit_rau=True still runs the full version iteration for the CRITICAL/CONFIRMED RCE finding; version identification and RCE confirmation are the same operation. Fix: version fingerprint used to send version 2014.3.1024, a real Telerik version. On a target actually running that version, that was an accidental file upload during 'default' scanning. * telerik: rename exploit_rau -> rau_confirm_version The safe fake-version probe already detects RAU exploitability by default; this opt-in specifically identifies the exact installed version by uploading a benign 1-byte file. Old name misrepresented its role. Description now warns explicitly about the file write. * telerik: expand RAU key spray, version list, verbose flow Safe RAU probe now sprays the full badsecrets keylist (not just the two hardcoded defaults), split into Default vs Known findings by key source. Version list picks up badsecrets' patched set + undotted variants; adopts quoted Version="X" and lowercase C:\\windows\\temp\\ per badsecrets. custom_secrets wired through. rau_confirm_version defers HIGH until version-check runs — CRITICAL alone on match, HIGH fallback (with attempted-but-failed wording) on miss. Verbose step messages throughout. dotnet-audit preset uses rau_confirm_version. * telerik: try both KDFs when DH KDF probe can't classify Post-patch DialogHandlers validate input length before touching crypto, so the short AAAA fingerprint probe returns 'Invalid length for a Base-64' regardless of the actual KDF. Real known-key probes are long enough to pass that gate, so spray PBKDF1_MS then PBKDF2 when the classifier can't tell. Catches weak-custom-key configs on hardened targets that would otherwise fall through with no attempt. * telerik: don't label 'Invalid length for a Base-64' as PATCHED badsecrets sees the same string and silently keeps its initial PBKDF1_MS default; it's an input-length gate, not a patch signal. Returning None makes the exploit path try both KDFs (my prior change), which is strictly more coverage than badsecrets' PBKDF1_MS-only fallback. * telerik: run oracle probe unless target is confirmed PBKDF2 dp_cryptomg does no KDF classification before find_baseline — it just tries the byte oracle and reads response strings. My PBKDF1_MS-only gate skipped legitimate oracle-vulnerable targets whose short KDF-fingerprint probe was rejected by an input-length gate (kdf_mode = None). Only skip when the classifier explicitly reported PBKDF2 (where the CVE-2017-9248 patch fixed the oracle by design). * telerik: DH version detection + RAU version threading Add DialogHandler version detection using the recovered hash/enc keys (safe, size-diff probe, mirrors badsecrets' DialogHandler.probe_version). Emit follows the RAU pattern: CRITICAL/CONFIRMED with version, HIGH/HIGH fallback when target's version isn't in the candidate list. Thread RAU-confirmed version through to DH oracle + known-key findings. Both handlers back onto the same Telerik.Web.UI install, so an RAU-confirmed version fills in the DH side when DH can't identify it directly (strong custom DH keys). Also fix DH known-key test mock to model version detection correctly (assembly type string is base64-encoded inside the plaintext) and assert CRITICAL + version in the finding. * telerik: drop redundant _rau_confirmed tracker; fix stale test copy _rau_confirmed set added nothing on top of _incoming_dedup_hash: URL events dedupe per-netloc (default) or per-normalized-URL (include_subdirs), and either way the same base_url can't reach _probe_rau twice. Also: rename stale exploit_rau -> rau_confirm_version in a test message and add missing f-string prefix on another.
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.16.6 to 0.16.8. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.16.6...0.16.8) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.16.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* add nowafpls Cloudflare WAF bypass detector * nowafpls: log resolved_hosts and host_metadata in filter_event debug * nowafpls: strip filter/handle_event debug prints * nowafpls: helper with per-host memoized probe Move the bypass detection into a NowafplsHelper (helpers.nowafpls) that memoizes verdicts per host via asyncio.Task so concurrent consumers share a single probe. Detection is provider-agnostic: baseline the endpoint via helpers.http_compare with a benign POST body, then compare unpadded and padded malicious bodies against that baseline. Verdict is one of no_interference / bypassed / blocked / error. Provider name for the finding description is pulled from event.host_metadata (cloudcheck's cloud_providers with type waf or cdn) when available; otherwise the finding falls back to "WAF/inspection layer". Module filter drops from provider-name whitelist to just "waf" in event.tags. * nowafpls: shorten finding description, move detail to context * nowafpls: wire into lightfuzz, ajaxpro, generic_ssrf Helper gains pad_form_body / pad_json for transparent WAF-bypass padding. Lightfuzz avoid_wafs becomes tri-state (always/never/try_bypasses, default try_bypasses); prepare_request pads POSTPARAM/BODYJSON when the WAF is bypassable. Ajaxpro and generic_ssrf's POST submodule opportunistically pad their adversarial bodies. Findings emitted through a padded probe are tagged used-nowafpls. * lightfuzz-xss: enable POST fuzzing so nowafpls bypass gets exercised Drops disable_post, adds try_get_as_post so GET params get retested as POST, sets avoid_wafs=try_bypasses explicitly. A padded-POST XSS is triggerable from an attacker-controlled form, so the bypass is worth attempting here. * nowafpls: skip 3xx URLs; bump default padding to 1 MiB Two independent bugs made cloud-fronted targets never detect: - per_host_only clobbered the real https URL when the http variant (a 301 redirect) arrived first. Add a status-3xx reject in filter_event so the redirect stops being probed and the real endpoint keeps its slot. - The historical 128 KiB default no longer beats Cloudflare's inspection window. Bisected against a live CF site: XSS bypasses at body offset >= 1048603 (~ 1 MiB). Bump default to 1048576. * per-URL wildcard check; nowafpls finding includes pad size Base module's _is_http_wildcard_host was a host-level check: when the site root looked like a catchall, every event on that host was rejected. Real endpoints on wildcarding SPAs (e.g. a 200-catchall CF site with a distinct /params_test2.php) got dropped by lightfuzz / webbrute / etc. Wrapper now probes the specific URL against the wildcard baseline that the underlying helper already returned. For WEB_PARAMETER GETPARAMs the target URL is reconstructed with the parameter baked in (bare URLs on catchall hosts collapse to the baseline, only the parameterized form diverges). Also thread the padding size into the nowafpls FINDING description so operators can tell what size worked without cross-referencing the run config. Tests cover: per-URL divergence, GETPARAM reconstruction, POSTPARAM falling back to bare URL, HttpCompareError -> None, scalar-True mocks still short-circuit, and nowafpls skipping 3xx URLs. * accept boolean avoid_wafs for backwards compatibility * Fix WAF-tagged hosts being skipped when nothing is blocking lightfuzz's try_bypasses branch gated on `not result.bypassed`, which collapsed no_interference, blocked and error into a single rejection. A host that carries the `waf` tag but isn't gating payloads got zero fuzzing. Branch on the explicit status instead. The same branch applied `_post_capable` before consulting nowafpls, dropping every URL and GETPARAM event on a tagged host regardless of what the probe would have said. Padding is body-only, so that gate is only meaningful once the verdict is `bypassed`. HttpCompare.compare() reported a failed request as a baseline match. nowafpls read that as "no interference" on a killed unpadded request and as "bypassed" on a killed padded one, and wildcard detection read it as "this host is a catchall". Add `none_is_match` (default True, preserving existing behavior) and pass False from those three call sites; the wildcard paths now treat a dead probe as unknown. The reasons value on that path is also a list now rather than a bare string, which consumers were rendering as "4,0,3". Log probe verdicts through a shared BypassResult.summary that carries the error and diff reasons, and report at INFO so the result is visible without debug logging. * Distinguish an inconclusive WAF probe from a blocked one STATUS_BLOCKED and STATUS_ERROR each return their own filter reason instead of a bare False, and the probe verdict is logged once per host at verbose so it lands outside debug logging regardless of which module asked. * Log the no-bypass result at verbose instead of info * nowafpls: own padding size in the helper and fall back on 413 The probe now walks a configurable, descending list of padding sizes and steps down only on an explicit 413, so an origin body-size cap (nginx's default client_max_body_size is exactly the old 1 MiB default) reports as too_large instead of masquerading as a WAF block. A dropped connection stays ambiguous and does not advance the ladder. padding_size and payload move from the nowafpls module to web.* config, so pad_form_body, pad_json and lightfuzz's prepare_request all pad with the size the probe validated rather than a compiled-in default. * telerik tests: use per-worker HTTPSERVER_URL instead of hardcoded 8888 * sql: give scan.started_at an explicit naive datetime column for sqlmodel 0.0.46
Bumps [cachetools](https://github.com/tkem/cachetools) from 7.1.8 to 7.2.0. - [Changelog](https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst) - [Commits](tkem/cachetools@v7.1.8...v7.2.0) --- updated-dependencies: - dependency-name: cachetools dependency-version: 7.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 11.0.2 to 12.0.1. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](facelessuser/pymdown-extensions@11.0.2...12.0.1) --- updated-dependencies: - dependency-name: pymdown-extensions dependency-version: 12.0.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add js_unpacker module with YARA-based detection Five unpackers: source-map, Dean Edwards, obfuscator.io, Next.js, and webpack. Emits unpacked HTTP_RESPONSE for excavate to re-process, and FINDING for exposed source maps with sourcesContent. * Fix HTTP_RESPONSE dedup so re-emitted responses from different modules are distinct HTTP_RESPONSE._data_id now includes the source module name, preventing js_unpacker's unpacked responses from being deduplicated against the original http module response. Adds integration test for the js_unpacker -> badsecrets chain. * add to js-audit preset * js_unpacker: fix FINDING schema + rehash unpacked HTTP_RESPONSE - FINDING for exposed source map was missing required 'name' field - unpacked HTTP_RESPONSE re-emit reused the original body_md5/sha256, causing excavate's content-dedup to drop the unpacked body * HTTP_RESPONSE dedup: opt-in re-emit marker instead of module name Original fix stuffed str(self.module) into _data_id to keep js_unpacker's unpacked HTTP_RESPONSE distinct from http's original. That broke the pydantic JSON round-trip (module is a runtime object, not serialized). Reverts _data_id to method|url by default. Modules re-emitting an HTTP_RESPONSE for the same (method, url) with transformed content set data["_reemit_source"] to force distinct event.id. js_unpacker does so. * run js_unpacker regex work off the event loop * fix flaky dean-edwards assertion in js_unpacker test * Move js_unpacker test to per-worker mock server ports The test hardcoded 127.0.0.1:8888, so under pytest-xdist any worker but gw0 aimed its scan at another worker's server and got no matching handler. * Move the js_unpacker re-emit marker off event data * js_unpacker: honor blacklist on source map fetch, bound page-supplied loop counts
* fix(events): set url_extension on HTTP_RESPONSE HTTP_RESPONSE.sanitize_data() overrode URL_UNVERIFIED's without extracting the URL file extension, so url_extension was never set. Modules that filter on it (paramminer) let every static-file URL through, fuzzing PDFs, DOCXs and ZIPs with a full binary search across the wordlist. Extract the extension logic into DictEvent._set_url_extension() rather than adding a third copy, and call it from HTTP_RESPONSE. Populating url_extension would also newly subject HTTP_RESPONSE to the url_extension_special gate, hiding .js responses from every module that doesn't set accept_url_special. Add _url_special_filterable so events representing already-retrieved content stay exempt. * Test url_extension gating behavior instead of class attributes
# Conflicts: # pyproject.toml # uv.lock
… crt.sh rejects with 400) (#3428) * crt: request an explicit / path; blasthttp sends an empty path, which crt.sh rejects with 400 add_get_params("https://crt.sh", ...) yields https://crt.sh?q=...&output=json, which has no path. blasthttp sends it as given, so the request line becomes `GET ?q=...` and crt.sh's nginx answers 400 Bad Request on every query. httpx (bbot 2.x) normalised the empty path to /. * Remove crt base_url comment --------- Co-authored-by: liquidsec <paul.mueller08@gmail.com>
Co-authored-by: Shane Engelman <shane.engelman@blacklanternsecurity.com>
…pytest-asyncio-1.4.1.post1 Bump pytest-asyncio from 1.4.1 to 1.4.1.post1
…pydantic-2.14.2 Bump pydantic from 2.14.1 to 2.14.2
Set the project author to Black Lantern Security in pyproject.toml and add Paul Mueller as maintainer. Updated README to reflect that BBOT is built and maintained by BLS, and adjusted individual credits to better represent contributions.
…pyzmq-27.3.0 Bump pyzmq from 27.2.0 to 27.3.0
correlate_event re-searched the batch with event containment, so a result on a subdomain was parented to any earlier batch URL on a parent domain. Look up the exact input URL nuclei echoes back, falling back to the host lookup for non-HTTP templates. Also handle "tags": null from untagged templates.
Lets a finding that isn't on a URL, such as a TLS or TCP service, say which port it's on. The port is part of the event's identity, so findings on different ports of one host no longer dedupe into one. legba and medusa already pass a port, which the validator was silently dropping.
ssl and network templates report matched-at as host:port and no URL. Parent them to the batch URL on the same port, and when there isn't one, emit the finding with its port instead of the parent's URL.
…-deps Remove unnecessary dependencies
Fix nuclei result correlation and add an optional port to FINDING
…horship Update project authorship to Black Lantern Security
Bump blastdns to 2.0.4
…es-update 3.1 documentation update
Contributor
|
All contributors have signed the CLA ✍️ ✅ |
liquidsec
marked this pull request as ready for review
November 11, 2026 00:10
Contributor
Author
|
recheck |
Contributor
|
I have read the CLA Document and I hereby sign the CLA |
Contributor
|
Signed above, but the CLA bot can't save it. Run 42930418939 fails with |
en0f
approved these changes
Nov 12, 2026
singlerider
approved these changes
Nov 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release 3.1.0
These notes cover everything since 3.0.2. The full migration guide is in
docs/migration/3.1_breaking_changes.md(#3594).Breaking changes
requires-pythonis now>=3.11,<3.16; CI tests 3.11 through 3.15. 3.10 reaches EOL this month.portfiltermodule removed (Filter CDN/WAF ports by default and remove the portfilter module #3534). CDN/WAF port filtering now happens in core and is on by default; opt out with--allow-cdn-ports.config.module_dirsis deprecated and ignored;module_dirsis honored only as a top-level preset key. BBOT asks before loading each custom module folder (-yanswers yes,-Sno longer implies-y), refuses world-writable folders and files, and refuses custom modules that reuse an existing module name. Presetconditionsare read-only, andversion/homeare validated.modules.lightfuzz.avoid_wafsdefaults totry_bypasses, which fuzzes a WAF-tagged host only if a nowafpls probe gets past the WAF, and the lightfuzz presets enable thenowafplsmodule. The top-levelavoid_wafsis no longer read. For the 3.0 behavior, setmodules.lightfuzz.avoid_wafs: alwaysand pass-em nowafpls.affiliatetag on in-scope events (Don't tag in-scope events as affiliate #3524) can affect existing presets and output consumers.Highlights
DNS (#3457)
--custom-nameserversflag (dns.nameservers), replacing the system resolvers for normal resolution. An invalid value aborts the scan during prep instead of producing a "completed" scan with zero results.dns.brute_max_resolvers(default 600,0for the whole list) (Draw a random sample of brute-force resolvers once per scan #3612). Each scan draws that many brute-force resolvers at random, once. Dead ones are dropped at startup, and every brute-force run in the scan shares the rest, so pacing learned in one run carries into the next. Also raises the blastdns floor to 2.0.3, which paces attempts when per-attempt loss shows a shared bottleneck.dns.threads10 to 50, newdns.max_concurrency(256), and the dnsresolve worker count derived from the client's total slots. On a large wildcardsubdomain-enumscan this halved wall time compared with 3.0.2, with the same subdomains found. Lowerdns.threadsfor a fragile resolver. Thesubdomain-enumpreset no longer setsdns.threads: 25, so it gets the new default too (3.1 documentation update #3613).is_wildcard(Fix nested wildcard detection in is_wildcard #3536).baddns 2.5.0 (#3457)
DELEGATIONsubmodule, enabled by default and in thebaddns/baddns-heavypresets. Checks_acme-challenge,_dmarcand 15 common DKIM selectors for dangling delegations, with wildcard and generic-finding filtering to keep volume down.NSgained a lame-delegation finding (ceiling raised to HIGH/CONFIRMED).WordMatcheris passed through, matching all signatures in a single pass.blastdnscapped at<2.1to match baddns's own ceiling.New modules
favicon: technology detection from favicon hashes (Add favicon module for technology detection #3532).js_unpacker: detects and unpacks obfuscated JavaScript (Add js_unpacker module for detecting and unpacking obfuscated JS #3335).nowafpls: WAF bypass detection via body padding (Add nowafpls Cloudflare WAF bypass detector #3336). lightfuzz, ajaxpro and generic_ssrf pad their payloads on hosts where the bypass is confirmed.otilabs: subdomain enumeration (Add otilabs subdomain module #3496).scanmalware: subdomains from ScanMalware's public scan archive (Add scanmalware subdomain module #3528). Keyless and opt-in (-m scanmalware); not insubdomain-enum.Modules
/path, which crt.sh requires (crt: request an explicit / path (blasthttp sends an empty path, which crt.sh rejects with 400) #3428).excavate
<base href>(Resolve excavated relative URLs against <base href> #3522).Core
api_requestrate limiting, plus config deprecation support viaField(deprecated=True)(Overhaul api_request rate limiting and add config deprecation support #3461). API calls made throughapi_requestnow send aBBOT/<version>User-Agent instead of the scan's browser User-Agent.affiliate(Don't tag in-scope events as affiliate #3524).portfor findings that aren't on a URL, such as a TLS or TCP service. It's part of the event's identity and shown ashost:portin text output, and legba and medusa findings now keep their port (Fix nuclei result correlation and add an optional port to FINDING #3629).HTTP_RESPONSEevents carryurl_extension(Set url_extension on HTTP_RESPONSE events #3406).ClosestHostEventkeeps its inherited port, and the port is restored from JSON (Keep inherited port on ClosestHostEvent and restore port from JSON #3462).download()respectscache_hrsin its freshness check (Respectcache_hrsindownload()freshness check #3563).Target.add()(fix TypeError when a hostless target is sorted against a /32 #3391).Performance
compute_simhash, with corrected executor placements (Speed up compute_simhash and correct executor placements #3331).response_to_jsonremoved in favor ofresponse_to_event_dict(Delete duplicate response_to_json, unify on response_to_event_dict #3473).Dependencies
deepdiffremoved, along withcacheboxandorderly-set(Remove deepdiff dependency #3604). ansible-core resolves to 2.22 on Python 3.13+, which is what makes 3.15 installable.dnspythonremoved (deps: drop dnspython; blastdns handles all DNS #3610). Nothing imported it, and its old pin held every install below 2.9.0, the fix for GHSA-45c3-73f7-pv4m. The baddns modules still install it, uncapped, through baddns.pyjwt,lxmlandsocksioremoved, andxmltojsonreplaced byxmltodict(Remove unnecessary dependencies #3627).Maintenance
Refs #3555