@@ -249,8 +249,17 @@ def scan(self, scan_input: SafetyScanInput) -> SafetyScanReport:
249249 # Also refuses to upgrade when any CRITICAL finding exists, regardless
250250 # of how the policy maps CRITICAL → decision.
251251 has_critical = any (f .risk_level == RiskLevel .CRITICAL for f in all_findings )
252+ allow_upgraded = False
252253 if (decision == Decision .NEEDS_HUMAN_REVIEW and not has_critical and self ._check_allow_patterns (script )):
254+ logger .info ("allow_patterns upgraded NEEDS_HUMAN_REVIEW → ALLOW for '%s'" , scan_input .tool_name )
253255 decision = Decision .ALLOW
256+ allow_upgraded = True
257+
258+ # ══════════════════════════════════════════════════════════════
259+ # Recompute max_risk after blocklist findings may have been appended
260+ # ══════════════════════════════════════════════════════════════
261+ if all_findings :
262+ max_risk = max (f .risk_level for f in all_findings )
254263
255264 # ══════════════════════════════════════════════════════════════
256265 # Multi-layer evidence redaction (improved from single-layer)
@@ -273,7 +282,8 @@ def scan(self, scan_input: SafetyScanInput) -> SafetyScanReport:
273282 denied = sum (1 for f in all_findings if f .risk_level in (RiskLevel .CRITICAL , RiskLevel .HIGH ))
274283 total = len (all_findings )
275284 summary = (f"Scan of '{ scan_input .tool_name or 'unnamed tool' } ' found { total } issue(s) "
276- f"({ denied } high/critical). Decision: { decision .value } ." )
285+ f"({ denied } high/critical). Decision: { decision .value } ." +
286+ (" [auto_allowed by allow_patterns]" if allow_upgraded else "" ))
277287
278288 return SafetyScanReport (
279289 tool_name = scan_input .tool_name ,
@@ -676,6 +686,37 @@ def _scan_bash_tokens(self, script: str, scan_input: SafetyScanInput) -> List[Sa
676686 path ,
677687 ))
678688
689+ # Redirect to sensitive paths (e.g. > /etc/passwd, 2>/dev/sda)
690+ for f in bash_findings :
691+ if f .kind == "redirect" :
692+ target = f .extra .get ("target" , "?" )
693+ findings .append (
694+ self ._make_finding (
695+ "BASH-FILE-003" ,
696+ RiskCategory .DANGEROUS_FILE_OPS ,
697+ RiskLevel .CRITICAL ,
698+ f .evidence ,
699+ f"Bash: redirect to sensitive path '{ target } '" ,
700+ "Do not redirect output to sensitive system files." ,
701+ f .line_number ,
702+ target ,
703+ ))
704+
705+ # Background execution
706+ for f in bash_findings :
707+ if f .kind == "background" :
708+ findings .append (
709+ self ._make_finding (
710+ "BASH-PROC-004" ,
711+ RiskCategory .PROCESS_AND_SYSTEM ,
712+ RiskLevel .MEDIUM ,
713+ f .evidence ,
714+ "Bash: background execution operator &" ,
715+ "Background execution in tool scripts may indicate persistence or resource abuse." ,
716+ f .line_number ,
717+ "&" ,
718+ ))
719+
679720 except ImportError :
680721 logger .debug ("Bash shlex scanner not available; skipping." )
681722 except Exception :
0 commit comments