From ab914052b29635e106c4645910abb349a28ed9e1 Mon Sep 17 00:00:00 2001 From: Wolfvin Date: Sun, 12 Jul 2026 01:50:53 +0700 Subject: [PATCH] fix(security): taint treesitter_used/regex_fallback stat miscounted clean files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stats loop inferred which engine ran from findings[0]['engine'], but this requires at least one finding to exist. Any clean file (0 findings) has 'if findings' evaluate False regardless of which engine actually analyzed it, so it always fell into the regex_fallback bucket. Found via real-codebase validation (Coretax-Auto-Downloader KDS backend, 0 taint findings total): treesitter_available:true but treesitter_used:0, regex_fallback:50 — misleading, since tree-sitter was in fact available and used for all 50 files, they just had no findings. Fix: check parser availability directly (mirrors _analyze_with_treesitter's own check) instead of inferring from finding content. --- scripts/ast_taint_engine.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/ast_taint_engine.py b/scripts/ast_taint_engine.py index 04407c54..3bb578d8 100644 --- a/scripts/ast_taint_engine.py +++ b/scripts/ast_taint_engine.py @@ -3546,8 +3546,19 @@ def analyze_workspace(self, workspace: str, rules_dir: str = None, findings = analyzer.analyze_file(fpath, content=content, language=lang, rules=lang_rules) - # Track which engine was used - if findings and findings[0].get('engine') == 'ast_taint': + # Track which engine was used. Bug: inferring this from + # findings[0]['engine'] silently miscounts every CLEAN file + # (0 findings) as regex_fallback regardless of which engine + # actually ran, since `if findings` is False on an empty list. + # Found via real-codebase validation: KDS backend had 0 taint + # findings total, so treesitter_used read 0 / regex_fallback + # read 50 even though tree-sitter was available and likely + # used for every file. Check parser availability directly + # instead — this mirrors _analyze_with_treesitter's own check + # and doesn't depend on there being at least one finding. + ts_lang = 'typescript' if lang == 'typescript' else ( + 'tsx' if lang == 'tsx' else lang) + if TREE_SITTER_AVAILABLE and _get_parser(ts_lang): treesitter_used += 1 else: regex_fallback += 1