Cross-session behavioral analysis for Axor via weighted resource reputation graph
Project description
axor-sentinel
Cross-session behavioral analysis layer for axor-core. Detects slow-and-low staging attacks — coordinated data exfiltration spread across many sessions over days or weeks — that are invisible to per-session anomaly detection.
The problem it solves
Per-session anomaly detectors see each session in isolation. An attacker staging an exfiltration across dozens of short, individually normal sessions — touching sensitive resources a little each time, then exfiltrating later — never exceeds any single-session threshold.
axor-sentinel maintains a resource reputation graph across all sessions. Resources accumulate suspicion over time, and that suspicion is fed back to axor-core as observe-only telemetry: it never denies a request on its own. The only enforcement coupling is opt-in — when a resource's suspicion is high enough, core's DegradationEngine (configured with a detection_floor) can tighten the session's degradation level, narrowing the surface. Reputation is a signal that raises caution, not a gate.
How it works
sessions (axor-core)
│
▼
SentinelCycle ← background audit, runs every ~1h
├── evidence sets ← windowed typed facts per resource (30-day TTL, exact expiry)
├── predicates P1–P4 ← declared, decidable: export-denied / distinct-origin
│ export-adjacency / staging count / staged-then-export
├── fanout quota ← > N distinct containers in one tainted session
│ (N declared per actor class — no self-trained baseline)
├── adjacency labels ← sharing a container with a FLAGGED resource ⇒ WATCH
└── snapshot swap ← atomic write to disk (symlink rename / os.replace)
│
▼
ReputationSnapshot ← resource_id → LEVEL_SUSPICION[level], a FINITE
codomain (0.0 clean / 0.4 watch / 1.0 flagged) +
level names and the facts behind each verdict;
the old scalar scores ride along as telemetry
│
▼
SnapshotIntentEnricher ← converts suspicion → trust, populates
│ NormalizedIntent.target_resource_reputation (telemetry)
▼
IntentLoop (axor-core) ← observe-only: records the reputation signal; with an
opt-in detection_floor it can only TIGHTEN degradation,
never deny. (floor in (0.001, 0.6) ⇒ FLAGGED-only;
floor ≥ 0.6 ⇒ WATCH too — decidable end-to-end)
Polarity note. Sentinel scores suspicion (high = bad). Core's reputation field is trust (a positive reading
<=detection_floorcrosses and tightens;0.0= unknown).SnapshotIntentEnricherconverts at the boundary (reputation = 1 - suspicion), so core tightens on suspicious resources.
Score accumulation uses logarithmic diminishing returns — each signal contributes proportionally to remaining headroom, so scores are bounded to [0, 1] and saturate naturally:
new_score = current + new_weight × (1 − current)
Quick start
pip install -e ".[neo4j]"
from pathlib import Path
from axor_sentinel.sentinel.cycle import SentinelCycle
from axor_sentinel.integration.intent_enricher import SnapshotIntentEnricher
from axor_sentinel.sentinel.weight import FLAG_THRESHOLD
from axor_core.degradation.engine import DegradationEngine
snapshot_dir = Path("~/.axor/sentinel").expanduser()
# Background audit cycle (runs hourly, not on hot path)
cycle = SentinelCycle(neo4j_session, snapshot_dir=snapshot_dir)
snapshot = cycle.run_once(sessions)
# Hot-path enrichment — pure dict lookup, no Neo4j
enricher = SnapshotIntentEnricher.from_dir(snapshot_dir)
# Wire into axor-core IntentLoop. Enrichment alone only populates telemetry; to act
# on it, give the loop a DegradationEngine with a detection_floor so a suspicious
# resource TIGHTENS degradation (never denies). The floor pairs with the suspicion
# flag threshold: floor = 1 - FLAG_THRESHOLD.
degradation = DegradationEngine(detection_floor=1.0 - FLAG_THRESHOLD)
loop = IntentLoop(..., reputation_enricher=enricher, degradation_engine=degradation)
Bench suite
820-scenario synthetic dataset (paper baseline):
pip install -e ".[bench]"
from axor_sentinel.bench.dataset.composer import DatasetComposer
from axor_sentinel.bench.eval.metrics import evaluate
scenarios = DatasetComposer().compose() # 820 scenarios, seed=42
result = evaluate(scenarios, scores=my_scores)
print(result.tpr_at_fpr_budget) # TPR @ FPR ≤ 0.02
See docs/architecture.md for the full design: graph schema, weight model, invariants, attack patterns, and bench composition.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file axor_sentinel-0.3.1.tar.gz.
File metadata
- Download URL: axor_sentinel-0.3.1.tar.gz
- Upload date:
- Size: 137.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e08008fd700c5b506bcea0db2b0f6fd15320d964abac40a5713e708089ed1c26
|
|
| MD5 |
375259da02cf400d0ac6204634b41179
|
|
| BLAKE2b-256 |
57aac38eab772367e10342d4d1209a636a7a3067d34bc42e9bb3221a526476ea
|
Provenance
The following attestation bundles were made for axor_sentinel-0.3.1.tar.gz:
Publisher:
ci.yml on Bucha11/axor-sentinel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axor_sentinel-0.3.1.tar.gz -
Subject digest:
e08008fd700c5b506bcea0db2b0f6fd15320d964abac40a5713e708089ed1c26 - Sigstore transparency entry: 2159591252
- Sigstore integration time:
-
Permalink:
Bucha11/axor-sentinel@1ff5137a684a94b9dd55e2570ac1fd37d2700173 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/Bucha11
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@1ff5137a684a94b9dd55e2570ac1fd37d2700173 -
Trigger Event:
push
-
Statement type:
File details
Details for the file axor_sentinel-0.3.1-py3-none-any.whl.
File metadata
- Download URL: axor_sentinel-0.3.1-py3-none-any.whl
- Upload date:
- Size: 73.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22dc24e4eaa50c6605881820964a2061cd6cae047ad99f6ba19e4cb226275700
|
|
| MD5 |
7f8f01c578703f7ed982f2839c48e72e
|
|
| BLAKE2b-256 |
ceb196ad0ca390cd23d8bb88248b76264492a2a162c67d13a04205179ab570a8
|
Provenance
The following attestation bundles were made for axor_sentinel-0.3.1-py3-none-any.whl:
Publisher:
ci.yml on Bucha11/axor-sentinel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axor_sentinel-0.3.1-py3-none-any.whl -
Subject digest:
22dc24e4eaa50c6605881820964a2061cd6cae047ad99f6ba19e4cb226275700 - Sigstore transparency entry: 2159591282
- Sigstore integration time:
-
Permalink:
Bucha11/axor-sentinel@1ff5137a684a94b9dd55e2570ac1fd37d2700173 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/Bucha11
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@1ff5137a684a94b9dd55e2570ac1fd37d2700173 -
Trigger Event:
push
-
Statement type: