Text Classification
Scikit-learn
Joblib
English
fraud-detection
agent-security
mcp
agentic-ai
payment-security
behavioral-detection
random-forest
session-graph
Instructions to use withgordon/acb-guard-session-graph-rf with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Scikit-learn
How to use withgordon/acb-guard-session-graph-rf with Scikit-learn:
from huggingface_hub import hf_hub_download import joblib model = joblib.load( hf_hub_download("withgordon/acb-guard-session-graph-rf", "sklearn_model.joblib") ) # only load pickle files from sources you trust # read more about it here https://skops.readthedocs.io/en/stable/persistence.html - Notebooks
- Google Colab
- Kaggle
| library_name: sklearn | |
| tags: | |
| - fraud-detection | |
| - agentic-commerce | |
| - agent-safety | |
| - mcp | |
| - random-forest | |
| - tabular-classification | |
| - session-graph | |
| - anomaly-detection | |
| pipeline_tag: tabular-classification | |
| inference: false | |
| extra_gated_prompt: "This model is part of the ACB-Guard research suite. Access is granted for research and evaluation purposes." | |
| # ACB-Guard · Session Graph RandomForest (`session_graph_rf`) | |
| A structural fraud detector for **agentic commerce sessions**. Every agent session is | |
| represented as a directed graph of MCP (Model Context Protocol) calls, reduced to a | |
| compact 20-dimensional feature vector, and scored by a scikit-learn | |
| `RandomForestClassifier`. It is a novel baseline for | |
| **AgentCommerceBench (ACB)** and ships as a drop-in per-event detector. | |
| > **Core idea.** MCP call sequences form distinctive graphs per persona. Clean sessions | |
| > produce regular, low-density graphs. Attacks introduce structural anomalies — high | |
| > out-degree (reconnaissance), recursive purchase cycles, amount-variance spikes (price | |
| > poisoning / ratcheting), and timing bursts. A graph view catches *behavioral* attacks | |
| > that a text classifier alone will miss. | |
| --- | |
| ## Model at a glance | |
| | | | | |
| |---|---| | |
| | **Model name** | `session_graph_rf` | | |
| | **Task** | Binary session classification — `clean` (0) vs `attacked` (1) | | |
| | **Algorithm** | `RandomForestClassifier` (scikit-learn), 200 trees, `max_depth=10`, `class_weight="balanced"` | | |
| | **Input** | An agent commerce session (ordered list of MCP events) | | |
| | **Output** | Fraud probability `P(fraud) ∈ [0, 1]` + top contributing feature flags | | |
| | **Feature space** | 20 hand-engineered session-graph features | | |
| | **Serialized as** | `session_graph_rf.joblib` (~833 KB, joblib/pickle) | | |
| | **Interface** | `detect(event, history) -> (score, flags)` — drop-in with other ACB detectors | | |
| | **Access** | 🔒 Gated | | |
| --- | |
| ## Why a graph model | |
| ACB attacks fall into two broad families, and each needs a different lens: | |
| - **L1 — prompt / payload attacks.** Injected instructions, base64-encoded payloads, | |
| "SYSTEM:" overrides, and settlement-proxy redirects embedded in request text. These are | |
| best caught by an LLM safety baseline and by lightweight payload heuristics. | |
| - **L2 — behavioral attacks.** Reconnaissance sweeps, recursive purchases, price | |
| ratcheting, and scope violations that look *fine per message* but are anomalous at the | |
| **session** level. Text classifiers, which score one message at a time, are effectively | |
| blind to these. | |
| `session_graph_rf` targets the L2 gap by modelling the *shape* of a whole session, while | |
| still carrying two cheap L1 signals (`has_override`, `has_b64`) so it degrades gracefully | |
| when both attack families appear together. It is designed to **complement**, not replace, | |
| the LLM safety baseline in the ACB-Guard ensemble. | |
| --- | |
| ## How it works | |
| ### 1. Session → graph | |
| Each session is treated as a directed graph: | |
| - **Nodes** — the agent plus every distinct `service_id` / `operation_id` it touches. | |
| - **Edges** — directed call edges (`FIND_SERVICE → service`, `AUTHORIZE → service`, …). | |
| - **Edge attributes** — normalized USDC amount, inter-event timing gap (seconds), and | |
| service category. | |
| ### 2. Graph → 20-dim feature vector | |
| `session_to_features(session)` reduces the graph to a fixed vector. Grouped by the signal | |
| it is meant to expose: | |
| | # | Feature | Signal | | |
| |---|---|---| | |
| | 0 | `n_events` | session size | | |
| | 1 | `n_find_service` | discovery volume | | |
| | 2 | `n_authorize` | authorization volume | | |
| | 3 | `n_settle` | settlement volume | | |
| | 4 | `find_authorize_ratio` | **reconnaissance** (search-heavy, buy-light) | | |
| | 5 | `n_distinct_services` | breadth of services touched | | |
| | 6 | `service_diversity` | entropy of the service distribution | | |
| | 7 | `total_amount_usdc` | total spend | | |
| | 8 | `max_amount_usdc` | largest single transfer | | |
| | 9 | `amount_std_usdc` | **price ratcheting / poisoning** (variance) | | |
| | 10 | `amount_max_ratio` | spike vs. session mean | | |
| | 11 | `timing_gap_mean_s` | pacing | | |
| | 12 | `timing_gap_std_s` | **burst** irregularity | | |
| | 13 | `timing_gap_min_s` | tightest burst | | |
| | 14 | `n_categories` | category breadth | | |
| | 15 | `dominant_category_frac` | **scope violation** (purity) | | |
| | 16 | `n_a2a_transfers` | agent-to-agent transfer count | | |
| | 17 | `a2a_amount_usdc` | agent-to-agent spend | | |
| | 18 | `has_override_keyword` | **L1** — `SYSTEM:` / override / proxy-redirect in payload | | |
| | 19 | `has_b64_blob` | **L1** — suspicious base64 blob in payload | | |
| Amounts are converted from integer units to USDC (`amount_units / 1_000_000`). | |
| `service_diversity` is Shannon entropy over the service-call distribution. The two L1 | |
| flags run regex/base64 checks over each event's `original_request`. | |
| ### 3. Vector → score | |
| The RandomForest returns `P(fraud)`. Scores below **0.30** are suppressed to `0.0` to keep | |
| the false-positive rate low. When a session is flagged, the detector attributes the | |
| decision by ranking `feature_importance × |feature_value|` and emitting the top-3 | |
| contributing features as human-readable flags (e.g. `sgrf:find_auth_ratio=8.00`). | |
| --- | |
| ## The detector interface | |
| The model plugs into the ACB harness through a per-event `detect` call and scores the | |
| **full session** (history + current event) each time: | |
| ```python | |
| def detect(event: Event, history: list[Event]) -> tuple[float, list[str]]: | |
| ... | |
| ``` | |
| - Returns `0.0, []` until the session has **≥ 4 events** (not enough context to judge). | |
| - Caches per `(session_id, session_length)` so the RandomForest runs at most once per | |
| session growth step — cheap enough to call on every event. | |
| - `score` is `P(fraud)`; `flags` are the top contributing features for attribution. | |
| --- | |
| ## Usage | |
| The repository ships two files: | |
| - `session_graph.py` — feature extraction + `SessionGraphModel` class and module-level API. | |
| - `session_graph_rf.joblib` — the fitted `RandomForestClassifier`. | |
| ### Load the trained classifier | |
| ```python | |
| import joblib | |
| from huggingface_hub import hf_hub_download | |
| # Gated repo — authenticate first: `huggingface-cli login` | |
| path = hf_hub_download( | |
| repo_id="withgordon/acb-guard-session-graph-rf", | |
| filename="session_graph_rf.joblib", | |
| ) | |
| clf = joblib.load(path) # sklearn RandomForestClassifier | |
| # clf expects a 20-dim feature vector produced by session_to_features(...) | |
| # proba = clf.predict_proba(features_20d.reshape(1, -1))[0][1] # P(fraud) | |
| ``` | |
| ### Score a session end-to-end | |
| ```python | |
| from benchmark.models.session_graph import SessionGraphModel | |
| model = SessionGraphModel() | |
| model.fit(train_sessions) # list[Session] | |
| score, flags = model.detect(event, history) # drop-in detector interface | |
| print(score, flags) # e.g. 0.87 ['sgrf:find_auth_ratio=8.00', ...] | |
| ``` | |
| > **Note.** `session_graph.py` imports session/event schema types from the ACB harness | |
| > (`harness.simulate.schema`: `Session`, `Event`, `ActionType`). Feature extraction and | |
| > the `detect` interface require those types to be importable, so run it inside the ACB | |
| > benchmark environment. | |
| --- | |
| ## Training | |
| - **Estimator.** `RandomForestClassifier(n_estimators=200, max_depth=10, class_weight="balanced", random_state=42)`. | |
| - **Labels.** `0` for `session.is_clean`, `1` otherwise. | |
| - **Features.** The 20-dim vector above, stacked across all training sessions. | |
| - **Class balance.** Handled via `class_weight="balanced"` (attacked sessions are the | |
| minority class). | |
| - **Determinism.** `random_state=42` for reproducible fits. | |
| Retraining is a single call: | |
| ```python | |
| model = SessionGraphModel(n_estimators=200, max_depth=10) | |
| model.fit(train_sessions) | |
| joblib.dump(model.clf, "session_graph_rf.joblib") | |
| ``` | |
| --- | |
| ## Intended use & scope | |
| **Intended.** A behavioral, session-level fraud baseline for AgentCommerceBench and for | |
| research on safety in agentic commerce / MCP tool-use settings. Best used as one member of | |
| an ensemble alongside an LLM safety baseline. | |
| **Out of scope.** Not a standalone production fraud system; not a general payments risk | |
| model; not intended for real financial authorization decisions. The two embedded L1 flags | |
| are convenience signals, not a substitute for a dedicated prompt-injection defense. | |
| --- | |
| ## Limitations | |
| - **Feature-engineered, not learned graph structure.** The model consumes hand-crafted | |
| aggregate features rather than a learned graph embedding (no GNN). It captures the | |
| intended structural signals but not arbitrary graph patterns. | |
| - **Cold start.** Returns `0.0` for the first 3 events of every session by design; very | |
| short attacks may complete before enough context accumulates. | |
| - **Threshold coupling.** The 0.30 suppression threshold trades recall for precision and | |
| may need re-tuning per deployment / attack mix. | |
| - **Distribution shift.** Trained on ACB-simulated sessions; behavior on real-world agent | |
| traffic, unseen attack strategies, or different MCP schemas is not characterized here. | |
| - **Attribution is heuristic.** Flags rank `importance × |value|`, an approximation of true | |
| per-prediction contribution — treat them as hints, not SHAP-grade explanations. | |
| - **Serialization caveat.** Distributed as a joblib/pickle artifact; only load it from a | |
| source you trust. | |
| --- | |
| ## Files | |
| | File | Description | | |
| |---|---| | |
| | `session_graph.py` | Feature extraction, `SessionGraphModel`, and module-level `detect` API | | |
| | `session_graph_rf.joblib` | Fitted scikit-learn `RandomForestClassifier` (~833 KB) | | |
| --- | |
| ## Citation | |
| ```bibtex | |
| @software{acb_guard_session_graph_rf, | |
| title = {ACB-Guard: Session Graph RandomForest for Agentic Commerce Fraud Detection}, | |
| author = {withgordon}, | |
| year = {2026}, | |
| note = {A novel session-graph baseline for AgentCommerceBench}, | |
| url = {https://huggingface.co/withgordon/acb-guard-session-graph-rf} | |
| } | |
| ``` | |
| --- | |
| *Part of the **ACB-Guard** suite for AgentCommerceBench. This model targets L2 behavioral | |
| attacks and is designed to complement an LLM safety baseline that handles L1 payload | |
| attacks.* | |