Connected-device security

Status: current network/device execution boundary; reconciled 2026-10-02.

ShakerScan treats TVs, cameras, printers, routers, NAS systems, conference equipment, and other network-connected devices as canonical targets. Connected Devices is a network-oriented view of the shared inventory; discovered ports and service origins enrich the same asset used by Scan and Hunt.

Normal shakerscan start and shakerscan restart supply one dedicated network worker. Rebuilding a running installation supplies it too. It uses the existing scanner image and a separate queue, so network inventory does not occupy ordinary web-scan slots. Starting capacity does not submit scans or grant testing authority. The container has a 2 GiB memory limit; idle usage is not that limit.

For resource-constrained installations, set SHAKERSCAN_NETWORK_WORKER_ENABLED=false in the installation's .env, or run shakerscan devices stop. The choice survives subsequent startup, restart, and rebuild. shakerscan devices start re-enables automatic startup; shakerscan devices status and shakerscan devices logs provide diagnostics. In a source checkout, replace shakerscan with ./scanner.sh. Building a stopped installation does not start its services.

During API startup, readiness may report starting for up to 120 seconds while waiting for a fresh, current, tool-capable worker heartbeat. After that, missing capacity reports not_ready with an operator remedy. Target pages refresh readiness automatically and keep diagnostics in Troubleshooting.

Product boundary

Hunt can create targets, rename its asset, and manage its instructions by default, without network-testing permission or repeated prompts. Target detail includes Hunt permissions to disable these edits. Planner confirmation flags cannot override that opt-out or grant sharing. Instruction edits retain their author and the previous 20 revisions; each running Hunt keeps its admission snapshot.

Select exact credential profile IDs for one-time sharing and exact collection IDs for revocable sharing. Same-asset service reuse remains automatic. Revoking collection sharing blocks visibility and subsequent Scan/Hunt replay, including queued work. Existing cross-asset bindings without a recorded sharing grant need operator approval; they are not silently grandfathered as authorized.

For SSH, save verified SHA256 fingerprints by port, or explicitly allow first-contact trust. With first-contact trust, the first key is pinned atomically and a changed key blocks login. An observed or planner-supplied key alone cannot authorize sending credentials. Hunt reports an untrusted key without authenticating so the operator can verify it. Passwords remain encrypted on the wire, but an impersonating server present on first contact could receive them when first-contact trust is used.

  • Devices live in canonical targets with target_device_profiles; device_targets is a compatibility view retaining existing UUIDs. Their interfaces and observed services live in device_interfaces and device_services. The device_targets.id UUID is the durable identity; its current IP address or hostname is mutable and every change is retained in device_locator_history.
  • Device scans use run_kind=device_posture and a dedicated Redis queue and worker.
  • Web interfaces discovered on any TCP port are checked by hidden device_web_dast children. Those children have no Web target, cannot alter Web target or ASM statistics, and do not appear in the normal scan list or dashboard totals.
  • Device findings use source=device, have a device-scoped fingerprint, and are available through the Device filter without changing ordinary DAST posture metrics.
  • Device-worker build health is stored separately from the Web DAST worker registry. Adding or rebuilding device capacity therefore cannot make the ordinary DAST fleet stale or non-uniform.

Coverage profiles

ProfileTCP inventoryUDP inventoryTypical use
inventoryNaabu priority/device hints plus top 100 TCP ports; Nmap fingerprints open portsSmall common-device setFast reachability and first inventory
postureChunked Naabu CONNECT discovery of all 65,535 TCP ports; Nmap fingerprints open portsCurated discovery/management setNormal device assessment
thoroughChunked Naabu CONNECT discovery of all 65,535 TCP ports; deeper Nmap fingerprintingCurated discovery/management setHigher-confidence service posture

Every profile is scoped to exactly one hostname or IP. URLs, CIDR ranges, paths, credentials, and shell-like locators are rejected. The operator must explicitly confirm authorization before a scan is queued.

Coverage and safety are independent controls. inventory, posture, and thorough select how much of the device is inventoried; they never grant permission for more invasive actions. The separately recorded safety profiles are:

  • observe_only: discovery, banners, TLS/HTTP detection, and SSH posture handshakes. Web origins are inventoried but no Web DAST children are launched.
  • safe_remote: bounded non-destructive network checks and passive device-owned Web DAST. This is the default and preserves the original connected-device behavior.
  • authenticated_active: supplied-credential SSH and web checks with device-bound, encrypted credential profiles. It never guesses credentials. Fixed host review is read-only; model-authored remote SSH commands require a separate exact-plan user confirmation.

Older releases advertised a fourth lab_invasive profile that no worker ever implemented. It has been removed; a request that still names it is rejected and should use authenticated_active. Persistent-state, resource-intensive, and destructive action classes remain unavailable to every profile.

Every device action receives a declared safety class. The device safety governor blocks actions not permitted by the selected profile and records baseline, post-inventory, and final health checkpoints. If a previously healthy device degrades, the scan is halted and cannot produce an allow decision.

Before inventory begins, ShakerScan runs a bounded, multi-signal reachability preflight. It checks previously observed open TCP ports, operator-supplied hints, policy and credential-bound ports, a compact common-device set, and a class-specific set for media/TV, camera, printer, router/NAS, conference, building, or industrial equipment. Nmap host discovery tries ARP/ICMP plus the same TCP hints and curated UDP probes. One successful TCP connection, an explicit refusal/reset, or a real Nmap response reason is enough to prove that the network stack answered. DNS resolution, Nmap's user-set assume-up reason, timeouts, and silence do not. The receipt distinguishes online, unreachable, and inconclusive, records the evidence and check time, and is shown on the device list and detail page.

Media devices also receive manufacturer-aware hints when the inventory identifies Vizio, LG, Samsung, TCL, or Hisense. These include Vizio SmartCast 7345/legacy 9000, LG webOS 3000/3001, Samsung Smart View/Tizen 8001/8002, Roku ECP 8060, Android/Google TV remote and Cast ports used by multi-platform TCL/Hisense models, and Hisense VIDAA MQTT 36669. A probe is only a discovery hint: it is never rendered or evaluated as an open service without a positive response.

An inconclusive inventory preflight stops without expanding to all TCP ports. For posture and thorough, which already require all-TCP coverage, the requested all-TCP discovery may begin as a fallback and its result is reused as the main inventory rather than scanning the range twice. An open port or explicit closed-port response can then prove the device online; an all-filtered/silent result remains inconclusive. Until online status is positively proven, authenticated and later protocol actions do not run, and the scan produces neither a numeric score nor a grade.

TCP assessment is staged. A bounded priority pass checks common administration, media, printing, messaging, and nonstandard web ports first. Naabu owns TCP discovery for every profile. The inventory profile follows the priority pass with its top-100 scope; posture and thorough divide all 65,535 ports into bounded ranges. Connect concurrency is derived from the configured probe rate and socket timeout so a silently filtered host cannot turn a nominally fast run into an hours-long one. Each failed range is retried once, while confirmed ports from every attempt are preserved. Cancellation and repeated health degradation are checked between ranges. Nmap never replaces a failed all-TCP Naabu run: it runs expensive service/version fingerprinting only against confirmed-open TCP ports and separately checks the curated UDP set. Missing Naabu is therefore an explicit worker readiness failure, and an incomplete range stays visible as partial coverage.

The scanner records service name, product/version hints, CPE, transport, port, encryption state, hostnames, addresses, MAC/vendor evidence when visible, and bounded OS fingerprints. UDP coverage is deliberately curated because a complete UDP sweep is both slow and ambiguous; the report lists the exact requested UDP ports instead of claiming full UDP coverage. An Nmap open|filtered UDP result with no-response is retained as an inconclusive observation, not a listening service. It is excluded from policy evaluation and scoring unless a protocol response confirms the port as open. Scan reports and device details present these observations in a separate uncertainty section, so an operator can inspect the raw evidence without mistaking UDP silence for an exposed service. Successful tool execution is reported separately from coverage semantics. A completed Naabu scope means the reachable open-port inventory is complete from the scanner's network vantage point; it does not claim that silent TCP ports were distinguished as closed versus filtered. Failed ranges and unresolved UDP observations prevent an allow decision and preserve prior service history. Silence does not become a service or finding and does not reduce the vulnerability score.

Each report also carries a deterministic device-evidence/v1 graph. It normalizes the device, interfaces, services, inconclusive observations, web origins, tool executions, and health checkpoints into stable nodes, edges, and observations. This is the compatibility layer used by future protocol adapters and the AI-directed device investigator; adapters exchange normalized observations rather than requiring later stages to parse raw tool strings.

The first protocol-aware adapters cover SSDP/UPnP discovery and mDNS/DNS-SD service enumeration. They send one bounded unicast discovery message to the exact authorized device rather than widening scope to a multicast segment. Responses, advertised service types, server metadata, USNs, DNS-SD records, and UPnP LOCATION values are normalized into the evidence graph. A cross-host LOCATION is recorded as out of scope and is never followed automatically. A valid application response can promote an Nmap open|filtered observation to a validated UDP service; silence remains inconclusive. Both adapters now run in the fast inventory profile as well as the all-TCP profiles.

Protocol identity, versions and authentication

A listener is named by what it answered, never by its port number. Nmap's port-table guesses (method="table") and unknown results keep their conventional name only as port_hint; the service is unknown until a probe matched. After Nmap fingerprinting, every open TCP port Nmap could not name (unknown, tcpwrapped or table-only, up to 32 per address) is offered the native protocol adapters one at a time: the banner first, then the hinted protocol, then the other silent protocols (HTTP, TLS, Redis, Memcached, MongoDB, PostgreSQL, RDP, SMB, OpenVPN, PPTP, MQTT, AMQP). A port Nmap did name gets only its own adapter, for the structured fields. Adapters cover SSH, FTP, SMTP (with STARTTLS), POP3, IMAP, Telnet, MySQL/MariaDB, PostgreSQL, Redis/Valkey, MongoDB, Elasticsearch/ OpenSearch, Memcached, SMB2, RDP, VNC, PPTP, OpenVPN, MQTT, AMQP, Modbus and EtherNet/IP over TCP, and DNS, NTP, IKE and OpenVPN over UDP. Industrial adapters run only when Nmap or the port names that protocol.

Each identification keeps protocol, product, version (the upstream release) and version_reported (the exact announced string with its distribution build suffix, for backport-aware advisory matching) apart. PostgreSQL is identified by its pre-authentication refusal of an unsupported protocol version and claims no version. A listener that answered but matched nothing is not_identified; one that stayed silent is inconclusive; WireGuard, silent by design, is not_identifiable.

A handshake is protocol identity, not access. authentication stays not_tested unless a bounded, read-only exchange decides it, named in authentication_proof: Redis answering INFO, MongoDB listing database names (only the count is kept), Elasticsearch listing indices, Memcached answering stats, VNC accepting the None security type, an MQTT broker accepting a credential-less CONNECT, or the server refusing one of these (NOAUTH, Unauthorized, 401/403, RDP requiring Network Level Authentication). No credential is sent and no login is attempted.

TCP 9100-9107 (raw printer ports) are connected to but never sent a probe payload, as Nmap's own version detection excludes them; the coverage record lists the exclusion.

Servers, several addresses and CDN edges

The server device class prioritises remote administration, mail, VPN, database, cache, broker and container control-plane ports before the full sweep, so an internet-facing or internal server is assessed with the same engine: priority ports, chunked all-TCP Naabu discovery, Nmap on confirmed-open ports, the curated UDP set and partial-coverage semantics.

Every stage of a scan is pinned to one address. A hostname that publishes several A/AAAA records is scanned as one pinned child per address the destination policy admits (up to 8), in turn, sharing the scan's time budget; addresses the policy refuses are listed by name rather than dropped. The result keeps the first address as the primary view, merges services by transport and port with the addresses that showed each (observed_addresses), tags each finding with its connect_address, and is complete only when every child was.

