Skip to content

UTMStack: static internal-key header auth bypass + any-user agent command transport (Oct 2 21:32Z)

Source: hourly offensive-security scan of GitHub Security Advisories, 2026-10-02. Six GHSAs published 21:32Z for UTMStack before 11.2.16, an open-source SIEM/UTM management platform with a microservice backend and an agent fleet. Two of the six are near-critical and carry durable axes the wiki hasn't catalogued in this shape; the rest land on existing canonical classes and are folded here as one wave.

Why this matters to an operator: a SIEM/UTM manager is a credential-dense, agent-riddled target class (same reasoning as the Oct 2 Zammad helpdesk KEV page): it stores integrations credentials, indexes the whole estate, and runs root/SYSTEM agents on monitored endpoints. Fixing one login page proves nothing about the service-to-service auth side door or the WebSocket command bus next to it.

1. Utm-Internal-Key: the static env-var header that is the admin API (CVE-2026-82042 / GHSA-phx4-fx7q-vfw9, 9.8)

InternalApiKeyFilter accepts a valid Utm-Internal-Key header matching the INTERNAL_KEY environment variable for any endpoint, with no path restriction, no constant-time comparison, no rate limiting, and no audit logging. An attacker who learns the key value authenticates with no user account and no JWT — then creates accounts, manages users, exfiltrates data, and edits security rules.

Operator axes:

  1. Internal-service header families are a standing probe list. Microservice backends routinely ship an "internal" auth header (X-Internal-Key, X-Internal-Token, X-API-Key, service-name variants) whose secret is an env var or a committed compose/manifest default. For any multi-service app, sweep known/internal header names against the public API edge with plausible values: committed defaults, the product name, and values leaked from any sibling disclosure (.env reads, debug endpoints, error bodies, source). A 200 where the browser flow needs a JWT = the side door is public.
  2. The bypass is invisible by design. The filter logs nothing, so the strongest post-exploitation signal is absence of expected auth events. On authorized engagements, the detection-resistance property is itself report-grade detail.
  3. Non-constant-time comparison of a header secret is a timing-oracle candidate — the advisory states the comparison is not constant-time; lab-position timing against a wrong-but-same-length key is a legit proof shape where network noise allows.
  4. Fingerprint the key's blast radius: the filter gates every endpoint, so once held, enumerate the full route tree (this platform exposes asset groups, network scans, identity providers, incident commands — see legs below) rather than the handful the UI uses.

2. Any authenticated user can run OS commands on every agent via the STOMP command bus (CVE-2026-82041 / GHSA-q995-ggc5-8fmx, CVSS 9.9)

UTMIncidentCommandWebsocket.processCommand() — the handler mapped to the /command/{hostname} STOMP destination — applies no role check and no command allowlist before forwarding caller-supplied commands over gRPC to any connected agent, where agent processes commonly run as root or SYSTEM. Read literally from the description: any authenticated user, regardless of role, sends arbitrary OS commands to any monitored endpoint by hostname.

