☠️
EXFILTRATING
DATA...
01010111 10110010 00101001 11000110 01101100 10011011 00010001 11100101 01000010 10101111
[ <-- BACK_TO_SEARCH ]
Hatchet logo [ WEBSITE ] [ VENDOR STATS ]
CVSS: 4.3 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N 🐛 CWE-639
👁️
Common Weakness Enumeration - Identifies the specific category of software weakness or flaw.

CVE-2026-88978

CVE-2026-88978 Vulnerability in Hatchet
📅 PUBLISHED: 2026-09-21 00:00 UTC 🔄 UPDATED: 2026-10-02 19:21 UTC
[ PATCH UNDER REVIEW ↓ ] Remains UNDER REVIEW until an independent source confirms the fix
[ DEFENSE PATCH ↓ ]
💣 PoC: None
👁️
Proof of Concept - Indicates if functional exploit code is publicly available, drastically increasing the risk of immediate attacks.
🎯 EPSS: 0.17%
👁️
0.17% probability
4.2× above the median CVE
Tier: ELEVATED
30-day exploitation window · FIRST.org · updated daily
🥷 MITRE: T1213
👁️
MITRE ATT&CK Tactic - Describes the strategy hackers use to execute this attack.
Country: Global License: Open Source
VULNERABLE: version not auto-detected — verify your deployed version locally
CVSS VECTOR BREAKDOWN 4.3
AV: N Attack Vector Network
AC: L Attack Complexity Low
PR: L Privileges Required Low
UI: N User Interaction None
S: U Scope Unchanged
C: L Confidentiality Low
I: N Integrity None
A: N Availability None
4.3
THREAT LEVEL
■ tracking this CVE ✓ independent patch confirmation ⧗ same-origin mirror (GHSA) ⚠ active exploitation verification policy →

Executive Summary

CVE-2026-88978 is an authorization bypass (tenant isolation failure) in Hatchet, a platform for orchestrating background tasks, AI agents, and durable workflows at scale. Prior to version 0.106.1, the WorkerStatus gRPC polling path in pkg/repository/durable_events.go passes caller-supplied durable task, node, and branch identifiers to ListSatisfiedEntries without applying a tenant filter, allowing an authenticated worker belonging to one tenant to retrieve durable event-log records belonging to another tenant when the corresponding durable-task UUID is known. Impact is limited to confidentiality (CVSS 4.3, C:L) because exploitation requires both authentication and knowledge of a target tenant's UUIDv4 identifier; the NVD description explicitly notes exploitation is unlikely and that single-tenant deployments are unaffected in practice.

⚡ AUTOMATE YOUR CVE INTELLIGENCE

This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.

›Patch confidence — UNVERIFIED to CONFIRMED, cross-referenced NVD + RHSA + Debian
›Exploit & PoC — poc_status, poc_url, has_exploit. Not in NVD.
›Shodan dorks — ready-made queries to find exposed vulnerable systems
›Detection rules — YARA · Wazuh · Elastic (all plans) · Sigma (Pro)
›pending_fields — know exactly which of 7 fields NVD hasn't processed yet
›Free backfill — data incomplete when you paid? Re-check within 30 days = 0 credits
PAYG €0.08/lookup Standard €19/mo (was €29) · 5k credits Pro €65/mo (was €99) · 20k credits FOUNDING PRICE · LOCKED FOR LIFE · ENDS 31 DEC 2026
[ FROM €19/MO ]
Free sandbox key available
No signup required

Technical Analysis

The vulnerability is a classic cross-tenant object reference / missing ownership check, classified as CWE-639 (Authorization Bypass Through User-Controlled Key). Hatchet's architecture exposes a gRPC interface used by worker processes to poll their status. The WorkerStatus polling code path is implemented in pkg/repository/durable_events.go. When servicing a poll request, this path takes caller-supplied identifiers — specifically a durable task identifier, a node identifier, and a branch identifier — and passes them into the repository function ListSatisfiedEntries. The function returns durable event-log records that match those identifiers.