Each address carries a coverage record (address_coverage): the TCP ranges attempted with their outcome, retries, the requested UDP ports and the exclusions. The full TCP sweep is resumable: ranges the latest posture scan left incomplete (a budget or health stop) run first in the next scan, right after the priority ports, so successive scans progress through the whole range. Every range still runs when the budget allows; earlier coverage is never assumed.

An address inside a shared CDN edge's published ranges (Cloudflare) is the provider's network, not the application's origin. Only the web ports the edge proxies are examined there, no UDP or full sweep runs, and the result says application assessed through the CDN; origin network not assessed (network_role). To assess the origin, register its explicitly authorized address as its own device and set the scan's server_name to the application's name: the scan connects only to that address and sends the name as Host and TLS SNI.

Web interfaces on any port

ShakerScan does not assume ports 80 or 443. After service inventory, it sends a bounded HTTP probe to each eligible open TCP service up to the declared profile probe cap, trying cleartext and TLS in the order suggested by the fingerprint. This can discover origins such as http://device:8008, https://device:8443, or an ephemeral vendor management port.

Discovered origins can receive passive quick, standard, or deep Web DAST coverage. Active Web DAST families are forcibly disabled, request and time budgets are capped, and at most 32 origins are handed off. Each merged finding retains the parent device, child scan, origin, connect address, Host header, and SNI provenance. Any probe or child truncation marks the assessment incomplete and prevents an allow decision.

SSH and service policies

SSH is checked on the port where it was actually discovered, not only port 22. The scanner records the banner, server host-key type and size, authentication methods, negotiated cipher/MAC, password and keyboard-interactive availability, public-key availability, and weak negotiated algorithms. It never guesses usernames or passwords. Under authenticated_active, an operator may attach one encrypted, device-bound SSH profile; offered methods are enumerated independently and the supplied credential is attempted at most once per device scan, subject to persisted cooldown and daily caps.

An authenticated scan may explicitly request the ssh-authenticated-host-review capability. Before the credential is submitted, ShakerScan requires a SHA-256 SSH host-key fingerprint from an earlier device observation and fails closed if the key changes. After authentication, the worker runs only server-owned read-only bundles for identity/runtime, interfaces/listeners, process and service names, accounts and bounded privilege metadata, mounts/hardening, packages, and update metadata. The model cannot supply shell text to this fixed capability. Each bundle has a timeout and byte cap; outputs are secret-scrubbed, hashed, and stored as device evidence. Collection failure is incomplete coverage, never a secure conclusion.

Agentic mode also supports agent-confirmed-ssh-shell when fixed collectors cannot answer the objective. The model may propose up to eight exact remote-device commands, but it cannot execute or approve them. ShakerScan shows the immutable command list, risk markers, device and port, pinned host key, timeout, expiry, and SHA-256 plan digest. A user must separately confirm both the exact commands and their possible effects. The single-use plan then runs on the isolated device worker without a PTY or forwarded stdin, with bounded, redacted, hashed output. This authority never grants local ShakerScan-host shell access and cannot transfer to another device, address generation, port, credential profile, or SSH host key.

Service policies are ordered rules with four outcomes:

  • allow: the observed service is expected.
  • deny: the service must not be listening.
  • review: the service needs an operator decision.
  • require: the service is permitted only when controls such as encryption, disabled SSH password authentication, no weak SSH algorithms, or public-key authentication are proven.

Unmatched confirmed-open services default to review. Required controls fail closed when they cannot be verified. ShakerScan ships generic, media-device, camera, printer, and network-appliance baselines. A device can use a selected custom policy; otherwise the closest active built-in policy is chosen by device class, with the generic fail-closed baseline as fallback.

Policy actions determine the final posture decision: deny and failed require controls block, review requires review, and allow is emitted only when all required inventory stages completed and no confirmed finding remains. The score and decision therefore cannot report an F-grade review set as policy-conformant.

Findings are auto-resolved only after a successful all-TCP assessment with untruncated web detection and complete web-child coverage. A fast or partial inventory never clears older findings.

