Repository navigation
Conversation
… check that lets one rule repeat (#342) A reviewed, versioned noise catalogue keyed by vendor and detection rule id (Wazuh raw.rule.id with the normalizer's rule name, never text) lifts only the unmapped never-close class. The campaign check now needs every related alert to be the same rule repeating as benign noise over a complete related set; a different rule, a threat or unjudged alert, a never-close class, a plan awaiting approval, a truncated or blind-audit-hidden set or an old digest blocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc
… close check, format-gated catalogue H1: T1531, the Wazuh authentication-failure groups and rules 6250/44733 are credential access. M1: a same-rule sibling is a quiet repeat only when closed as benign or when its own model-close blockers (minus tier and campaign) are empty. L1: the ingestion service records the normalizer format on the canonical alert (kept out of prompts) and the catalogue and repeat count require wazuh. L2-L5: abuse, residual-risk and fail-closed text corrected; non-Wazuh vendors and the max_correlations bound documented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc
…he vendor rule through the state cap A same-rule sibling's own campaign block counts as cleared only when its digest shows no threat, a complete related set and no related alert of another or unknown rule (new digest count related_other_rules); a digest without it is not cleared. cap_alert keeps raw.rule (id, level, description, groups, mitre) when it drops an oversized raw event, and a Wazuh-built alert whose rule cannot be read is the never-close class vendor_unknown. Docs state the deliberate trust in a sibling closed benign by an analyst or approved evidence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc
…ut groups lists are vendor_unknown Three review rounds found ways to launder a campaign block through the same-rule repeat count, so the lead dropped it from this PR: _campaign_in_progress, the correlation digest, openapi.json and schema.gen.ts are back to main. Kept: the noise catalogue, T1531 and the Wazuh auth-failure groups as credential access, the raw.rule subset through the state cap, vendor_unknown (now also for a groups list the cap cut) and CanonicalAlert.normalizer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc
INV-03 keeps both changes. The verdict-key replay's benign floor moves to 14: Wazuh authentication-failure rules are now a never-close class, so they get no verdict key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc
…lasses Wazuh authentication-failure rules outside credential access by ATT&CK are a never-close class since FIX-2, so they get no verdict key: the oracle closes 4 benign corpus_v1 alerts instead of 9, still no attack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc
…ro-reopen replaces the forward gates (#348) At auto_full_audit an info-to-high alert closes when the deep verdict is benign (any certainty, below the response policy) and the fast tier did not call it a likely or confirmed threat, unless it is critical, a never-close class, steering text, a recent true positive, model-normalised or reopened. The 8/85 thresholds, the campaign check and the unmapped block are removed. A response plan or malicious close, an escalation a model judged a threat, an analyst true positive or a blind-audit malicious label reopens every model-closed alert sharing a host, user or IP in the previous 24 h: queued again, attached to the escalation, audited alert.reopened, counted on failure. INV-03 amended with proofs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc
…t the tier, unmapped closes, vendor_unknown does not) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc
|
Review of FIX-3 (decision policy v3) I read Overall: The design is sound. Reopening is idempotent, tenant-scoped and audited. A failure is counted and logged without failing the threat's own decision. Tier Potential issues
Security
Tests
Process 🤖 Generated with Claude Code |
FIX-3: decision policy v3. AI-benign alerts close, and retro-reopen replaces the forward gates
Closes #348. Tier T3: this changes the decision policy and INV-03. Builds on #345 (branched from its tip; it will be rebased once #345 merges).
What changed
Model-led close at
auto_full_audit(domain/closure.py,domain/routing.py). The tier is per tenant and defaults tooff.benign, at any certainty;likely_threatorconfirmed_threat;vendor_unknown, log clearing, tampering, ransomware, named persistence;routing.model_close_*settings), the campaign check, theunmappedblock, and the grey zone for a benign deep verdict.Retro-reopen (
core/retro_reopen.py, next tocore/benign_learning.py). On every threat path, the tenant'smodel_closedalerts that closed in the previous 24 h and share a host, user or IP with the threat are reopened. The paths are:plan_responseand the malicious close (nodes._forget_benign_learning);nodes.escalate);true_positive(api/routers/review.py);maliciouslabel (api/routers/blind_audit.py), both throughapi.common.invalidate_verdicts.A reopened alert is:
queued, with its run reset as on a reprocess (API paths enqueue it at once; workflow paths are picked up by the orphan sweep);summary.reopened, which reaches the next run's state and blocks a model close;related_alert_ids;alert.reopenedwith reasonrelated_threat, plus a timeline event.The reopen is idempotent (only a still-closed
ai_closed:*alert is selected) and tenant-scoped. Failures are counted inlgsotf_retro_reopen_failures_total{path}and logged as errors, never raised; reopens are counted inlgsotf_retro_reopened_total{path}.INV-03 is amended: tier
offnever closes on the model's word; critical and never-close classes never close; a related threat reopens a model close.test_retro_reopen.py: the escalation path; plan_response and the malicious close checked separately, so dropping either call site fails; tenant scope, the 24 h window, idempotence, attach, audit, and the failure metric;test_retro_reopen_api.py: analyst TP, blind-audit label, and the failure metric;test_closure.py.routing_policyruntime check is updated.Docs: the threat model (TM-WRK-2, with a v3 lead and residual risk), architecture, operations metrics, configuration (thresholds removed), INV docs, and
changelog.d/FIX-3.md.openapi.jsonandschema.gen.tsgainsummary.reopened(additive).Measured
Fake model (eval harness plus gates). The fake model follows injected text: this is the worst case for v3, not a real model.
auto_full_auditbenign closed: before reopen → still closedauto_full_auditmalicious closed: before reopen → still closedcv1-0392adv-009auto_full_auditthe malicious-close gates (max 0) fail by design. The tier-off gates pass unchanged.model_closed) and blind audit must.DeepSeek simulation (
fix3_sim.py).decideatauto_full_audit, in stream order; a model close is recorded with its entities.Each malicious close:
cv1-0247(dev, low): reopened bycv1-0232, a malicious alert the model escalated as a threat.cv1-0026(dev, low), Wazuh 60106 "Windows Logon Success", the successful logon of a password-spray campaign: not reopened by an automatic path.cv1-0021(60122, same hostsdc-02/sales-ws-03and IPs, 5 min later) is now never-close (auth failure) and goes to an analyst. Both models called that step benign, so it triggers nothing automatically.true_positiveoncv1-0021reopenscv1-0026(the analyst path, inside 24 h).cv1-0358(corpus_v1, low): reopened bycv1-0406, a benign alert the model escalated as suspicious.Note for the lead: in these attack-dense streams, retro-reopen also reopens most benign closes. In the dev run, 18 of the 25 benign closes are reopened because a suspicious alert shares their host. On a real tenant, where attacks are rare, far fewer would be. But it is the cost of the safety net, and the "about 25/60" acceptance holds only before reopen.
Threat note
model_closed/ai_closed:audit_requiredand enrolled in blind audit;suspiciousno longer blocks;Checks
ruff,mypy(383 files),lint-imports(14 kept), changelog check.pytest tests/unit tests/invariants tests/deploy: 5131 passed.main([BUG] phishing_v1 cassette replay is time-dependent: 4 items miss after some hours #346, fixed separately).🤖 Generated with Claude Code
https://claude.ai/code/session_01JmdYVXkgpNHoygVJCrUeZc