Operator axes:

  1. Authorization is enforced at the REST layer; the message transport beside it enforces nothing. On any product with WebSocket/STOMP/SockJS/SignalR surfaces, enumerate destinations (/command/*, /topic/*, /queue/*, /app/* via CONNECT + subscribe/send probes) with a lowest-privilege lab principal and diff against the REST permission model. A destination a Viewer-role user can SEND on is the finding. This is the transport-parity sibling of the alternate-surface drift already canonized on the Sept 19 WP and Sept 21 precedence pages — the transport is the alternate surface.
  2. Hostname/enrollment identifiers are the target selector. The destination embeds {hostname}, so a host inventory (from any enumeration leg, DHCP logs, or the asset-group search below) converts one beachhead credential into fleet-wide execution. On pentests, the agent-command destination + an asset inventory is an instant lateral-movement map.
  3. Command-allowlist absence: test with an inert marker command (id, hostname) in a lab only; on customer-approved systems, prefer proving reachability (response shape on a benign verb) over execution.

3. Same wave, canonical-class legs (folded, no new axes)

  • Native-query SQLi via String.format() — UtmAssetGroupService.searchQueryBuilder() interpolates assetType/groupName into a native PostgreSQL query reachable at GET /api/utm-asset-groups/searchGroupsByFilter with DBA privileges (CVE-2026-82039 / GHSA-2c66-2qvh-84xr, 8.8), and the JPQL twin searchPropertyValues() builds JPQL with String.format() + em.createQuery(), letting an authenticated user exfiltrate entity tables incl. jhi_user credentials (CVE-2026-82045 / GHSA-ggxr-hwjj-pgmj). String-concatenation-into-native-query and JPQL-injection classes are canonical (Sept 18 ORM query-grammar page; YesWiki deferred-SQLi page). One fingerprint takeaway: the Spring Boot scaffold (jhi_user table name) marks this as a JHipster-generated app — JHipster-shaped apps inherit this scaffold's route families; grep-scan generated-codebases for String.format near createQuery/native queries during white-box reviews.
  • SSRF pair with two render/scan channels: PdfService.downloadPdf() fetches an unvalidated url and renders the fetched content into the returned PDF — internal backend endpoints, the OpenSearch cluster, or cloud instance metadata readable in the artifact (CVE-2026-82044 / GHSA-hg4r-wjvj-4cww); IdentityProviderService.validateMetadataUrl() fetches caller-supplied IdP metadata URLs with no host/IP/scheme validation = internal port-scan + metadata access (CVE-2026-82040 / GHSA-w93c-mfp3-35p4). "Report/PDF generator SSRF = response read-back through the generated document" is the final-destination-proof pattern already on the SSRF pages; the metadata-URL validator that fetches before validating is the SAML/OIDC metadata class from the Oct 1 Authlib fold. Proof stays bounded to owned callbacks and lab-internal canaries.

Validation workflow (lab scope only)

SIEM = the estate's data lake

UTMStack-class platforms index real credentials and endpoint telemetry. All proofs run against a disposable instance with synthetic assets/users/agents. Never send commands through a customer's production agent fleet; the STOMP leg proof is a lab agent + id-class marker, and the internal-key leg is a single request with a lab-set value plus the negative control (no header → 401).

  1. Internal-header probe matrix: public edge × {X-Internal-Key, Utm-Internal-Key, X-Internal-Token, X-API-Key} × {absent, empty, product-name default, env-leaked value}; compare against a JWT-authenticated positive control on one harmless GET route.
  2. Transport parity sweep: CONNECT a STOMP session as the lowest-privilege lab user, SEND /command/<lab-agent> with an inert marker, table accept/reject per role.
  3. Route-vs-transport diff: replay three representative REST actions (read asset group, write config, generate report) through both transports and diff the authz decision.

Follow-up (Oct 3 12:31Z): NASA AIT-Core — the same bus class, one layer lower (CVE-2026-105105 / GHSA-9xfm-37f4-2h8g, 9.8)

AIT-Core through 3.1.1 (NASA AMMOS Instrument Toolkit, the flight-software ground toolkit for small satellites/rovers): the ait-server telemetry/command broker binds its ZeroMQ XSUB/XPUB sockets to all interfaces by default with no authentication and no transport security. Reaching TCP 5559 lets an unauthenticated attacker publish onto internal topics — including the __commands__ command topic, whose messages are forwarded through command_stream and emitted on the command-uplink UDP path with the shipped defaults. Reaching TCP 5560 subscribes to all command and telemetry traffic on the ground bus. 3.1.2 changes the default binds to loopback only. A sibling advisory (GHSA-3j6g-pxmx-58qg, 9.8) covers the AIT GUI with the same missing-auth pattern.

Operator axes (generalizing the STOMP lesson above to raw message buses):

  1. ZeroMQ pub/sub is a standing scan class across robotics, ground-segment, and industrial middleware. In the XSUB/XPUB pattern, any reachable peer is a legitimate-looking publisher — there is no handshake and no identity, so injected messages are indistinguishable from components downstream. Product families to check for exposed 555x-family/ephemeral-ZMQ ports: spacecraft ground stacks (AIT-Core, similar AMMOS toolkits), robot/autonomy middleware bridged over ZMQ, ad-hoc service buses in embedded appliances.
  2. The protocol probe is one byte. A TCP connect plus an XSUB join (\x01 + topic prefix, legacy \x00 on old XPUB) subscribes you to every matching publish with no auth exchange — non-HTTP open ports that answer a raw join with live structured traffic are the finding. Enumerate topics by prefix-widening ("" = everything) and fingerprint command vs telemetry topics from message shape.
  3. Blind-injection proof shape: publish to a command topic is often unobservable from the attacker side; pair it with the subscribe leg (which proves bus position and shows whether your own injected frame echoes back on the bus) before claiming command-path impact. Uplink emission, actuator/telemetry forging, or station disruption require the matching sink — on authorized ground-segment engagements, prove with a lab bus bound to a test rig, never a live station.
  4. Default-bind fail-open is a three-grep fingerprint for white-box review of any broker/daemon: bind("tcp://* / tcp://0.0.0.0 near socket setup, plus presence/absence of an auth or curve(zmq) wrapper. The fix here is literally the bind address — same "loopback by default vs network by default" axis as every agent-manager and dashboard page on this wiki.

Follow-up (Oct 5 18:34Z): Velociraptor — wrong-predicate, wrong-scope, and unguarded-artifact legs in a DFIR fleet manager (CVE-2026-78411 / CVE-2026-78412 / CVE-2026-78413)

The same 18:34Z wave published three advisories for Velociraptor, the open-source DFIR/endpoint-visibility platform — the same target class as this page (a server that commands an agent fleet, now with multi-tenancy). All three are medium-severity role-prerequisite findings, and all three are textbook instances of axes already on this wiki:

  • Wrong permission predicate (CVE-2026-78411 / GHSA-gpw6-25f6-673m): SetClientMetadata enforces LABEL_CLIENTS where the action writes server-wide metadata that is supposed to be admin-only — a label-permitted user mutates site-wide configuration. The check exists; it names the wrong permission.
  • Caller-scope vs requested-scope (CVE-2026-78412 / GHSA-83qj-9c78-grhx): the WatchEvent gRPC API accepts an OrgId parameter and validates the caller's permission in the caller's own org, never in the requested org — a user with API access in one org streams events from any other org. This is the OpenAM _queryFilter / ZITADEL x-zitadel-orgid target-scope axis landing in a DFIR server's event bus.
  • Parameterized artifact without its required permission (CVE-2026-78413 / GHSA-9q45-6cc2-4qjv): Windows.Sysinternals.SysmonLogForward takes an arbitrary binary path parameter but never declares the EXECVE requirement, so an Investigator-role user (COLLECT_CLIENT, normally read-only collection) collects the artifact with a swapped binary path and gets arbitrary program execution on endpoints — the agent-command primitive reached through a legitimate artifact instead of a raw command destination (the UTMStack /command/{hostname} sibling above).

Operator axes:

  1. Permission-exists-but-wrong is invisible to route-enumeration sweeps. A request that carries a permission check passes every "missing authz" probe; only the role differential exposes it. Build a role × action matrix with one disposable account per role and test each sensitive write from the lowest role whose grant list nearly covers it (LABEL_CLIENTS, COLLECT_CLIENT). The near-miss role is the audit target, not the guest.
  2. gRPC/API parameters that name a tenant (OrgId, org_id, X-Tenant, realm) must be authorized against the target, not the caller. Replay one read with the scope parameter pointed at a foreign lab org from a single-org principal; accept/reject per scope is the decision table. Same sweep applies to every streaming/watch/subscribe verb — long-lived streams are routinely audited less than request/response routes.
  3. In artifact/collection frameworks, the parameter set is the permission boundary. Audit every shipped collection template for parameters that name binaries, paths, or URLs, then diff each template's declared permission requirements against what its parameters actually enable. One missing EXECVE-class declaration converts a read-only analyst into a fleet-wide runner — same shape as allowlist-absence on the STOMP leg above, reached one layer up through the feature catalog.
  4. Proof discipline: disposable server + lab agents only; the artifact leg proof is an inert marker binary (whoami-class) collected against a lab endpoint, and cross-org proofs use synthetic event streams in two disposable orgs.

Tracked without publication (same 21:32Z wave)

  • Digi appliance CVE-2026-75937 unauth root POST → cmdi (critical, zero sink detail; revisit when the vendor advisory lands).
  • Microsoft Exchange CVE-2026-96940 weak-authorization privilege escalation (8.8, description-free vendor text).
  • H3C CVM CVE-2023-54405 / Weaver e-Bridge CVE-2020-37278 late-backfill publications (old classes, no new axis).
  • Trivy CVE-2026-104994 Terraform filesystem-function traversal above scan root during misconf scans of untrusted PRs (low; scanner-reads-outside-root class noted, revisit if a leak-channel pattern generalizes).
  • Canonical MAAS CVE-2026-12392 info exposure; postgresql-operator charm CVE-2026-104055 exporter logging the monitoring password in cleartext on connection errors (log-credential-leak class).
  • Phproject CVE-2026-104991 REST API never calls its own allowAccess() (missing-call class canonical on the Sept 21 pages); Wallstreet WP CSRF + AIO SEO shortcode-processing single.
  • Detail-free six-pack of same-product advisories (CVE-2026-90452–90457: reverse-proxy→IdP calls without cert verification, Referer-driven upload redirect, weak admin hash + world-readable hash file, shipped default admin password, read-only-mode tag-route deny-list gap, reverted HTTP-client bump) — vendor unnamed in summaries; the no-cert-verify leg and shipped-default leg land on existing classes; revisit when the product identifies itself.

October 7 follow-up: oc-mirror embedded cache registry binds 0.0.0.0 unauthenticated — mirror-content tampering from adjacent network (CVE-2026-96577 / GHSA-gh86-jqm4-pwg7, high)

During mirroring, oc-mirror's embedded local cache registry binds all interfaces with no auth and no encryption instead of loopback: an unauthenticated adjacent-network attacker pushes tampered images into the cache, deletes cached images, or reads mirrored content — and the poisoned cache is what subsequent oc-mirror image-set exports ship to air-gapped/disconnected clusters.

  • Durable local-recon/attack primitive, generalizing this page's transport-side-door reasoning: embedded helper registries, build caches, and mirror components routinely bind 0.0.0.0 while their operator assumes localhost-only. Standing scan rule on any host: enumerate listening sockets owned by build/mirror/CI tooling (ss -tlnp greps for registry-ish ports 5000/5001/15000+, or find the embedded registry binary and check its bind address); on shared/air-gap-staging hosts these are no-auth write surfaces. Cache-write = supply-chain: the integrity boundary of every downstream cluster starts at whoever can push to the cache. Validate only on owned hosts/disposable image sets; a presence-only proof (unauthenticated catalog listing from a second lab host) is sufficient — never inject images into a live mirror feeding real clusters.

October 7 follow-up: LMCache unauthenticated ZeroMQ ROUTER with auto-pickle extension type — one DEALER message to pre-handler RCE (CVE-2026-105192 / GHSA-vv44-hjm2-qw2f, 9.8 critical)

LMCache (the KV-cache layer sitting under vLLM-class inference stacks) multiprocess/distributed mode opens an unauthenticated ZeroMQ ROUTER (default transport port 5555) so workers can register and share cache blocks. Messages are msgpack, and extension code 1 is passed straight to pickle.loads inside DeviceIPCWrapper.Deserialize while the server is still decoding request arguments — before any handler runs. A single unauthenticated ZMQ DEALER message to the port therefore executes code as the LMCache process user; official container images run that process as root. The socket binds localhost unless the operator passes --host with a routable address — which is exactly how legitimate multi-node deployments let peers connect, so every distributed LMCache/vLLM-KV deployment is the target population.

This sharpens the AIT-Core ZMQ rule above into a stronger generalization for the whole class:

  1. Parsing IS the boundary on message buses — deserialization gadgets fire before authorization exists. The AIT-Core leg showed command routing on an unauthenticated bus; here the sink is even earlier: codec-level pickle.loads on a registered msgpack ext type runs during argument decode, so no handler gate, role check, or topic allowlist can intervene. Audit any ZMQ/IPC service that registers msgpack ext/cbor-tag hooks: msgpack.Packer(default=...)/ext_types=/ExtType near a pickle.loads/yaml.unsafe_load/torch.load deserializer call is a pre-auth RCE fingerprint, greppable white-box in one pass.
  2. AI-serving sidecar ports are a standing external scan class. vLLM/LMCache/Mooncake-class stacks add aux ports (ZMQ, nixl, RDMA-gateways) that don't appear in the serving API docs an operator secures. On authorized AI-infra engagements, enumerate every non-HTTP listener on inference hosts, probe the 555x/ZMQ band first with the XSUB join / DEALER envelope from the AIT-Core rules above, and check whether any well-formed frame elicits a structured reply — a ROUTER answers a DEALER frame with zero auth exchange.
  3. The localhost-bind default is only as good as the deployment flag. --host 0.0.0.0/routable bind for "multi-node" is the same default-bind fail-open axis as oc-mirror above, reached through an operator flag instead of a code default — from outside, distinguish the two only by banner/response shape. Proof discipline: lab LMCache with a disposable peer, one ext-code-1 frame carrying an inert whoami-class pickle canary against a lab process; never poke shared inference clusters, and never replay production cache-block traffic.

October 7 (18:32Z) follow-up: LMCache HTTP control-plane four-pack — a guarded-exec sandbox that leaks its own host, self-writable allowlists, and /env as a credential read (CVE-2026-107204 / -107206 / -107205 / -107207)

The same LMCache product published four more advisories eleven hours after the ZMQ leg, this time on the multiprocess-mode HTTP servers (management HTTP, fleet coordinator HTTP, frontend monitoring service) — all bind all interfaces by default, all unauthenticated:

  • POST /run_script guarded-exec sandbox leak (GHSA-xgvf-x9rh-chj9 / CVE-2026-107204, 9.8): posted Python runs with a guarded __import__, but the execution scope contains the injected FastAPI app object — walk from it to recover real __builtins__, then import os and run commands as the LMCache process. The "guard" was a name restriction on an interpreter whose scope already contained everything needed to defeat it.
  • GET /env and GET /config on the management endpoints (GHSA-3m4j-8j42-jwr9 / CVE-2026-107206, 9.4): environment-dump and config-dump routes on the default-bound HTTP server = plaintext credential read (this class of app puts endpoints/keys in env); plus cache clear/delete and tenant-quota modification to evict other tenants' cached data — quota is an authorization boundary enforced by a writable number.
  • Fleet coordinator control API (GHSA-87j8-jqhj-hfm7 / CVE-2026-107205, 8.6): /instances register/deregister, /quota overwrite, /events injection, /directory/keys enumeration — placement-metadata disclosure and cross-tenant cache disruption from one routable port.
  • Proxy allowlist the attacker can write to (GHSA-hrhp-726g-9jqc / CVE-2026-107207, 7.2): the frontend monitoring service fetches only allowlisted hosts — but POST /api/proxies registers arbitrary new hosts into the allowlist, after which /proxy and /proxy2 read internal services. The SSRF guard's state is the product's own config, writable through the same unauthenticated surface.

Operator axes:

  1. A guarded-eval/__import__ restriction inside an app scope is theater if any app object is in scope. The escape needs no exotic gadget: reachability to any framework object → __class__/__mro__/module chain → real builtins. White-box grep: any exec/eval whose namespace is built from app/router/request objects; black-box proof: type(app)-class expressions in a lab /run_script-equivalent. This is the same "guard checked at the wrong layer" family as the LMCache ZMQ pickle leg — the mitigation named in the advisory text (guarded import) tells you exactly what to defeat.
  2. /env, /config, /debug/* verbs on internal HTTP servers are first-request credential reads. When any service's admin/monitoring HTTP port is routable, GET /env before anything else; it is the same class as the Quasar dev-error process.env dump (June 9 page) shipped as a production route.
  3. Enumerate allowlists that are runtime-writable config. Any "only fetches approved hosts" feature backed by a REST-writable store (proxies, webhooks, redirect tables, JWK URIs) has an allowlist-bypass leg one POST away — the OpenAM jwks_uri and Actual cors-proxy rules generalized: audit the write path of every security-relevant list, not just the read-path enforcement.
  4. Tenant quota is an access-control field. If tenant A can write the quota number that governs tenant B's cache/session/queue retention, cross-tenant disruption is a PATCH away. Sweep quota/limit/retention fields for ownership binding, per the Payload field-ACL rule.

October 8 17:5xZ follow-up: the JHipster scaffold itself — reactive sort= SQLi and Blob-ContentType stored XSS in generated code (generator-jhipster < 9.4.0)

The page's jhi_user fingerprint takeaway just compounded: the generator this app inherits from shipped two legs of its own (published 2026-10-08T17:40Z, fixed generator-jhipster 9.4.0).

  • SQLi in the sort parameter of every reactive (WebFlux + R2DBC) generated app (GHSA-r223-96jv-q533 / CVE-2026-107375, 8.8): the template createOrderByFields() renders order.getProperty() as an unquoted SqlIdentifier into ORDER BY, and because the generated R2DBC query has no bound parameters the driver uses the simple query protocol — ;-separated stacked statements execute. One self-registered low-priv user reads jhi_user hashes, modifies/drops data; reproduced on default H2 and PostgreSQL 16. The JPA path is not affected (metamodel validation) — the reactive/WebFlux edition choice is the fingerprint: on any JHipster-shaped app, ?sort= probing with (select ...)/stacked-statement canaries on GET /api/<entity> distinguishes reactive-scaffolded deployments, and self-registration is the entry. ORDER BY injection genealogy: same client-supplied-sort-column family as the Sept 23 MyBatis-Plus concatOrderBy leg.
  • Stored XSS via unrestricted Blob <field>ContentType opened same-origin (GHSA-9ffp-22j7-56r2 / CVE-2026-107303, 7.6, also react-jhipster <=1.0.3): generated entity endpoints (no per-method @PreAuthorize unless configured — global /api/** rule = any authenticated user) persist an attacker-declared MIME string; the generated openFile() client helper builds new Blob([data], {type: contentType}) + objectURL + window.open — attacker HTML/SVG opens as a document on the app origin. Validation-target vs render-target mismatch: content type is stored unchecked server-side and consumed as a trust declaration client-side. Probe: on any JHipster-shaped app, upload blob entity content <svg onload=marker> with contentType: image/svg+xml from a disposable user, open via the UI as a second user, observe same-origin render (CSP-gated, record it).
  • Durable rule: generated code is a shared zero-day across every app from the generator. On engagements against scaffolded stacks (JHipster, Yeoman family, enterprise blueprints), check the generator version like a dependency version — one template fix fans out to thousands of deployments, and the scaffold's optional guards (per-entity authorities, metamodel validation on the other DB path) define which edition/config is vulnerable.

October 9 09:31Z follow-up: Telerik Report Server — guest-token bearer accepted on the service-agent SignalR hub, and the settings-sync event hands over encryption keys (CVE-2026-106145 / GHSA-mqv8-78j6-26gw, high, fixed 12.2.26.1007)

Telerik Report Server's service-agent SignalR hub — the channel trusted agents use to receive server configuration — accepts registration from any authenticated user holding a valid bearer token, explicitly including low-privilege and guest accounts. Nothing binds the agent role to a machine credential; the hub's authz gate checks "has token," not "is agent." Once registered as a trusted agent, the rogue client sits and waits: on the next server settings-synchronization event it receives storage settings and the encryption private keys, which decrypt stored data-source credentials and connection strings — and it can impersonate an agent and interfere with report task dispatch.

This is the page's "auth lives at the handshake, role lives in the frame" invariant arriving on a real-time transport, with two sharper axes:

  1. Human-token / machine-role crossover on shared hubs is a first-class recon target. Any product with an "agent/gateway/worker/runner" component exposes a registration channel where the server trusts whoever claims the role. Sweep rule: for every WebSocket/SignalR/SSE/MQ endpoint, enumerate the role names the client can assert during handshake or first frame (query-string agentName, hub method Register, STOMP login header, JWT role claim the server echoes back), then attempt registration with the lowest-tier token you can mint — guest, anonymous, self-registered. The gate that fails open is the one written as "authenticated at all" because the real gate was assumed to be network location (agents live on internal hosts) rather than credential class.
  2. Sync/push events are standing secret-delivery opportunities — you don't have to ask for the secret. The rogue agent never calls a "get credentials" endpoint; it just stays connected and the server pushes keys on its own schedule. Audit rule white-box: find every "send config to registered peers" broadcast and check what identity the recipient registry stores; black-box: after proving rogue registration, hold the socket open across a settings change (create a dummy data source as your own low-priv account to induce a sync event in a lab) and capture what the sync frame carries. Report value is high: guest account → database credentials of every configured data source, bypassing the product's own credential-encryption layer entirely.
  3. Version fingerprint: fixed band 12.2.26.1007; Report Server's /ReportServer/api + SignalR hub paths (/signalr/hubs lineage) are the fingerprint for fingerprinting the product in the wild — enterprise reporting servers are rarely internet-facing but are prime post-foothold pivots, and stored XSS via javascript:/vbscript: URLs in report navigation actions/HTML text-box links (CVE-2026-106155 / GHSA-97qc-r4xh-88c5, high, same band) rides the same server: report authors' content executes in viewers' (including admins') sessions on the reporting origin — report-author → admin-session is the same trusted-rendering-sink class as the JHipster Blob leg above, worth pairing in one engagement pass.

Validation boundary: lab Report Server, your own guest-tier account, a synthetic data source with a canary password; prove rogue agent registration + capture the sync frame for YOUR canary only; never decrypt or replay real deployments' data-source credentials.

October 14 follow-up: Xorbits Xoscar — unauthenticated actor-pool TCP channel runs cloudpickle.loads before message-type validation (CVE-2026-49950 / GHSA-5rfg-55mw-4h28, 9.8 critical, ≤0.11.2)

The distributed Python actor framework Xoscar (the actor layer under Xorbits-class dataframe engines) takes the LMCache ZMQ leg of this page and lands it on a raw TCP actor-pool channel: SocketChannel.recv() passes unvalidated socket data straight into cloudpickle.loads() — the pickle __reduce__ gadget fires before any message-type validation runs, so no dispatch gate, session check, or protocol handshake intervenes. One crafted TCP payload = code execution as the server process, which the advisory notes commonly runs as root on GPU nodes.

This is now the third confirmed member of the same family on this page (STOMP /command/{hostname}, ZMQ msgpack ext-1, raw-TCP cloudpickle), which promotes the generalization to a standing scan rule:

  1. Any distributed-compute framework whose inter-worker channel deserializes Python objects on a routable socket is a pre-auth RCE surface, full stop. Fingerprint set on authorized infra engagements: Ray (10001+ band), Dask, Celery+pickle serializer, Horovod auxiliary ports, Xoscar/Xorbits actor pools, LMCache 555x — check which serializer each speaks before crediting the framework's "internal" port story. Grep fingerprint white-box: recv()/read_frame() whose result flows to pickle.loads/cloudpickle.loads/torch.load above any msg_type/opcode branch.
  2. Validation-order is the finding, not validation-absence. The Xoscar text is explicit that type validation exists — it just runs after the deserializer. Black-box triage order on any unknown binary protocol port: (a) does a malformed/oversized frame crash the service (deserializer fired), (b) does a well-formed-but-unknown-type frame get cleanly rejected (validation exists), and (c) crash-before-clean-reject = sink-before-gate. Proof stays lab-only: disposable Xoscar instance, one __reduce__ canary carrying an inert marker, never against shared GPU clusters.
  3. GPU/ML worker nodes are the high-value population — root-run compute planes with flat internal network assumptions are exactly where these channels get exposed; on cloud lab engagements, test actor-pool ports from a second owned node before assuming security-group topology protects them.