REST workflow

# Read device-worker readiness
curl http://localhost:8080/devices/readiness

# Register one device
curl -X POST http://localhost:8080/devices \
  -H 'Content-Type: application/json' \
  -d '{"name":"Lobby display","primary_locator":"tv.example.lan","device_class":"media"}'

# Keep the same permanent device after DHCP changes its address
curl -X POST http://localhost:8080/devices/DEVICE_ID/locator \
  -H 'Content-Type: application/json' \
  -d '{
    "locator":"192.168.1.45",
    "reason":"DHCP assigned a new address",
    "confirm_same_device":true
  }'

# Queue an authorized full TCP posture scan with passive web handoff
curl -X POST http://localhost:8080/devices/DEVICE_ID/scan \
  -H 'Content-Type: application/json' \
  -d '{
    "profile":"posture",
    "confirm_authorized":true,
    "include_web_dast":true,
    "web_scan_type":"standard",
    "max_web_origins":8
  }'

Policy management is available at GET/POST /device-policies and PATCH /device-policies/{policy_id}. Device inventory is available at GET/POST /devices, GET/PATCH/DELETE /devices/{device_id}, POST /devices/{device_id}/locator, and GET /device-scans.

Stable identity and changing addresses

A TV or other DHCP client can keep the same ShakerScan device ID while its IP address changes. The device detail page's Change address action updates only the current locator. Policies, credentials, findings, services, scans, agent memory, and history remain attached to the permanent device UUID. Completed and queued scan records retain the exact locator they used.

The operator must confirm that the replacement locator belongs to the same physical device. This is deliberately not inferred from IP reuse: DHCP can give an old address to a different host. Address changes are blocked while a posture scan, service probe, or Device Hunt is active, preventing an in-flight operation from switching hosts. Prefer a stable local DNS/mDNS name where it is reliable; automatic MAC- or sensor-assisted relocation can be added later only with verified identity evidence.

Imported API requests

The device page accepts Postman Collection v2 JSON plus an optional environment, HAR 1.2 traffic, OpenAPI 3.x, and Swagger 2.0 JSON. Imported documents can contain tokens, cookies, authorization headers, IDs, request bodies, and captured responses, so ShakerScan encrypts the complete payload and publishes only a redacted request inventory. Postman pre-request/test scripts and HAR responses are never executed.

During a device scan, selected collections are decrypted only inside the dedicated device worker. Postman variables and authentication definitions are resolved in memory. HAR preserves captured request order, headers, cookies, and bodies. OpenAPI/Swagger generates bounded examples from examples, defaults, enums, and schemas; only local JSON Pointer references are resolved, and no external reference is fetched. An optional device base URL can supply a missing specification server. A separately bound web credential can be inherited in worker memory without entering the document or Device Hunt transcript. Every socket is still pinned to an HTTP(S) origin positively discovered on the registered device; an imported URL, server declaration, redirect, variable, or environment value cannot send the scanner to another host. Imported URL ports are also added to reachability priority hints.

Quick coverage replays saved safe methods. Standard and Deep add an authentication-removal comparison for safe authenticated requests. POST, PUT, PATCH, and DELETE are skipped by default; exact replay requires the authenticated_active safety profile and a separate explicit confirmation for that scan or Device Hunt session. Imported file bodies and unsupported body modes are skipped with a request-level reason. Results retain redacted per-request status, timing, body size/hash, header names, skipped reasons, and request-aware findings without persisting request secrets.

HTTPS interfaces are assessed with a separate strict certificate handshake. Self-signed and otherwise untrusted device TLS does not hide the interface: non-secret checks continue and create a TLS finding. Selected credentials and imported requests continue under the existing testing authorization; certificate trust adds no second confirmation or veto. The legacy allow_untrusted_tls_credentials field remains accepted but does not control execution. Credential and state-changing permissions remain enforced, and unverified TLS transmission is recorded as evidence, never labeled trusted. Response cookies, authentication challenges, URL query values, token-like path segments, and token-like request names are redacted before persistence.

After service discovery, a server-owned platform catalog recognizes Roku ECP, Vizio SmartCast, Samsung Tizen, LG webOS, Philips JointSPACE, Google Cast/DIAL, Panasonic VIERA, and Sony BRAVIA. Same-device SSDP descriptions are fetched and parsed to recover device identity, service schemas, control URLs, and nonstandard web origins. Bounded read-only platform probes then confirm application endpoints and authentication boundaries. Cleartext device APIs, unauthenticated privacy-sensitive reads, exposed version details, TLS failures, cookie defects, CORS behavior, and authenticated-versus- anonymous response equivalence become device findings with request evidence. Control and mutation families remain fully testable through exact confirmed imported requests and Device Hunt authority; they are not silently treated as unsupported merely because automatic discovery is read-only.

The device detail page displays a structured activity feed while a selected scan is running. It shows reachability, discovery, fingerprinting, web/API execution counts, failures, findings, and safety stops while suppressing command noise, payloads, and secrets.

Device targets in Hunt

Connected devices use ShakerScan's canonical, target-kind-aware Hunt runtime. The current Codex, Claude, OpenCode, or Pi session is the planner, while ShakerScan executes a closed device capability contract. Start through POST /hunts, drive only capabilities returned by that run, and confirm an immutable SSH plan through POST /hunts/{hunt_id}/shell-plans/{plan_id}/confirm. The former /devices/{device_id}/agent/session and /device-agent/session/* writes are quarantined migration surfaces; their UI URL redirects to /hunt.

Device Hunt compatibility wording refers to the device-target Hunt capability pack derived from the Smart TV assessment playbooks. GET /devices/{device_id}/capabilities resolves each capability as ready, completed, blocked, planned, sensor-required, lab-only, or not applicable using current device evidence, credentials, platform hints, and sensor readiness. inspect_capabilities refreshes this view during an investigation. The catalog guides planning. Registered deterministic capabilities execute within their contracts; the SSH shell capability additionally requires a separately user-confirmed immutable plan.

The Device Hunt tools can inspect the registered device, capability pack, and user-bound redacted request collections; queue a deterministic device or request-aware scan; inspect a device-owned scan; query normalized graph evidence; and retain bounded notes. A run is fixed to one device_target_id and one safety profile at creation. Tool arguments contain no locator, credential, arbitrary URL, local-host shell, plugin, or safety-escalation field. The planner can only propose remote-device SSH commands; confirmation is not a planner tool. Sessions are capped at 30 turns, 36 tool actions, six calls per turn, and three queued scans. Concurrent agent sessions and concurrent device scans for the same device fail closed.

Device Hunt cannot create authoritative findings directly. A final AI debrief may retain evidence-backed, typed candidates only when they cite real devref_N references created by device context, scan-result, or evidence-graph reads. Candidates have a durable lifecycle (new, queued/verifying, verified, refuted, inconclusive, blocked, or expired), a canonical device locus, and a registered verifier contract; notes, queue acknowledgements, and model prose are not proof. The verify_candidate tool resolves scope and probe inputs from the persisted candidate. Registered server-owned verifiers cover policy-denied service exposure, strict TLS identity failure, authenticated-versus-anonymous imported-request equivalence with a negative control, pinned-host-key SSH policy violations, and exact CPE/version matches against a SHA-256-pinned offline advisory snapshot. Each promotion requires fresh or hash-pinned deterministic evidence satisfying Proof Contract v2 before it can create a device finding, verification record, and typed evidence instance. Control-authorization claims abstain unless an exact read/mutate/read/restore/read contract exists. The verifier supports only fixed server-validated restoration adapters bound to an imported request: an explicit inverse request, one query parameter, one JSON field, or one form field. The restoration value comes from the pre-test response at a declared JSON pointer, never from model text. Device Hunt cannot select arbitrary cleanup code or invent a mutation. Every posture scan re-correlates the pinned advisory snapshot, and resolves an old advisory finding only when the same service locus was observed again and no longer matches. Silence is never treated as remediation.

Firmware and package advisories also preserve evidence tiers. Unauthenticated banners, Nmap product strings, SSDP metadata, and model names remain candidates; they cannot establish an exact vulnerable version. Promotion requires an authenticated host review, signed manifest, or another authoritative identity source tied to the exact observed service locus.

Offline advisory snapshot

Exact CPE/version promotion is backed by a compact, hash-pinned advisory snapshot rather than a live vulnerability feed, so device workers make no external calls and no unverified data can silently change matching behavior. The bundled snapshot lives at scanner/data/device_advisories.json under the shakerscan-device-advisories/v1 schema. It is loaded only through the real loader (scanner/scanner_tools/device_advisories.py), which requires a regular file whose SHA-256 matches the pinned digest; a mismatched or missing file fails closed instead of degrading to unpinned data.

Only advisories with explicit NVD version bounds (or an exact version) are included; unbounded wildcard configurations are signal-only and are never emitted into the snapshot, so any promotable match is provably version-bounded. The loader pins the bundled copy by BUNDLED_SNAPSHOT_SHA256; the release image sets no DEVICE_INTEL_DB_* variables (setting them is an operator pin that also freezes out signed bundles), and tests reject drift between the file and the loader constants.

An operator can substitute a newer or site-specific snapshot without rebuilding by pointing the same two environment variables at a regular file and its SHA-256; DEVICE_INTEL_DB_SHA256 is mandatory, so an unpinned override is rejected. Values are resolved at read time with the environment taking precedence over the bundled fallback.

The snapshot is refreshed at release time with scripts/generate_device_advisories.py (stdlib only, no API key; it honors the unauthenticated NVD rate limit). Typical refresh:

# Curated CVE selection against the live NVD API 2.0
python3 scripts/generate_device_advisories.py \
  --cve CVE-2017-17562 --cve CVE-2023-38545 ... \
  --output scanner/data/device_advisories.json --self-check

# Or product-wide queries for an embedded product
python3 scripts/generate_device_advisories.py --vendor mosquitto --output /tmp/mosquitto.json

The generator prints the new SHA-256 plus the exact DEVICE_INTEL_DB_PATH/DEVICE_INTEL_DB_SHA256 override lines. --self-check validates the written file through the real scanner loader and confirms every record is bounded and promotable; --verify PATH runs the same validation against an existing snapshot; --offline emits only the generator's built-in curated seed with no network access; and --from-raw DIR rebuilds deterministically from cached NVD API responses. After a refresh, copy the printed SHA-256 into BUNDLED_SNAPSHOT_SHA256 in scanner/scanner_tools/device_advisories.py and the snapshot's generated_at into BUNDLED_SNAPSHOT_GENERATED_AT; the drift tests fail until they match. Between releases the same snapshot can be shipped as a signed bundle (see Service intelligence).

Wireless and non-IP extensions

Bluetooth, BLE, Zigbee, Thread, and passive network telemetry require hardware or network placement that a normal Docker worker cannot safely assume. The readiness response advertises these as optional sensor capabilities, but this release does not claim radio coverage. The intended extension point is a separately enrolled, capability-labeled sensor that submits normalized device/interface/service evidence into the same device model while preserving the dedicated queue, authorization, provenance, and policy boundary.

