ANT-2026-GACTPNVK · wireshark/wireshark

other low

CVE-2026-76890

Severity Claude high · Security research firm high · Maintainer low

Discovered by Claude Mythos Preview

REPORT

Anthropic's analysis, sealed at approval. Disclosure to the maintainer was performed by Ada Logics.

ANT-2026-GACTPNVK: sharkd iograph error path leaks stack-array listeners

sharkd_session_process_iograph() declares struct sharkd_iograph graphs[10] on the stack and registers each as a tap listener. If a later graph in the same request has an invalid filter or field, the function emits an error and returns without removing the listeners already registered for earlier valid graphs, leaving the global tap_listener_queue holding pointers into a dead stack frame. On the next request that triggers retap/redissection, the io-stat packet callback runs with a dangling tapdata pointer, reads garbage fields, and calls g_realloc on stack garbage before writing back into the reused frame. A connected sharkd client fully controls the graphN/filterN JSON strings needed to trigger this, yielding memory corruption and a plausible path to RCE.

Target

Project: wireshark/wireshark
Location: sharkd_session.c:4758
Discovery: static analysis — not yet dynamically reproduced

Technical Details

The error path at lines 4758–4765 returns immediately when graph->error is set, but listener removal (remove_tap_listener at line 4818) is only reached on the success path after the loop. Because register_tap_listener stores the address of the stack-local graph struct (tap.c:576–608) into the global tap_listener_queue, any subsequent retap invokes sharkd_iograph_packet on freed stack memory, where it dereferences graph->interval/num_items/space_items and calls g_realloc(graph->items, ...) on whatever now occupies that slot.

Reproduction

  1. Send {"req":"iograph","graph0":"packets","graph1":"packets","filter1":"!!invalid!!"} — graph0 registers &graphs[0]; graph1's filter fails compilation and the handler returns early without cleanup.
  2. Send any request that calls sharkd_retap() (e.g. {"req":"iograph","graph0":"bytes"}, or tap/follow/download-rtp).
  3. tap_push_tapped_queue invokes sharkd_iograph_packet with tapdata pointing at reused stack memory, calling g_realloc on garbage and writing into the current frame.

[No reproducer or sanitizer output attached — request from security-cvd@anthropic.com if needed.]

Suggested Fix

Remove all successfully-registered tap listeners before any early return — restructure to a single exit point with unconditional cleanup, or validate all graph inputs before registering any listener.

Acknowledgement

This vulnerability was discovered by Claude, Anthropic's AI assistant, and triaged by the Anthropic security team in collaboration with Anthropic Research. Please direct questions to security-cvd@anthropic.com and reference ANT-2026-GACTPNVK.


Reference: ANT-2026-GACTPNVK
Anthropic CVD Policy: https://www.anthropic.com/coordinated-vulnerability-disclosure

SECURITY RESEARCH FIRM ANALYSIS

Triage and disclosure were performed by Ada Logics.

Verdict
true positive
Severity
high
UPSTREAM FIX

The change that resolved this finding.

diff --git a/sharkd_session.c b/sharkd_session.c
index 610967eef7d..481119fc69f 100644
--- a/sharkd_session.c
+++ b/sharkd_session.c
@@ -4680,10 +4680,9 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count)
     const char *tok_interval = json_find_attr(buf, tokens, count, "interval");
     const char *tok_interval_units = json_find_attr(buf, tokens, count, "interval_units");
     struct sharkd_iograph graphs[10];
-    bool is_any_ok = false;
-    int graph_count;
+    unsigned graph_count;
 
-    int i;
+    unsigned i;
 
     /* default: 1000ms = one per second */
     uint32_t interval = 1000;
@@ -4721,7 +4720,7 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count)
         interval_us = 1000000 * interval;
     }
 
-    for (i = graph_count = 0; i < (int) G_N_ELEMENTS(graphs); i++)
+    for (i = graph_count = 0; i < G_N_ELEMENTS(graphs); i++)
     {
         struct sharkd_iograph *graph = &graphs[graph_count];
 
@@ -4791,8 +4790,6 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count)
         if (!graph->error)
             graph->error = register_tap_listener("frame", graph, tok_filter, TL_REQUIRES_PROTO_TREE, NULL, sharkd_iograph_packet, NULL, NULL);
 