The defect is that ListSatisfiedEntries, as reached through this polling path, does not include a tenant-scoping predicate. The identifiers are trusted as supplied by the caller. Consequently, the query scope is defined entirely by the attacker-controlled key values rather than by the authenticated tenant identity attached to the gRPC session. If the attacker supplies identifiers that correspond to records owned by a different tenant, the repository layer will return those records because no ownership/tenant constraint filters them out.

Several characteristics of the flaw materially constrain severity:

  1. Authentication is required. The CVSS vector is PR:L (Low privileges) with AV:N (Network) and UI:N (No user interaction). The attacker must be an authenticated tenant worker able to reach the gRPC WorkerStatus polling endpoint. Unauthenticated parties cannot invoke this path.

  2. The key is a UUIDv4. The durable-task identifier that must be known to retrieve another tenant's records is a version-4 UUID. UUIDv4 values carry 122 bits of randomness, making them infeasible to enumerate or brute-force. The attacker must already possess the target tenant's durable-task UUID through some other means (leak, log exposure, shared artifact, insider knowledge, or a separate information disclosure). The NVD description explicitly states this requirement "makes exploitation unlikely."

  3. No integrity or availability impact. The vector shows I:N and A:N; this is a read-only disclosure path. There is no reported mechanism to modify, delete, or disrupt another tenant's durable events through this flaw.

  4. Single-tenant deployments unaffected in practice. In a single-tenant deployment there is no second tenant whose data could be cross-read, and the described impact does not materialize in practice.

No public proof-of-concept, exploit code, or Nuclei template is known for this issue. The attack chain below is therefore described at the vulnerability-class level and is inferred from the NVD description rather than from a public exploit.

Exploitation Scenarios

No public PoC is available; the following chain is inferred from the vulnerability class (CWE-639, missing tenant filter on a caller-supplied key) and the NVD description. Names of functions, files, and identifier types are taken verbatim from the description.

  1. Reconnaissance / target identification. The attacker must first be an authenticated worker on a multi-tenant Hatchet deployment, and must obtain a durable-task UUID belonging to a different tenant. Because the identifier is a UUIDv4, it cannot be guessed; it must be acquired out-of-band — for example, from a leaked log, a shared artifact or dashboard, a misconfigured export, or insider access. Once the attacker holds a target tenant's durable-task UUID, no further reconnaissance is required because the polling path accepts the key directly.

  2. Triggering the flaw class. The attacker's worker issues a WorkerStatus gRPC poll request and supplies the durable task identifier (the victim tenant's UUIDv4), along with node and branch identifiers, as the caller-controlled keys. The request is routed into the WorkerStatus polling path in pkg/repository/durable_events.go. Because that path passes the caller-supplied identifiers to ListSatisfiedEntries without a tenant filter, the request is authorized against the attacker's own tenant identity but executed against the victim's identifier. There is no ownership check that would reject a key not belonging to the calling tenant.

  3. Retrieval / execution method. ListSatisfiedEntries executes with the supplied durable task, node, and branch identifiers as its selection criteria and returns the matching durable event-log records. The attacker receives event-log records belonging to the other tenant. The interaction is a normal gRPC request-response cycle; no crafted payload, memory corruption, or code execution is involved — the "payload" is simply the victim tenant's UUID plus node/branch identifiers.

  4. Post-exploitation impact. The attacker gains read access to the victim tenant's durable event-log records: workflow execution history, task state transitions, and related durable-event metadata for the referenced task. This is an information disclosure only. It can be used to map another tenant's workflows, infer business logic, and potentially harvest additional identifiers (node/branch/task values) that could extend reconnaissance. It does not permit modification, denial of service, or lateral movement by itself, and exploitation probability is assessed as low due to the UUIDv4 requirement.

Impact Assessment

The CVSS 3.1 base score is 4.3 (Medium), with vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N. Subscore interpretation:

  • AV:N (Network) — the WorkerStatus gRPC polling path is reachable over the network by a worker with valid credentials.
  • AC:L (Low) — once the victim's UUID is known, no special conditions or race is required; the poll is a straightforward request.
  • PR:L (Low privileges) — the attacker must hold authenticated worker credentials for some tenant; no administrative role is needed.
  • UI:N (No user interaction) — no victim action is required; the attacker merely polls.
  • S:U (Unchanged) — the flaw does not cross a security authority boundary in the CVSS sense; the impact is scoped to the vulnerable component's data.
  • C:L (Low confidentiality) — disclosure is limited to durable event-log records for tasks whose UUIDs the attacker already possesses.
  • I:N / A:N — no integrity or availability impact is described; the path is read-only.

Business impact. In multi-tenant SaaS or platform deployments of Hatchet, the flaw breaks tenant data isolation for durable workflow event logs. Metadata about another tenant's background tasks, AI agent runs, and durable workflow state may be exposed, which can constitute a confidentiality and contractual/compliance issue (data isolation guarantees). The blast radius is bounded by the UUIDv4 requirement: an attacker can only read records for tasks whose identifiers they have already obtained, so mass cross-tenant harvesting is not achievable through this bug alone; its practical value is as a secondary disclosure primitive or to amplify an initial identifier leak. Single-tenant deployments and single-tenant on-premises installations are unaffected in practice. No CISA KEV listing and no observed exploitation in the wild are known.

Detection Guidance

Detection should focus on the WorkerStatus gRPC polling path and on anomalous mismatches between the authenticated tenant context and the tenant that owns the requested durable-task UUID. Because the request is legitimate protocol traffic, high-fidelity detection depends on correlating the caller's tenant identity with the ownership of the referenced task — an enrichment that must be performed by the platform or by application logs that record both.

Sigma Rule

title: Hatchet Cross-Tenant Durable Event Access via WorkerStatus Polling (CVE-2026-88978)
id: 6e2e0a1c-4f9b-4c7d-9a11-7c0a5e3b8d21
status: experimental
description: Detects WorkerStatus gRPC polling requests where the authenticated tenant does not own the referenced durable task UUID, indicating exploitation of the missing tenant filter in pkg/repository/durable_events.go (ListSatisfiedEntries).
references:
    - https://nvd.nist.gov/vuln/detail/CVE-2026-88978
author: valtersit.com
date: 2026/01/01
tags:
    - attack.t1213
logsource:
    product: hatchet
    service: workerstatus
detection:
    selection_endpoint:
        rpc_method|contains: 'WorkerStatus'
    selection_fields:
        durable_task_id|exists: true
        node_id|exists: true
        branch_id|exists: true
    filter_same_tenant:
        caller_tenant_id: request_tenant_id
    condition: selection_endpoint and selection_fields and not filter_same_tenant
falsepositives:
    - Administrative cross-tenant tooling or legitimate delegated service accounts
    - Telemetry where request_tenant_id enrichment is unavailable (will not match)
level: medium

Note: this rule requires log enrichment that records both the authenticated caller caller_tenant_id and the owning request_tenant_id of the referenced durable task. Where that enrichment is not available, the rule degrades to alerting on all WorkerStatus polls from a single principal referencing many distinct task UUIDs.

YARA Rule

rule CVE_2026_88978_Hatchet_WorkerStatus_Tenant_Bypass_PoC
{
    meta:
        description = "Detects artifacts, scripts, or tooling referencing the Hatchet WorkerStatus cross-tenant durable event access flaw (ListSatisfiedEntries / durable_events.go)"
        author = "valtersit.com"
        reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-88978"
        date = "2026-01-01"
        severity = "medium"

    strings:
        $p1 = "ListSatisfiedEntries" ascii wide
        $p2 = "durable_events.go" ascii wide
        $p3 = "WorkerStatus" ascii wide
        $c1 = "ListSatisfiedEntries" ascii
        $c2 = "durable_task_id" ascii wide
        $c3 = "durable-task UUID" ascii wide nocase
        $c4 = "tenant filter" ascii wide nocase

    condition:
        uint16(0) == 0x5A4D or uint32(0) == 0x464C457F or true
        and
        ( 2 of ($p*) or 1 of ($p1) and 2 of ($c*) or ( $p1 and $p2 and 1 of ($c1, $c2) ) )
}

Interpretation: this is a hunting rule for tooling, notes, or binaries that reference the named function and file together with tenant/durable-task identifiers — not for identifying a remote client by packet inspection.

Suricata IDS Rule

alert tcp any any -> any any (msg:"CVE-2026-88978 Hatchet WorkerStatus cross-tenant durable event polling attempt (ListSatisfiedEntries)"; flow:established,to_server; content:"WorkerStatus"; fast_pattern; content:"ListSatisfiedEntries"; distance:0; within:512; threshold:type limit, track by_src, count 5, seconds 60; classtype:attempted-recon; reference:cve,2026-88978; reference:url,nvd.nist.gov/vuln/detail/CVE-2026-88978; sid:202688978; rev:1;)

Note: gRPC over HTTP/2 uses HPACK header compression and often TLS, so cleartext string matching is best-effort and only applicable where the traffic is decrypted or unencrypted. This rule serves as a placeholder for environments that terminate or mirror TLS with a protocol decoder capable of exposing gRPC method names and message fields; production fidelity is better achieved via application-layer logging described in the Sigma/EQL detections.

Elastic Detection

sequence by process.entity_id with maxspan=5m
  [ network where network.direction == "egress"
      and network.transport == "tcp"
      and process.name : ("hatchet*", "worker*", "grpc*") ]
  [ network where network.direction == "egress"
      and network.transport == "tcp"
      and process.name : ("hatchet*", "worker*", "grpc*") ]

This sequence flags repeated gRPC polling from a single worker process. Where gRPC method names are captured in rpc.method or http.request.body fields (with TLS inspection or a gRPC-aware dissector), refine with:

any where rpc.method == "WorkerStatus" and
  (network.bytes > 0) and
  process.name : ("hatchet*", "worker*")

Fidelity improves when the platform emits structured fields correlating the calling tenant with the referenced durable-task owner; the pure network assertion cannot see the tenant mismatch and should be used as a hunting lead only.

Splunk SPL Query

index=hatchet sourcetype=hatchet:app:workerstatus OR sourcetype=hatchet:grpc
| where match(rpc_method, "WorkerStatus")
| eval same_tenant=if(caller_tenant_id==request_tenant_id, 1, 0)
| where same_tenant=0
| stats count AS poll_events,
        dc(durable_task_id) AS distinct_tasks,
        values(durable_task_id) AS tasks,
        values(branch_id) AS branches
        BY caller_tenant_id, request_tenant_id, src_ip
| where (distinct_tasks >= 1 AND caller_tenant_id != request_tenant_id)
| sort - distinct_tasks
| table caller_tenant_id, request_tenant_id, src_ip, poll_events, distinct_tasks, tasks, branches

If the platform does not emit caller_tenant_id/request_tenant_id, fall back to a volume-based hunt for a single worker principal referencing an abnormal number of distinct durable_task_id values:

index=hatchet sourcetype=hatchet:app:workerstatus rpc_method="WorkerStatus"
| stats dc(durable_task_id) AS distinct_tasks, count AS polls BY src_ip, worker_id
| where distinct_tasks > 50
| sort - distinct_tasks

Wazuh OSSEC Rule

<group name="hatchet,cve-2026-88978,">
  <rule id="100900" level="10">
    <decoded_as>json</decoded_as>
    <field name="rpc_method">WorkerStatus</field>
    <field name="caller_tenant_id" negate="yes">request_tenant_id</field>
    <description>CVE-2026-88978: Hatchet WorkerStatus poll references a durable task not owned by the calling tenant - possible cross-tenant durable event access via ListSatisfiedEntries</description>
    <mitre>
      <id>T1213</id>
    </mitre>
    <group>cve_2026_88978,tenant_isolation,</group>
  </rule>

  <rule id="100901" level="7">
    <if_sid>100900</if_sid>
    <field name="durable_task_id">\.</field>
    <description>CVE-2026-88978: Follow-on Hatchet WorkerStatus cross-tenant poll with concrete durable_task_id - correlate UUID reuse</description>
  </rule>
</group>

Because Wazuh's field comparison is limited, deploy rule 100900 against application logs that emit both the caller tenant and the owning tenant of the requested durable task. In the absence of that enrichment, use rule 100900 as a presence-based alert and perform the tenant-mismatch correlation with the Elastic or Splunk query.

Mitigation & Patch Guidance

Patch confidence is 0/4: no patch evidence was found in any tracked source, no vendor fix URL is provided, and no workaround is published. The NVD description states the issue is fixed in Hatchet version 0.106.1, but this datum is not corroborated by a tracked advisory in the supplied data — treat it as the target version and verify against the vendor's own release channel before relying on it.

  1. Immediate mitigations (no code change):

    • Enforce strict multi-tenant isolation at the deployment layer: where operationally feasible, run separate Hatchet instances per tenant so that no worker can hold credentials for a namespace that contains other tenants' data. Single-tenant deployments are unaffected in practice and need no action for this issue.
    • Restrict which principals may invoke the WorkerStatus gRPC polling path and from where. Network-segment worker-to-control-plane gRPC traffic and firewall the endpoint to known worker subnets.
    • Reduce UUID leakage: audit where durable-task UUIDs are emitted — logs, dashboards, exported artifacts, error messages, shared tickets — and scrub them. Since exploitation depends on knowing a victim's UUIDv4, preventing UUID disclosure removes the practical precondition for exploitation.
    • Monitor and alert on the detections above, particularly a single authenticated worker principal polling for durable tasks it does not own.
  2. Patch / upgrade steps:

    • Verify the vendor's 0.106.1 release notes and checksums directly, then upgrade to 0.106.1 (or the latest 0.106.x) across control-plane and worker components. Confirm that the WorkerStatus polling path in pkg/repository/durable_events.go applies a tenant filter before calling ListSatisfiedEntries.
    • After upgrading, confirm the fix by testing with two tenants: authenticate as tenant A and attempt to poll using a durable-task UUID owned by tenant B; the request must return no matching records. Retain evidence of the negative test.
    • Because no vendor advisory is confirmed in the supplied data, register for Hatchet security and release notifications and re-check the CVE record for an official fixed-version confirmation.
  3. Long-term hardening:

    • Adopt a "tenant context is mandatory" invariant at the repository layer: all queries over tenant-scoped tables, including ListSatisfiedEntries, must require an explicitly bound tenant identity and must never derive scope solely from caller-supplied keys. Reject requests whose key does not resolve within the caller's tenant rather than returning an empty result, so failures are observable.
    • Add automated cross-tenant isolation tests (negative tests) to CI for every gRPC polling/handling path, not just REST endpoints.
    • Treat durable-task, node, and branch identifiers as sensitive where they act as authorization keys; consider transitioning to opaque, server-issued handles bound to the authenticated tenant so that possession of an identifier alone never grants access.
    • Track CVE-2026-88978 and re-evaluate patch confidence as vendor advisories, OSV entries, and package metadata become available.

References

  1. NVD — CVE-2026-88978: https://nvd.nist.gov/vuln/detail/CVE-2026-88978
  2. Hatchet project repository and release notes (verify 0.106.1 fix): https://github.com/hatchet-dev/hatchet
  3. MITRE ATT&CK T1213 — Data from Information Repositories: https://attack.mitre.org/techniques/T1213/
  4. CWE-639 — Authorization Bypass Through User-Controlled Key: https://cwe.mitre.org/data/definitions/639.html
  5. CISA Known Exploited Vulnerabilities Catalog (query to confirm CVE-2026-88978 is absent): https://www.cisa.gov/known-exploited-vulnerabilities-catalog

Exploitation status: No public PoC, no exploit code, no Nuclei template, and no CISA KEV listing were identified for CVE-2026-88978 at the time of writing. No threat actor campaign or in-the-wild exploitation evidence was found in the supplied data.

◈ SOURCE Analysis & enrichment: valtersit.com/cve/CVE-2026-88978/ · CVE data: NVD/MITRE (public domain) · © 2026 ValtersIT Hub
>_ SYSTEM_CORE: INTEL_ACTIVE
90% TEAM-CURATED // 10% AUTOMATED INGESTION.
ALL PATCH REFERENCES AND VERSION DATA SOURCED FROM NVD + OSV OFFICIAL REGISTRIES.