Current limits

  • The scanner observes the network path visible from its device worker; NAT, firewall rules, VLANs, and client isolation can hide services.
  • A silent reachability check is inconclusive, not proof that a device is offline. Wake the device or move the worker to a network path that can reach it, then scan again.
  • Service and OS fingerprints are evidence, not guaranteed product identity. Stable MAC identity is unavailable across routed networks and can be randomized.
  • UDP coverage is a declared curated set, not all 65,535 ports.
  • SMB is identified by an SMB2 negotiate; a server that speaks only SMB1 is not identified. L2TP and DNP3/S7 have no adapter: an open conventional port is reported as a hint, never as the protocol.
  • A multi-address scan stores the union of services in the device's service table; per-address detail stays in the scan result (addresses). The pinned Web DAST handoff for an origin examined under server_name keeps the address-based origin.
  • CDN edges are recognised from Cloudflare's published ranges; other CDNs are named only from their response headers after an HTTP exchange.
  • UDP silence is inconclusive. Firewalls can make closed and open UDP ports look identical from the worker's network path, so only a protocol response is treated as confirmed open.
  • Cloud metadata/control-plane addresses are denied by default after DNS is pinned. Authorized public devices remain supported; operators can extend the deny CIDRs for their environment.
  • No credential guessing, firmware extraction, destructive protocol testing, radio probing, or active XSS/SQLi is performed by the device workflow.
  • Postman scripts, HAR responses, external OpenAPI references, and imported external hosts never execute. State-changing request replay is disabled unless the user explicitly binds collections and grants that fixed authority under an authenticated-active scan or Device Hunt session.
  • Fixed authenticated host collection accepts only server-owned read-only bundles. Agent-authored remote SSH commands execute only after an earlier host key is pinned and a user separately confirms the exact digest-bound plan; local-host shell is never exposed.

Hunt service selection and managed authentication

An authorized active Hunt may select HTTP or HTTPS on any valid port of its existing canonical host. This is a per-action service selection: target UUID, frozen IP addresses, scope, credential version, and revocation checks remain unchanged. A redirect or imported script cannot authorize a different destination.

auth.session.establish accepts an optional origin for relative saved login endpoints; absolute operator-saved endpoints select their own same-host service. New Hunt sessions retain the admitted asset binding plus their login service, so an explicitly selected session works in subsequent same-asset requests and refresh returns to the original login port. Historical exact-bound sessions remain readable; Scan sessions retain exact binding. browser.login_check accepts an optional origin, or derives it from the immutable saved workflow. Credential decryption still occurs only in the worker. Device credentials are revalidated against the live device inventory, not the separate web-target table.

Request-collection replay resolves only the selected, persisted collection origins against the same admitted asset, then narrows the replay transport to those origins. Collection ownership, selection digests, frozen addresses, budgets, and secret handling are unchanged. This does not authorize reuse between unrelated target UUIDs.

Device authorization investigations use the same API/service/repository as web Hunts. Their graph records belong to device_target_id; an additive migration supports device HTTP sessions and graph ownership without manufacturing web targets. Native device adapters inherit the canonical Hunt request and scan limits rather than applying a second legacy 40-request / three-scan ceiling.

Hunt NSE transport and coverage

service.nse_check retains the installed Nmap analyses for http-methods, http-security-headers, http-trace, and ssl-enum-ciphers. The HTTP analyses use the worker's pinned transport, preserving Host and TLS SNI on the frozen address. Same-asset HTTP/HTTPS redirects, including alternate ports and untrusted certificates, reuse existing network authority; no per-hop approval is created. A redirect to another asset is recorded as incomplete coverage, and other selected checks continue. Evidence includes the actual response service and redacted URL.

HTTP discovery uses metered HEAD requests instead of an implicit -sV version scan. Native TLS enumeration is forced on the explicitly selected port, including nonstandard ports; broader fingerprinting remains service.fingerprint. HTTP budgets count every request-header attempt, including connection-library retries, detector requests, and permitted optional method probes. Unused HTTP allowances are released. Native port/TLS device cost is still an estimate, not a claim of exact handshake or packet counting.

The method analysis can probe POST and an unknown method as negative controls. Those probes use the existing allow_state_changing_http permission and budget. Without it, Hunt preserves the available read-method observations and explains which optional probes were omitted instead of refusing the entire capability. An incomplete script is not a clean security result; observations remain unverified until a separate deterministic proof contract validates a finding.

NSE coverage outcomes do not stand in for a device health checkpoint. Repeated partial results (closed services, unavailable script output or optional omissions) do not trip the health circuit breaker, and a completed NSE action does not clear a pre-existing failure or operator pause. Traffic usage and pacing still settle; other capabilities retain their actual health-check behavior.

This page is rendered from docs/connected-device-security.md in the open-source repository at v2.12.2. When documentation and implementation disagree, the code, database schema, and tests at that tag are authoritative.