From 5776bad3717131a2a40e8896b2666f4acbc52b1c Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Wed, 22 Apr 2026 20:27:36 +0300 Subject: [PATCH] fix: guard parse_node against missing "type" key to avoid TypeError crash When "type" is absent from node_data, node_data.get(None) returns None and "description" in None raises TypeError. Guard with early returns. Closes SURF-73 --- CHANGELOG.md | 3 +-- capa/ghidra/plugin/capa_explorer.py | 9 ++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 247aced1..fcda354d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,8 +48,7 @@ - fix: remove unreachable backports.functools_lru_cache fallback and dead dependency @williballenthin - fix: Scopes.from_dict uses cls instead of self so subclasses return the correct type @williballenthin - fix: correct wrong dict key in VMRay _compute_monitor_threads assertion (used thread_id instead of process_id) @williballenthin -fix: replace assert with isinstance guard in get_callee for invalid MethodSpec tokens @williballenthin -- fix: replace assert with isinstance guard in get_callee for invalid MethodSpec tokens @williballenthin +- fix: guard parse_node against missing "type" key to avoid TypeError crash @williballenthin (SURF-73) - fix: allocate feat_dict per feature in parse_json to avoid shared-reference aliasing @williballenthin (SURF-72) - fix: add missing capa.features.extractors.elf import to ghidra/helpers.py and ida/helpers.py @williballenthin (SURF-71) - fix: remove dead view_tab_rulegen assignment from CapaExplorerForm that was never read @williballenthin (SURF-70) diff --git a/capa/ghidra/plugin/capa_explorer.py b/capa/ghidra/plugin/capa_explorer.py index 1eb9ebf3..550cb989 100644 --- a/capa/ghidra/plugin/capa_explorer.py +++ b/capa/ghidra/plugin/capa_explorer.py @@ -313,7 +313,14 @@ def get_locations(match_dict): def parse_node(node_data): """pull match descriptions and sub features by parsing node dicts""" - node = node_data.get(node_data.get("type")) + node_type = node_data.get("type") + if node_type is None: + logger.debug("parse_node: node_data missing 'type' key: %s", node_data) + return + node = node_data.get(node_type) + if not isinstance(node, dict): + logger.debug("parse_node: node_data[%s] is not a dict: %s", node_type, type(node)) + return if "description" in node: yield "description", node.get("description")