ShakerScan 2.11.1
The client for this release is shakerscan 0.11.1.
A patch release: security and correctness fixes, longer time budgets for thorough and deep
Scans, roomier Hunt profiles, reliable Hunt recording, and dependency updates. No schema changes.
Security
- Login attempts and state-changing GETs need the state-changing permission. Active Nuclei
templates that sign in by GET ran in any Scan with active testing (
tomcat-default-loginsends its password list in anAuthorizationheader), and a login attempt can lock the account. A template taggeddefault-login, or one that sends a username or password in a header or the body, or a password in the query string, now needs state-changing HTTP whatever its method. So do the GETs reviewed as changing state: one sets a device password, one restores a default admin password, one changes a plugin's settings, one registers a user, one adds an administrator. 56 bundled GET-only templates of the default selection move behind it. The Scan form and the terminal's--allow-state-changing-httphelp say so, and the step's receipt counts them (template_selection.default_login). - Exploit templates need the state-changing permission. The active template sweep ran exploit
templates sent by GET in any Scan with active testing: 68 of the default selection, 13 of them
tagged
rce(one puts;curl ...;in a parameter, another aRuntime.execexpression in a path). Only a verify Scan held them back. A template taggedrce,lfi,sqli,ssrf,ssti,xxe,deserialization,code-injectionorcmdi, or one that runs a code, JavaScript or flow step, now needs state-changing HTTP in the sweep as well. With the permission the sweep runs the same templates in the same windows as before. The Scan form and the terminal's help say so, and the step's receipt counts them (template_selection.exploit_class). - Go-based scanner and Model Intake tools use patched compilers. Go 1.27.3 and 1.26.10
address
CVE-2026-111943, which removes trust in affected intermediate certificates. Builder images remain pinned by digest; the image vulnerability gate checks the compiled tools. shakerscan recordnever follows a redirect with the API token (client 0.11.1). The recorder's HTTP client followed 301, 302 and 303 answers and re-sentAuthorizationto theLocationhost, including another origin and from HTTPS to HTTP. It now refuses every redirect, like the other client commands, and names the refused origin.- Copyable commands pass every target-chosen value as one shell word. The reproduce, verify, replay and check commands on finding pages could carry an unquoted URL, parameter or payload chosen by the target, which a shell would expand when pasted. Replay commands stored before the upgrade are rebuilt from their stored inputs when read.
- Capture replay withholds credentials carried in URL paths. Magic-login, share, invite and
reset links, cookieless session ids, long random tokens and userinfo in a captured URL are no
longer replayed, and copies of the page URL in
Referer,Origin,HX-Current-URL,Next-Url, query values and bodies lose the credential. Captures recorded before the upgrade are treated the same way when replayed. The display mask used elsewhere is unchanged. - Session headers stay on the target's origin across redirects. A Scan authenticated with
an API-key or other custom session header sent that header to whatever origin a redirect
named: curl, httpx, aiohttp, sqlmap, dalfox and nuclei drop only
AuthorizationandCookieon a cross-host redirect, and an inline-bcookie string goes everywhere. A request that carries such material now follows a redirect only to the same scheme, host and port, or to the same host upgraded fromhttpon port 80 tohttpson 443; on that origin it follows exactly ascurl -Ldoes (output, request bodies, cookie jar,--max-redirs).Authorization,Cookie,-uand--oauth2-bearerkeep curl's own behaviour, since curl 7.83 and later strip them itself. Trade-off: sqlmap, dalfox and nuclei runs that carry the session do not follow redirects at all, and a curl request with a custom session header stops at a redirect to another origin, so a check whose proof sits behind such a redirect is not reached in a custom-header session. - Browser sessions send their headers to the target's origin only. Playwright's extra
headers went with every request a page made, including images and scripts from other origins
and redirect hops to another origin, which no route handler sees. A browser context that
carries session headers (the XSS browser proof, the authenticated browser crawl, the
interactive browser session once a header is set, the AI widget target) is now confined at the
network layer: all of its traffic goes through a local proxy that admits only its bound
origins (scheme, host and port, or the same host upgraded from http on port 80 to https on
443) and refuses every other connection before it is made. The headers stay the context's own,
so Chromium keeps its streaming, CORS, cookie and size behaviour; an HTTPS connection elsewhere
is refused before any byte of the request is sent, and a plain-HTTP one reaches only the local
proxy. The cost: such a context loads nothing from another origin (a CDN, a third-party
script, a redirect to another site). Each refusal is listed in the Scan's coverage, the
browser crawl's and XSS proof's results, the interactive session's action result and the AI
widget's evidence, without changing a family's status:
session_cross_origin_refused, andsession_navigation_redirect_refusedfor a navigation a bound origin redirected elsewhere. These confined contexts are granted Chromium's Local Network Access, so an internal application on private addresses loads;private_network_subresource_blockedis listed where Chromium still refuses one. A refused connection is closed unanswered, so the page sees a network error (never a response that would read as the other origin's), and WebRTC is disabled in these contexts, since it sends UDP outside any proxy. A context that carries only cookies is not confined. A custom session header makes a cross-origin request between two bound origins non-simple, so Chromium preflights it, as it did before. When an interactive (Hunt or AI verification) browser session is given a session header, it moves to a confined context that keeps its cookies, localStorage and current URL, but not its sessionStorage or any other page the user had open in that session. - Scan and Hunt browser actions keep trusted headers on the bound origin. The browser
capability's pinned proxy admitted the target's own address written as a host, so a redirect
to that address as another origin received the trusted headers Chromium carries into redirect
hops. The pinned proxy of a hostname target now refuses that address as a destination and
counts it on its receipt (
address_literal_destinations_refused); every scanner on that path (sqlmap, katana, nuclei, dalfox, httpx, ffuf) addresses it by hostname. The browser's tunnel also admits only its bound origin's scheme (a TLS record for https, plaintext for http), so an https origin's redirect to http on the same port is refused (scheme_mismatch_refused), and WebRTC is disabled in that browser. The action's result and the Scan's coverage listsession_cross_origin_refusedandsession_navigation_redirect_refusedwhen the proxy refused a connection. - Dalfox does not use its headless browser with a session. Its headless verifier and
--deep-domxssrun a Chromium outside any proxy that adds the session headers to every request a page makes. A session-carrying run now passes--skip-headlessand no--deep-domxss, and the Scan's coverage listssession_header_withheld_from_headless. - Known limit of browser sessions. A Scan or Hunt browser XSS proof that sends its payload in a request body follows a 307 or 308 redirect the way the browser does for the page's own navigation, so the redirected request is a GET without the body.
- A refused-redirect hint names only a plain origin (client 0.11.1). The suggested
shakerscan connect <origin>/--url <origin>used theLocationhost as sent, so a craftedLocationproduced a command that ran shell syntax when pasted. The origin is rebuilt from a validated host and port and quoted, or the hint says<origin>. - Path-segment SQL injection replay commands are quoted like the others. Replay commands for
a marked path segment (
/products/1*) passed the stored URL to the shell with control characters and a backslash-quote intact. - A token used as a bare query name is masked. A URL carrying a credential as a query key
without a value (
?<token>) showed it in capture request lists, replay plans and receipts. - Copy commands stored by earlier releases are rebuilt or shown as text only. A finding's stored manual verification commands are rebuilt from the evidence's URL and path when read; a stored command that cannot be rebuilt or checked is shown as recorded text without a copy button.
- The client shows server text without terminal control characters (client 0.11.1). Public check results, instance health answers and error messages could carry escape sequences or a carriage return that rewrote the terminal; they are shown as visible text now.
- aiohttp 3.14.5 in the scanner image, for CVE-2026-111064 (GHSA-2g87-pp6c-29x5, high), published after 2.11.0 (fixed in 3.14.4).
- certifi 2026.10.19 in every Python image and tool lock, for GHSA-6q48-6c7w-9gw2 (critical): 2026.7.22 bundles emSign root certificates that were compromised. The image vulnerability gate refused the older version. pip 26.2.2 in the Model Intake image's pip-audit environment, whose vendored copy of certifi carries the same fix.
- filelock 4.2.4 in every Python lock that carries it (the scanner image, the Model Intake image's pip-audit environment, the locally built Firecracker guest and the CI pip-audit tool), for CVE-2026-112940 (GHSA-v4x8-3wr5-3wq8, high) and the other filelock advisories fixed in 4.2.1, published after 2.11.0. The image vulnerability gate refused 3.32.2. tldextract, CacheControl, huggingface-hub and torch, which pull it in, all accept 4.x. The scanner and API images also remove the Playwright base image's virtualenv and its dependencies, which nothing in them uses: virtualenv requires filelock older than 4, and the base's filelock 3.32.5 stayed installed beside the locked version. Their builds now fail when a Python package is installed twice.
- Next.js 16.4.1 in the UI image, for GHSA-2464-fhr4-w9xw and GHSA-673q-mjm6-r5xr (critical) and CVE-2026-94482 (high), published after 2.11.0. The image vulnerability gate refused 16.4.0.
- Go scanner tools build with patched echo and compress libraries. echo 4.16.1 in dalfox, for GHSA-cxf3-9h37-7rr8 (critical) and GHSA-9969-6676-49h5, GHSA-f48p-c9v4-h7xv and GHSA-h7wr-284f-5qvc (high), published after 2.11.0; klauspost/compress 1.18.7 in gungnir, httpx, katana, naabu, subfinder and tlsx, for CVE-2026-63209 (high). The image vulnerability gate refused the older versions. The tools' own versions are unchanged, and the image build now stops if a library lift would move one.
Fixes
- A pre-2.6 install is refused instead of starting on a new, empty database. An install that
still holds PostgreSQL 16 data in
postgres-dataand has no migratedpostgres-clusterno longer passes the start checks; the refusal names the backups to restore from. This corrects 2.11.0, whose notes said such a start refuses.redis resetrefuses in that state before it changes anything. - A pre-upgrade backup is taken when the release record does not name the running API's image (running or stopped), or when that container cannot be inspected.
- TLS legacy-protocol probes run only when the action's reservation pays for them.
- A parallel Scan's summary covers every part when a finding has no CVSS score (a verified XSS) or gives it as text, or carries its OWASP or CWE labels as a list; the parent kept one part's summary. The merge no longer copies the summary grader's compliance block over the report's.
- An open-redirect probe that got no answer stays inconclusive and is probed again on resume, instead of counting as examined.
- Exposure service pages give a device and its host target, which share an id, their own inventories.
- Opening a browser capture by an IPv6 target URL finds the target.
- A credentials link with
?target=<url>reads search pages until it finds the origin; a failed read is reported as such, not as a missing target. - A browser XSS proof or retest finishes when the headless browser stops answering. Opening the proof page had no time limit, so a browser that stayed connected but stopped answering held the Scan's proof, or the worker's retest, for good. A browser that does not start within 60 s, or open the page within 30 s, now fails that proof and is replaced for the next one; the retest of a verified XSS finding is then inconclusive and says so. The browser kept between proofs now belongs to the event loop and thread that started it and is closed when that loop ends: a process that ran proofs in a second event loop was handed the first one's browser, on which every call waited forever.
Finding accuracy
- A retest uses only the prover of the finding's own kind of check. Title words matched
anywhere chose the prover ("source" contains "rce"), so exposure, header and template findings
were retested with command-injection or JWT payloads. The finding's tool now decides; a title is
read, by whole words, only for an earlier scanner's attack checks. A finding with no prover, or
only an AI verifier, offers no retest and says why (
retest_unsupported_reason); run a new Scan, or the Hunt, again.GET /findings/{id}addsretest_active. - A verified SQL injection, NoSQL injection or XSS finding is retested with the request its proof
sent. The retest read neither the tested field the proof recorded nor the route's site, so it
sent its payloads to the bare route with no parameter and could never conclude; a retest request
was refused with "The target's authorization does not cover the host". The retest now rebuilds
the proved request (the route on the target's site with the tested query parameter, or the page
with the browser proof's own payload, checked against the digest the finding kept) and runs the
check that proved the finding, a page judged by the browser proof's own marker: still
vulnerable when it reproduces, likely fixed when it does not and every request was answered,
inconclusive otherwise (a refusal, a service that is unavailable, rate-limiting or no longer
serves the page). A finding whose request cannot be rebuilt (a path segment, a templated
route such as
/products/{int}, a request body, a recorded request whose values were not kept, a fragment) offers no retest and says what is missing (retest_unsupported_message); so does a potential SQL injection or XSS from a request differential, which keeps no route. New SQL and NoSQL proofs record the site they were proved on (origin). - An AI retest verdict is at most inconclusive. An AI "likely fixed" or "false positive" could
refute a Hunt candidate or close a finding; it is now inconclusive, with the model's note. The
finding page no longer offers an "AI only" retest (
retest_modesliststieredanddeterministic); the API still takesmode=ai. - Reflected XSS is browser-proven again. The Scan's browser proof declared an adapter identity the capability registry did not accept, so every proof was rejected before it ran and no "Verified cross-site scripting" finding could be produced. A proof that breaks now leaves its family partial and the grade provisional, instead of complete.
- "Nothing to test" needs a crawl that ran. When every crawl of a Scan failed or never
started, its selected XSS, SQLi and NoSQLi checks found no candidates and read complete
(
no_candidates) with a reliable grade, although nothing was tested. They now read partial with the reasondiscovery_failed, so the Scan is not complete and its grade is provisional. When one crawl ran (the static crawl on a target without a browser runtime), an empty candidate list still means there was nothing to test. - A CORS policy that reflects any origin is detected. The receipt redactor rewrote the echoed
Access-Control-Allow-Originbefore the check compared it with the probe origin. - Reproduce and check commands work from masked evidence. Engine-authored probe values (the open-redirect target, the GraphQL introspection document) are kept; a stored URL whose query the scanner masked is not replayed as stored.
- Active Nuclei templates run against the scanned URL, not a discovered endpoint's path, on
every profile, so host-level templates such as exposed-service checks match. Each active-template
attempt now targets the directory of the URL the Scan targets (
/app/login.phpruns at/app/), and then the root of every other origin the Scan discovered; plans, holds and attempts are unchanged, only the URL each attempt targets. A host with more endpoints than template windows no longer repeats a window at the same URL. A finding a 2.11.0 Scan matched at a discovered subpath with a template that asks only its base URL (108 of the permitted templates) may not be reproduced by 2.11.1 and then reads as fixed: those templates now run at the Scan's base and the other origins' roots, not at discovered subpaths. - Active-template coverage counts every origin.
nuclei_active.template_windowscounts (origin, template window) pairs and lists each origin's run and total, so a second origin that ran 11 of 39 windows no longer reads as 39 of 39. A thorough or deep Scan whose active templates did not all run at one of its allowed origins reads partial, with the reasontemplate_windows_incomplete_on_origin. Each parallel scan part starts its template windows at its own offset, so alone it runs as many windows as before and the parts together run at least as many; the merged coverage counts each (origin, window) pair once and says how many pairs two parts both ran (repeated_pairs); an attempt resumed from before the upgrade is kept and never sent again, and a window it ran at a discovered endpoint's path is listed apart (legacy_windows_run), not counted at an origin. - Known limit: a thorough or deep host whose endpoints span more than one origin and whose plan
has fewer than 39 positions per origin reads partial on active templates
(
template_windows_incomplete_on_origin): 2.11.1 does not change the plan, and a later release will plan the windows per origin. - Active Nuclei never runs a template that requests a heap dump, on any profile. A test checks the bundled template set, so a template update cannot bring one back.
- A SQLi point sqlmap marked in a URL path segment (
/products/1*,#1*): the brief and replay commands use the unmarked URL with the payload in that segment, the database name comes from sqlmap's summary line, and a retest declines (inconclusive, nothing sent) because the retest prover injects only query and form parameters. - Each variant of one form is tested as its own candidate. A form seen as declared, as crawled with its hidden fields and as a JSON variant has one candidate identity (its route, method and the field that anchors the body), and the three shared one attempt record: a variant could take another's finished SQLi techniques as its own, so the crawled form's extra fields went untested while the candidate read complete; a variant whose attempt ended differently from another's could fail the verifier, the SQLi proof, the XSS browser proof or the NoSQLi check; and one variant's verifier signal sent all three to the proof. Each variant now keeps its own attempt, techniques and count of what it sent in each of them, and a signal sends only the variant that produced it to the proof; the first keeps its earlier record, so a scan resumed across the upgrade keeps what it already ran (a signal recorded before the upgrade still sends every variant). The anonymous-versus-signed-in route comparison probes a route seen with several bodies once and counts each of its entries, so coverage no longer reads them as never attempted, and the exposure sweep likewise reads such a URL once instead of once per body.
- A scan allowed state-changing requests no longer fails to plan its verifiers when two forms
post to one action with the same rank (a login page's form and a sidebar sign-in widget, a
search form seen with and without a filter): building the candidates raised
TypeErrorat admission, in a continuation round and in the parallel fan-out. Both forms are now candidates. - TLS: a weak signature or key no longer also raises "chain is not trusted"; the certificates the server sent are read correctly on Python 3.12; weak-cipher evidence comes from the weak handshake; reproduce commands show the weakness.
- Finding pages: a page titled "Directory listing" is no longer a verified listing without a real listing; GraphQL findings get GraphQL commands and advice; JDK 9+ stack frames are recognized; non-secret key names are not masked; weak-CSP advice never loosens framing; Tomcat's Apache-Coyote is not reported as Apache httpd; DNS posture findings use the target's origin; the coverage page and the stored grade agree.
Authenticated scans and Hunts
- A credential profile left with no capability list now covers the crawl. On an HTTP identity it grants every read-only capability that uses the identity (probe, crawl, browser crawl, content discovery, spec ingest, passive templates, safe collection replay, browser navigation); sign-in kinds also keep their session capabilities. Active verifiers are never a default and still need an approved elevation. Profiles saved with a list keep it. New Scan says when the attached profile leaves the crawl or a selected verifier running anonymously.
- A crawl or content discovery that carries a session leaves action links alone: sign-out, delete, disable, reset and similar paths and query actions are not requested with the session.
- XSS and SQLi verifiers no longer fail with zero requests when a replayed collection request and a declared endpoint share a route.
- A signed-in crawl starts where the signed-in area is. A crawl or browser crawl that carries
the session also starts at the page the sign-in landed on and at the GET seed endpoints on its
origin (pages before API routes, at most 20), so an area linked from nowhere the target's root
reaches (a
/hub/behind/hub/login) is crawled with the session. The target keeps its whole time box: the static crawl runs its inputs side by side under its one rate limiter and request ceiling, so the seeds share the target's requests while they run (a seed that finishes returns its share), and the browser crawl adds only its first seed, so the target keeps half of that box. Action paths (also percent-encoded), route templates and the profile's own sign-in page are never a seed, and a seed the crawler cannot take is left out instead of failing the crawl. A static primary identity (a bearer token, a header or a cookie), which has no sign-in step, starts from the same seed endpoints, whether the Scan carries one profile or two. - The credential profile's own sign-in endpoint is tested at a lockout-safe pace. An
authenticated balanced scan of a test application sent about 1,460 injection requests to the
sign-in form it used. On that one endpoint (a request with a body to the sign-in path, its
routing query included, or to the form's action) the SQLi and XSS verifiers keep their full
payloads (sqlmap level 2 / risk 2, Dalfox's own payloads for the body), send at most 20 requests
a minute, one attempt at a time, and share one probe set per verifier across every candidate
and round of the scan, sized at twice what a verdict was measured to cost: 946 sqlmap requests
per tested field (twice its level-2 ladder of 473) and 64 Dalfox requests per field, at most
four fields, Dalfox stopping at its first verified finding. A check the probe set leaves without
a verdict is inconclusive, never negative, and its family reads partial with the reason
auth_endpoint_probe_limited. A GET to the sign-in page and every other endpoint keep their full holds, and plans are unchanged. sqlmap's stages on the endpoint are paced and recorded at its pace, so the latency they measure is that endpoint's and paces no other candidate. The checks that send from the worker itself (the SQLi and XSS request verifiers, the SQLi proof, the NoSQLi check and the XSS browser proof) keep the same pace there and each draw from a probe set of their own, twice what one attempt sends per field, and three times that again for the checks whose attempts test every field (the NoSQLi check and the request verifiers): 28 for the SQLi proof, 24 for NoSQLi, 12 for each request verifier and 2 for the XSS browser proof. Each set is the endpoint's four-field set whichever variant of the form draws from it, so the declared form, the crawled form and a JSON variant all fit, twice over, in any order (sized by each variant's own fields, the crawled form's NoSQLi attempt could spend a two-field variant's set, and a fresh scan left up to two variants untested). Such a check runs on the endpoint only when its slice can pace the whole attempt (a sign-in form's SQLi proof is 8 requests, so 32 seconds); otherwise it waits rather than running short, and a proof no slice could pace leaves the family partial (auth_endpoint_probe_limited). - How much the sign-in endpoint may receive. Up to 4,352 requests per scan (the four-field
sets: 3,784 sqlmap, 256 Dalfox, 112 SQLi proof, 96 NoSQLi, 48 for each request verifier and 8 XSS
browser proof), at most 20 a minute, so about 3 h 38 min if the scan's budget lets all of them
run; clearing a two-field form with no SQL injection takes about 950 sqlmap requests (about 47
minutes). In a scan split across parallel parts each part paces the endpoint by the number of
parts, so together they stay at 20 a minute, but each part holds its own probe sets: N parts may
send N times that total. The bound covers the injection verifiers and the checks above; the
active templates (run by default on
thoroughanddeep) are neither paced nor counted there, so a template for a product whose sign-in path is the profile's own (thedefault-loginones, for example, when state-changing HTTP is allowed) may send its sign-in attempts to it as well. - Expect XSS to read partial on an authenticated scan that tests its sign-in form, and the
grade provisional, unless an XSS is verified there. Dalfox sends its whole payload set to a
request body whether or not a field reflects (1,347 requests for a two-field sign-in form,
measured in the scanner image), ten times the 128 its probe set holds there, so its attempt on
the sign-in endpoint cannot end negative: it is inconclusive (
auth_endpoint_probe_limited). Every other endpoint is unaffected. - A credentialed scan admitted on the target's standing authorization records a credential-tier receipt, as New Scan does, whether or not the request named that authorization: the scan is bound to a receipt derived from it (same scope and approver, a seven-day bound, the scan and the source named in it), which covers the scan's credentials and the source's tier only and authorizes nothing else. It ends with its source: every revocation path revokes it (also one filed under an application service from its host's authorization), and the running-scan check and the worker's credential check, the only check a passive credentialed scan has, refuse it once the source no longer stands. Who may start the scan is unchanged.
- A browser session the session store refuses ends the Hunt action with its reason.
- A scan refused at admission leaves no target behind and keeps its blocked audit record.
- ASM: a completed recon fills the target's endpoint inventory from what the scan observed,
without probing the target again; a target without an inventory can be opened from the ASM page;
the continuous-testing controls are hidden where the deployment does not offer them. Several web
apps on one host (different ports) are each listed in their domain group, so every target with
an inventory appears on the Coverage page.
GET /targets/groupedtherefore lists a domain's other root targets, such as other ports of one host, insubdomainsand counts them insubdomain_count,total_count,total_findingsandtotal_targets;best_scoreandlatest_scanremain the group root's own values (the root is the last root target in URL order). Only an ASM batch or recon scan is labelled as hidden from the Scans list, in the view and in the 409 an ASM action gets while a scan runs. - Client 0.11.1:
shakerscan scan helpprints the options instead of submitting a scan, under its own name (usage: shakerscan scan);hunt callexits 2 when the action was refused; a certificate the client does not trust namesSSL_CERT_FILE, once per line; a state-changing scan from the terminal relies on the target's standing authorization; a submitted scan prints the families it runs and, onfastorbalancedwithout them, how to add active templates (--include-family nuclei_active);hunt start --credential-reftakes the short slot names (primary=,secondary=, ...). The Hunt page keeps decided permission requests visible.
Hunt recording and budgets
- Only the duration ends a Hunt. A used-up safety ceiling (state-changing requests, TCP
ports, hosts, UDP ports, out-of-band interactions, device fragility) or any other used-up limit
refuses only the actions that need it, each with a
budget.raiserequest a person can approve (a dimension whose permission is off is refused as before), and the Hunt keeps running: on 2.11.0 it stopped the whole Hunt, read-only work included. Onlymax_duration_secondsrunning out ends a Hunt asbudget_exhausted. The ceilings keep their values. Hunts that stopped on another dimension under 2.11.0 resume as before. - Ports are counted once. A port a Hunt already attempted (listed in a sweep, or reported open
by one) costs nothing more to fingerprint, check or inspect, and a
tls.inspectis one port instead of its ten handshakes. Device fragility still counts every connection: on a device Hunt a re-sweep or atls.inspecthandshake costs a fragility point and a device request even when the port costs nothing more. A network action stopped part way is charged the new hosts and ports of the commands that started. A mutatingcandidate.verifyis charged the requests and state-changing requests its workflow reports it sent, not its whole 24 / 12 hold. - SNMP inspection is charged what it uses.
service.snmp.inspectis charged its UDP port and, on a device, its fragility estimate for each address it reached; 2.11.0 charged no UDP port and one fragility point. - Limits that outlast the duration. Every call that runs is charged at least one second of the
duration, and call, verification, browser and HTTP limits now cover the whole duration at the
most one call can be charged in that second:
fast1 h, 3,600 calls and verifications, 115,200 browser actions, 460,800 requests;balanced4 h, 14,400, 460,800 and 1,843,200;thorough24 h, 86,400, 2,764,800 and 11,059,200. Every call stays paced by its tool. A request refused before it sends is charged the wall it took (at least a second), not its 15-second hold, and a paced Dalfox or sqlmap run without its own request log is charged its rate over the seconds it ran, not its whole hold. - Approval-gated calls may use the whole call allowance (
max_active_actions3,600 / 14,400 / 86,400, was 4 / 20 / 80); every such call still checks its approval receipt. TCP ports, state-changing requests, hosts, UDP ports, out-of-band interactions and device fragility keep their values. - The default profile needs no raise for ordinary web work. Logging in, crawling, content discovery, verification and recording draw no start warning; a remaining warning names a safety ceiling that matters only when the plan needs that capability.
- Useful verifier reservations on every profile:
sqli.verifyreserves 900 requests / 540 s andxss.verify1,800 requests / 480 s. A Hunt that cannot fund one asks for a budget raise instead of starting a shortened verification. - Recording never stops a Hunt. Findings and candidates share
max_candidates(one record per call: 3,600 / 14,400 / 86,400) and need no calls or traffic; a full allowance refuses only that write, a refused write spends nothing, and an unfinished budget-exhausted Hunt can still record. A Hunt's findings hold at most 64 MiB, and its candidate writes stop at 256 MiB of candidate records; a write past either is refused and the Hunt keeps running. - Findings stay on the service their evidence came from. A relative path keeps the target's
own service when it is evidenced and otherwise follows the single evidenced service, including a
nonstandard port; a finding created without a path is located on the evidenced service too.
Device Hunts can save findings with a path: a device's address or name is a host, and a cited
device HTTP probe names its service. A location is stored in one spelling, so
HTTPS://EXAMPLE.TEST:443/xandhttps://example.test/xare the same finding. Malformed context origins and invalid ports are refused as input errors. - A repeated finding returns the existing record unchanged, spends nothing and says whether
newly cited evidence was attached;
findings.updateattaches it. - Finishing proposes reusable steps; it never saves them. The Hunt's newest completed steps
that can be replayed join one rolling proposal per target for
shakerscan knowledge review, outside the Hunt's own proposal allowance, for a person to review before accepting. A step is left out when its inputs carry query values, headers, bodies, browser input, sessions, credentials or other hosts, or its path names an action, a credential, a code or a token, or carries a payload character or dot segment. Accepting the proposal names the digest of the text reviewed, so steps a later finish added are never accepted unseen. The debrief and results page report the outcome, and a failure does not lose the debrief. - Known limit: on a slow sign-in endpoint a Hunt
sqli.verifycan count about twice the requests that reach the target. With the longer 540 s window it can then reach its 900-request ceiling, end with "above the hard ceiling" and be charged its full hold; run it again on a narrower parameter set. Counting it once is planned for the next patch.
Time budgets on thorough and deep
fast and balanced Scans plan exactly as in 2.11.0; a test fixture generated on 2.11.0 pins
them.
- Active Nuclei runs every template window. Each endpoint attempt runs one window of 30
templates. 2.11.0 ran as many windows as a host had endpoints, so a small host ran 1-6 of the 39
windows of the active set.
thoroughanddeepdirect Scans that include active templates now run all 39. Coverage showsnuclei_active.template_windows(windows run of total) on every profile, and so does the scan page; a sweep whose every (origin, window) pair ran is complete in the report and on the page, not partial for endpoints the plan left without a position (the templates run at the origins, not at each endpoint). - The standard active set runs the active templates on
thoroughanddeep. Thestandard_activepreset (New Scan's "Standard active", and--active-testingin the terminal) now addsnuclei_activeon those two profiles;fastandbalancedresolve and plan exactly as before. A scan whose request ceiling was lowered below 8,000 (twice the 4,000 the sweep holds at admission), since that hold might not fit beside the scan's own admission traffic, or with state-changing HTTP whose mutation ceiling was lowered below 5,000 (the sweep is the only mutation held at admission, andthorough's own ceiling is 6,000), keeps the earlier set;--include-family nuclei_activestill adds it, and--exclude-family nuclei_activeremoves it on any profile. The scan contract states the addition and its floors (family_preset_profile_additions,family_preset_addition_floors); New Scan's preview takes the ceilings typed under Advanced, and the terminal names the lowered ceiling when it leaves the active templates out. - SQLi extensions are sized to the techniques left. 2.11.0 gave an extension the lane's whole
time share and paced its requests to fill it (6.25 s per request on
thorough). Extensions now hold what the remaining techniques need, at about 0.5 s per request. - Later rounds step down to a slice the remaining budget affords instead of planning one the allocator refuses.
- Request-body candidates get at least one attempt when the Scan may send state-changing requests, through a floor in the first slice or a floor extension.
- A lowered
max_duration_secondsalso lowers the tool wall when no tool wall is given.
Expect thorough Scans of small hosts to take about 25 minutes instead of about 4.
Documentation
- The OWASP coverage matrix counts only what a Scan runs. It marked SSRF, command injection,
SSTI and XXE as covered, but no Scan family tests them: the
ssrfandrcefamilies are planned and a Scan refuses them, and SSTI and XXE have no family. A10 and API7 (SSRF), A04, A08 and API6 now read "not covered". A06, A07, A09, API2, API3 and API5 drop from covered to partial. The other rows name the family or baseline check behind them and say which are opt-in, need credentials or need state-changing HTTP. API3 names its one narrow check, the plaintext-password account-record exposure. The matrix also gives the number of active Nuclei templates for named products that touch other categories; no row is marked covered for them. It says how much of the active pack a Scan runs: afastorbalancedScan runs one 30-template window per endpoint, so a small host runs only part of the pack. The functionality reference lists all eleven Scan families, and a test keeps both documents in step with them. - The Scan contract describes
xss,sqliandbolaas they run.GET /scan/contractsdescribedxssas "Reflected, stored, and DOM XSS probes" andsqlias having extraction depth. No Scan action looks for stored XSS or extracts data, and the descriptions now say so. It saidbola"Requires Lab/deep policy"; a Scan needs active testing and two distinct credential profiles that allowauthz.verify, and only a focused Continuous ASM batch needs Lab/deep policy.
Dependencies
- UI: lucide-react, postcss, Playwright 1.64.
- CI: CodeQL actions 4.38.3,
actions/download-artifact8.0.2,actions/upload-artifact7.0.2 (with the workflow changes it needs). - posture:
@types/node26.6.5.
Upgrade notes
- No database schema changes and no new settings.
- A Scan with active testing but without state-changing HTTP no longer sends default-login or password attempts, or exploit templates, so it reports no default-login findings and no findings from those templates; allow state-changing HTTP to test them. Authentication-bypass checks that name an account but send no password still run. Its active template sweep has 22 windows instead of 26 (636 templates instead of 760).
- Template, exposure, posture and Hunt findings no longer offer a retest: run a new Scan, or the Hunt, to check them again. A Hunt's verified XSS was retested with a Scan prover's default payload and check; it is now checked again by running the Hunt. Neither do verified injection findings whose request cannot be rebuilt, potential injections from a request differential, nor a SQL injection sqlmap found in a URL path segment (its retest sent nothing).
thoroughanddeepScans run longer and send more requests to each host than on 2.11.0 (for the active template windows, about 2,200-2,600 requests per small host at the unchanged 2 requests per second). Their standard active set now includes the active templates, so athoroughordeepscan with active testing runs them unless it excludesnuclei_active.