Skip to content

fix(strix): bare Fatal/Denied/Warn/Warning match lacks provider-context guard, causing false-positive fail-closed on clean scans #1291

Description

@seonghobae

Problem

While triaging why the required strix check was failing on essentially every open PR across fast-mlsirm (including a trivial Dependabot Actions-version bump, PR #1311, where no plausible real finding exists), I traced one concrete failure to its root cause in scripts/ci/strix_quick_gate.sh.

has_detected_infrastructure_error() (around line 2946) starts with:

has_detected_infrastructure_error() {
	if grep -Eiq '(^|[^[:alpha:]])(Fatal|Denied|Warn|Warning)([^[:alpha:]]|$)' "$STRIX_LOG"; then
		return 0
	fi
	...

Unlike every other branch in the same function (is_timeout_error, is_rate_limit_error, is_llm_token_limit_error, is_llm_api_connection_error, is_llm_service_unavailable_error, is_nvidia_nim_not_found_error, and the generic ConnectionError|... branch at the bottom), this first branch has no requirement that the match occur in an LLM-provider context (no LLM_PROVIDER_ONLY_REGEX / PROVIDER_CONTEXT_REGEX co-requirement). It fires on the bare words Fatal, Denied, Warn, or Warning appearing anywhere in the full Strix log — including inside Strix's own narrative/report text about the scanned target, which very plausibly contains these exact words as ordinary vocabulary (e.g. many CWL repos' own CLAUDE.md/AGENTS.md literally instruct treating Timeout, Fatal, Warn, or Denied output as a hard failure — a convention Strix would naturally quote or reference while analyzing those repos; or Strix simply describing an access-control check as "Denied" or a log level as "Warn").

Evidence

PR fast-mlsirm#1311 (a pure bump rust-toolchain/CodeQL-action-version Dependabot PR — no plausible real finding):

  • Run: https://github.com/ContextualWisdomLab/fast-mlsirm/actions/runs/32691078281/job/97324789969
  • The primary-model Strix run completed cleanly:
    ╭─ STRIX ──────────────────────────────────────────────────────────────────────╮
    │  Penetration test completed                                                  │
    │  Vulnerabilities  0 (No exploitable vulnerabilities detected)                │
    ╰──────────────────────────────────────────────────────────────────────────────╯
    
  • Immediately after, the gate logged: Strix run emitted provider infrastructure or failure-signal output; failing closed. — with rc=0 and a genuine 0-vulnerability report already produced, this can only be the bare-word branch (none of the other, provider-context-gated branches would plausibly fire on a report that already completed with no LLM/provider errors visible in the summary box).
  • This forced a full model-fallback cascade: nvidia_nim/nvidia/llama-3.3-nemotron-super-49b-v1.5 (also flagged the same way) → openai-direct/gpt-5.6-luna, which then hit a second, independent bug: litellm rejected it outright (litellm.BadRequestError: LLM Provider NOT provided ... You passed model=openai-direct/gpt-5.6-luna). The final fallback exhausted, and the gate correctly failed closed on "provider infrastructure failures are not clean scan evidence" — but only because the cascade was triggered unnecessarily by the first false positive.

I did not have time to fully trace the second bug (hyphen- vs. underscore-normalized openai-direct/openai_direct model-string handling differs between strix.yml:757-758 and strix_quick_gate.sh:2311-2312, and whichever code path fed openai-direct/gpt-5.6-luna — hyphenated — into this particular fallback attempt evidently skipped the hyphen→underscore conversion that the other path applies). Flagging it here since it compounds the same incident, but the bare-word false positive is the primary, reproducible finding and worth fixing independently.

Why this matters

This repeats across nearly every open fast-mlsirm PR I sampled (confirmed failing on 1237, 1194, 1311; same blocked/no-fresh-review pattern strongly suggestive of the same cause on 1181, 1172, 1156, 1074, 1056, 1302, 1299, 1196) — i.e., it is very likely the single largest current source of required-check failures blocking merges org-wide, not a per-repo code issue.

Suggested fix (not attempted here — this touches fail-closed security logic and the existing multi-thousand-line test_strix_quick_gate.sh suite, and per this repo's own policy that deserves a dedicated, test-first change, not a drive-by patch)

Require the bare Fatal|Denied|Warn|Warning branch to co-occur with an LLM/provider-context marker (mirroring LLM_PROVIDER_ONLY_REGEX/PROVIDER_CONTEXT_REGEX used by the other branches in the same function), or scope it to text that appears after the log's own completion marker is absent (i.e., don't apply it once a Penetration test completed + Vulnerabilities N block with no in-band provider-error marker has already been observed for that attempt). Add regression fixtures using real Strix report narrative text that legitimately contains these words in a non-infrastructure sense, alongside the existing genuine-infrastructure-failure fixtures, so the fix is provably narrowing false positives without reopening the fail-closed gap that #891 tracks.

Related

Agent: Claude
Recorded: 2026-08-24T07:xx (see issue creation timestamp)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: securitySecurity boundary, hardening, or vulnerability preventionpriority: highHigh-priority or P1 worktype: bugDefect or incorrect behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions