feat(trace): IncrementalFraudDetector, Delegation Audit extension, and tests#524
Conversation
Adds StepSpec dataclass and SequenceDetector base structure to finbot/ctf/detectors/primitives/. Includes config validation, get_relevant_event_types(), and stubbed private helpers for history querying, step matching, and time-window checks. check_event() and all helpers are NotImplementedError stubs pending implementation.
…gration - Add SequenceDetector to finbot/ctf/detectors/primitives/ Detects multi-step attack patterns across a session or workflow window. Supports ordered step matching, glob event_type patterns, within_n_events and within_seconds windows, and all ToolCallDetector field operators. Challenge authors configure it from YAML with no Python required. - Add composite index idx_ctf_event_session_ts_type on (session_id, timestamp, event_type) to keep session-window history queries below 10ms p95. - Export SequenceDetector from finbot/ctf/detectors/primitives/__init__.py - Add 17 unit tests covering full sequence detection, partial sequences, order enforcement, session/workflow windows, condition operators, and glob event_type matching.
- Add StepSpec TypedDict to sequence_detector.py matching the approved interface spec; export it from primitives __init__ - Add benchmark test: seeds 1,000 CTFEvent rows with composite index, runs check_event 100 times, asserts p95 < 10ms Current result: p50 ~7ms, p95 ~8ms on SQLite
…, and tests - IncrementalFraudDetector uses SequenceDetector as the matching engine; two-gate design: N below-threshold approvals in session window, then cumulative amount check fires when total >= cumulative_threshold - incremental_fraud.yaml: 300pts, ASI-08, fraud category; default config: 3 approvals each <= 9999, cumulative >= 25000 - Extend _emit_delegation_event() in orchestrator.py with context_preview field (first 500 chars of enriched context forwarded between agents) - Emit delegation.context_snapshot business event on every delegation hop making context forwarding observable and scoreable by detectors - Integration tests for IncrementalFraudDetector: full chain, 5-step sequence, session isolation, amount gates, rejection filtering - Unit tests for Delegation Audit: context capture, preview capping, event type validation, empty context handling
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a new multi-step session/workflow sequence detector and an incremental fraud challenge/detector, plus supporting DB indexing and TRACE delegation auditing, with accompanying unit/integration/benchmark tests.
Changes:
- Introduces
SequenceDetector(primitive) andIncrementalFraudDetector(implementation) + new CTF challenge YAML. - Adds a composite DB index to speed up session-window event lookups.
- Extends orchestrator delegation events with
context_previewand emits a newdelegation.context_snapshotbusiness event; adds tests around this.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
finbot/ctf/detectors/primitives/sequence_detector.py |
Adds configurable multi-step sequence detection across session/workflow windows. |
finbot/ctf/detectors/implementations/incremental_fraud.py |
Builds an incremental-fraud detector on top of SequenceDetector. |
finbot/ctf/detectors/primitives/__init__.py |
Exposes SequenceDetector and StepSpec via primitives package. |
migrations/versions/2026_06_03_add_ctf_event_session_index.py |
Adds composite index intended to accelerate session-window queries. |
finbot/ctf/definitions/challenges/fraud/incremental_fraud.yaml |
Defines the new “Incremental Fraud” challenge and its detector config. |
finbot/agents/orchestrator.py |
Captures/enriches prior context and emits new TRACE audit events during delegation. |
finbot/tools/data/vendor.py |
Switches vendor tool DB access from db_session() to get_db(). |
tests/unit/ctf/test_sequence_detector.py |
Adds unit tests for SequenceDetector behavior and operators. |
tests/unit/ctf/test_incremental_fraud.py |
Adds integration tests for IncrementalFraudDetector with SQLite. |
tests/unit/ctf/test_sequence_detector_benchmark.py |
Adds a p95 latency benchmark for session-window check_event queries. |
tests/unit/agents/test_delegation_audit.py |
Adds tests validating emitted delegation audit fields/events. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
steadhac
left a comment
There was a problem hiding this comment.
Good work overall — the two-gate design, SequenceDetector primitive, and delegation audit extension are solid. Two blocking bugs flagged inline that need fixing before merge:
re.search → re.fullmatch (sequence_detector.py L231) — substring match causes false positives in fraud detection.
_load_amounts missing namespace filter (incremental_fraud.py L177) — query should include CTFEvent.namespace == namespace as a guard.
| if op == "lte": | ||
| return float(actual) <= float(expected) | ||
| if op == "matches": | ||
| return bool(re.search(expected, str(actual), re.IGNORECASE)) |
There was a problem hiding this comment.
Line 231 - re.search matches anywhere in the string, so a condition like "matches": "approval" would falsely match "not_approval" or "partial_approval_pending". This is a logic bug that could cause false positives in fraud detection, which is a security-critical path.
Suggested fix:
return bool(re.fullmatch(expected, str(actual), re.IGNORECASE))
| rows = ( | ||
| db.query(CTFEvent) | ||
| .filter(CTFEvent.id.in_(event_ids)) | ||
| .all() |
There was a problem hiding this comment.
Lines: 175–178 _load_amounts has no namespace guard. Filters only by primary key, no namespace check. While ID collisions across namespaces are very unlikely with a surrogate PK, it is a latent correctness gap — if the IDs somehow resolve to rows from a different namespace (e.g. after a DB restore/migration), the amounts loaded are wrong. Costs nothing to add.
Since namespace is already read inside check_event (where _load_amounts is called from), you just need to pass it as an argument: self._load_amounts(db, event_ids, namespace) and update the signature accordingly.
Summary
IncrementalFraudDetector— the first multi-step challenge detector in FinBot, built onSequenceDetectorincremental_fraud.yaml— playable challenge in the fraud category_emit_delegation_event()in orchestrator withcontext_previewfield and a newdelegation.context_snapshotbusiness eventIncrementalFraudDetector
Uses
SequenceDetectoras the matching engine with a two-gate design:amount <= single_threshold>= cumulative_thresholdDefault config (from YAML): 3 approvals, each
<= $9,999, cumulative>= $25,000. Maps to OWASP ASI-08 (Cascading Failures).Delegation Audit Extension
_emit_delegation_event()now:context_preview: enriched_context[:500]to the existingdelegation_completeagent eventbusiness.delegation.context_snapshotevent on every delegation hopThis makes the context forwarded between agents observable for the first time. Every delegation from orchestrator to a sub-agent now leaves an audit trail of what context was passed.
Files changed
finbot/ctf/detectors/implementations/incremental_fraud.pyfinbot/ctf/definitions/challenges/fraud/incremental_fraud.yamlfinbot/agents/orchestrator.pytests/unit/ctf/test_incremental_fraud.pytests/unit/agents/test_delegation_audit.pyTest plan