-        graph_count++;
-
         if (graph->error)
         {
             sharkd_json_error(
@@ -4800,15 +4797,14 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count)
                     "%s", graph->error->str
                     );
             g_string_free(graph->error, TRUE);
-            return;
+            goto cleanup;
         }
 
-        if (graph->error == NULL)
-            is_any_ok = true;
+        graph_count++;
     }
 
     /* retap only if we have at least one ok */
-    if (is_any_ok)
+    if (graph_count)
         sharkd_retap();
 
     sharkd_json_result_prologue(rpcid);
@@ -4853,12 +4849,19 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count)
         }
         json_dumper_end_object(&dumper);
 
-        remove_tap_listener(graph);
-        g_free(graph->items);
     }
     sharkd_json_array_close();
 
     sharkd_json_result_epilogue();
+
+cleanup:
+    for (i = 0; i < graph_count; i++)
+    {
+        struct sharkd_iograph *graph = &graphs[i];
+
+        remove_tap_listener(graph);
+        g_free(graph->items);
+    }
 }
 
 /**

https://github.com/wireshark/wireshark/commit/d43d89d201b18f1c6d77460e52b4e6b5a4ec68f8

TIMELINE

Recorded dates, in order.

  1. 2026-04-02 Discovered or logged
  2. 2026-07-06 Sent to maintainer
  3. 2026-08-12 Maintainer acknowledged
  4. 2026-08-12 Patch released
  5. 2026-09-28 Publicly revealed
PROVENANCE

SHA-3-512 hash:

ab180bc6dad222dd8d350da26913a397d4ed975e56370475735de8b0eaf7643f9df293cb10754ccd26af8a4fdf0452eaaf04f98a01c8dbabbd3efd0af47a4785

Committed 2026-07-22 07:34 UTC

Revealed 2026-09-28 20:38 UTC

Verify (download preimage.json)

Show preimage JSON
{
  "ant_id": "ANT-2026-GACTPNVK",
  "bug_class": "Use-After-Return / Memory Corruption",
  "claude_severity": "high",
  "commit_sha": null,
  "created_at": "2026-04-16T14:11:17+00:00",
  "description": "sharkd_session_process_iograph() declares `struct sharkd_iograph graphs[10]` on the stack and registers each as a tap listener. If a later graph in the same request has an invalid filter or field, the function emits an error and returns without removing the listeners already registered for earlier valid graphs, leaving the global tap_listener_queue holding pointers into a dead stack frame. On the next request that triggers retap/redissection, the io-stat packet callback runs with a dangling tapdata pointer, reads garbage fields, and calls g_realloc on stack garbage before writing back into the reused frame. A connected sharkd client fully controls the graphN/filterN JSON strings needed to trigger this, yielding memory corruption and a plausible path to RCE.",
  "discovered_at": "2026-04-02T00:00:00+00:00",
  "location": "sharkd_session.c:4758",
  "poc_sha256": null,
  "preimage_version": 1,
  "project": "wireshark/wireshark",
  "reproduction": [
    "1. Send {\"req\":\"iograph\",\"graph0\":\"packets\",\"graph1\":\"packets\",\"filter1\":\"!!invalid!!\"} — graph0 registers &graphs[0]; graph1's filter fails compilation and the handler returns early without cleanup.",
    "2. Send any request that calls sharkd_retap() (e.g. {\"req\":\"iograph\",\"graph0\":\"bytes\"}, or tap/follow/download-rtp).",
    "3. tap_push_tapped_queue invokes sharkd_iograph_packet with tapdata pointing at reused stack memory, calling g_realloc on garbage and writing into the current frame."
  ],
  "technical_details": "The error path at lines 4758–4765 returns immediately when graph->error is set, but listener removal (remove_tap_listener at line 4818) is only reached on the success path after the loop. Because register_tap_listener stores the address of the stack-local graph struct (tap.c:576–608) into the global tap_listener_queue, any subsequent retap invokes sharkd_iograph_packet on freed stack memory, where it dereferences graph->interval/num_items/space_items and calls g_realloc(graph->items, ...) on whatever now occupies that slot.",
  "title": "sharkd iograph error path leaks stack-array listeners",
  "vendor_severity": "high"
}