Skip to content

fails_gate treats an unrecognized --fail-on severity as most-permissive (fails on any match) #9

Description

@cognis-digital

What

core.fails_gate(results, fail_on) looks up the floor with SEVERITY_ORDER.get(fail_on, 99). An unrecognized severity string maps to rank 99 (below every real severity), so the comparison SEVERITY_ORDER.get(m.severity, 99) <= 99 is true for every match. A typo'd or unknown floor silently becomes the most permissive gate rather than a no-op or an error.

Reproduce

from c2detect.core import scan_observations, fails_gate
res = scan_observations([{"jarm": "07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1"}])
print(fails_gate(res, "criticl"))   # typo -> True (gate fails on any match)
print(fails_gate(res, "nonsense"))  # -> True

Impact

Low in practice for the CLI: argparse restricts --fail-on to valid choices, so the CLI never reaches this. But fails_gate / fails_gate_with_ai are part of the public API (exported from c2detect), and a library caller passing an unvalidated severity gets a gate that fails on everything — the opposite of a safe default.

Suggested fix

Treat an unknown floor as "no gate" (return False) or raise ValueError, rather than defaulting to rank 99. If a real floor genuinely means "everything", callers can pass "info" explicitly. A one-line guard in fails_gate:

if fail_on not in SEVERITY_ORDER:
    return False   # or: raise ValueError(f"unknown severity floor: {fail_on!r}")

Same guard applies to the AI-aware fails_gate_with_ai and the correlate-gate path in the CLI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions