Follow one alert through Calseta. From raw webhook to closed investigation.

An Impossible Travel alert fires in Elastic Security. Here's what happens next — and why your agent gets a complete investigation starting point instead of a raw JSON dump.

Phases 1–4: Deterministic pipeline — zero tokensPhases 5–8: Agent + human — reasoning happens here
Phase 1 · Ingest

Alert arrives via webhook.

202 Accepted in <200ms.

Elastic Security fires an Impossible Travel alert for nick.hathaway@calseta.com — a login from Frankfurt via a known Tor exit node, 148 minutes after a San Francisco login. The raw ECS payload hits POST /v1/ingest/elastic. Calseta validates, enqueues, and returns 202.

elastic-security — raw webhook payload
// Elastic Security ECS alert payload
{
  "kibana.alert.rule": {
    "name": "Impossible Travel Detected",
    "severity": "high",
    "risk_score": 73
  },
  "source": {
    "ip": "185.220.101.47",
    "geo.city_name": "Frankfurt am Main",
    "geo.country_name": "Germany"
  },
  "user": {
    "email": "nick.hathaway@calseta.com",
    "name": "nick.hathaway"
  },
  "event": {
    "action": "user-login",
    "outcome": "success"
  },
  "signal.original_event": {
    "distance_km": 9349,
    "time_delta_minutes": 148
  },
  "okta.security_context": {
    "as.name": "Tor Project, Inc.",
    "domain": "torproject.org",
    "is_proxy": true
  }
  // ... 47 more lines
}
SentinelElasticSplunkWebhook
push webhook< 200msany source
Phase 2 · Normalize

Vendor format in. Clean schema out.

Every indicator found.

Elastic's ECS format uses nested objects and numeric risk scores. Calseta normalizes to clean field names designed for AI consumption — same schema regardless of source. Then a 3-pass extraction pipeline pulls every actionable indicator.

Elastic ECS fields
kibana.alert.rule.name: "Impossible Travel"
kibana.alert.severity: "high"
kibana.alert.risk_score: 73
event.category: ["authentication"]
source.ip: "185.220.101.47"
source.geo.city_name: "Frankfurt am Main"
user.email: "nick.hathaway@calseta.com"
@timestamp: "2025-01-15T03:42:18Z"
Calseta normalized fields
title: "Impossible Travel Detected"
severity: "High"
severity_id: 4
source_name: "elastic"
status: "Open"
occurred_at: "2025-01-15T03:42:18Z"
tags: ["authentication", "identity"]
malice: "Pending"
3-pass indicator extraction
Pass 1 — Source pluginextract_indicators(raw_payload)
ip185.220.101.47ip67.180.201.3accountnick.hathaway@calseta.com
Pass 2 — System mappingsAgainst normalized alert columns
Covered by Pass 1
Pass 3 — Custom mappingsAgainst raw_payload dot-notation
domaintorproject.orgfrom okta.security_context.domain
ip185.220.101.47ip67.180.201.3accountnick.hathaway@calseta.comdomaintorproject.org
Why not OCSF?
OCSF is designed for SIEM interop — numeric class IDs, epoch timestamps, unmapped buckets. Calseta's schema is designed for AI agents — readable field names, enrichment as first-class data, relational indicator model.
source-agnostic3-pass pipeline8 indicator types
Phase 3 · Enrich

Parallel enrichment. Cached.

Automatic verdicts.

Every indicator fans out to all configured providers in parallel. Threat intel, identity context, internal data — whatever your environment needs. Results cached per provider TTL. A failing provider never blocks others. Malice verdicts computed automatically from configurable threshold rules.

Enrichment fan-out — 185.220.101.47
185.220.101.47
Threat Intel
VirusTotal, AbuseIPDB, GreyNoise...
Identity
Okta, Entra, any IdP...
Internal Data
Lambda, Logic Apps, internal APIs...
Custom
Any HTTP endpoint
enrichment — 185.220.101.47
{
  "indicator": "185.220.101.47",
  "type": "ip",
  "malice": "Malicious",
  "enrichment_results": {
    "virustotal": {
      "malicious": 14,
      "suspicious": 2,
      "score": "47/94",
      "as_owner": "Tor Project, Inc."
    },
    "abuseipdb": {
      "confidence_score": 97,
      "total_reports": 1842,
      "is_tor": true,
      "isp": "Tor Project"
    }
  }
}
Any HTTP endpoint is a provider. Trigger an AWS Lambda that pulls internal asset data. Call an Azure Logic App that runs multi-step enrichment. Hit your own API. If it returns JSON, Calseta can extract fields and compute verdicts from it.
Database-driven providers
Add at runtime via API, zero code changes. Every provider is a row in the database — not a Python class.
HTTP template system
Define any enrichment source as a templated HTTP config. URL, headers, body, auth — all configurable. Trigger a Lambda, call a Logic App, hit an internal API.
Field extraction mappings
source_path → target_key per provider per indicator type. You control exactly what your agents see — not the raw API response.
Malice threshold rules
Auto-verdicts from any numeric field. AbuseIPDB score > 80 = Malicious. Your rules, your thresholds, per provider.
async · parallelcache-firstauto-verdictany HTTP source
Phase 4 · Contextualize

Org knowledge.

Attached automatically.

Calseta evaluates every context document's targeting rules against the alert. The Impossible Travel detection rule documentation, Account Compromise Runbook, and Company IR Plan all match. Past alerts involving nick.hathaway or 185.220.101.47 are surfaced too.

Impossible Travel
Detection Rule
TA0001, TA0005
match:rule_name = "Impossible Travel"
Account Compromise Runbook
Runbook
match:severity in [High, Critical]
Company IR Plan
IR Plan
match:global — always included
Past alerts: 2 previous Impossible Travel alerts for nick.hathaway — one closed as True Positive (sessions revoked, password reset, INC-2847), one closed as Benign (VPN exit node, INC-2601).
context-engine — targeting rules
// Targeting rule evaluation
{
  "alert": "Impossible Travel Detected",
  "severity": "High",
  "rule_name": "Impossible Travel",

  "matched_documents": [
    {
      "title": "Impossible Travel",
      "type": "detection_rule",
      "rule": "rule_name = \'Impossible Travel\'",
      "matched": true
    },
    {
      "title": "Account Compromise Runbook",
      "type": "runbook",
      "rule": "severity in [High, Critical]",
      "matched": true
    },
    {
      "title": "Company IR Plan",
      "type": "ir_plan",
      "rule": "global",
      "matched": true
    }
  ],

  "past_alerts": [
    {
      "uuid": "3c1d-a2f4-...",
      "title": "Impossible Travel Detected",
      "status": "closed",
      "classification": "true_positive_suspicious_activity",
      "closed_at": "2024-11-03T14:22:00.000Z",
      "indicators": ["91.108.56.130", "nick.hathaway@calseta.com"],
      "analyst_notes": "Confirmed malicious. Sessions revoked. Password reset. INC-2847."
    },
    {
      "uuid": "7e8b-c9d2-...",
      "title": "Impossible Travel Detected",
      "status": "closed",
      "classification": "benign_positive_suspicious_but_expected",
      "closed_at": "2024-09-17T09:14:00.000Z",
      "indicators": ["185.220.101.47", "nick.hathaway@calseta.com"],
      "analyst_notes": "VPN exit node. User confirmed travel. No action taken. INC-2601."
    }
  ]
}
targeting rulesdetection docsorg context
━━━ Pipeline complete. 1.2 seconds. Zero LLM tokens consumed. ━━━
Phase 5 · Dispatch

Context-rich payload delivered.

The agent reasons — not guesses.

The enriched alert — normalized data, enrichment, detection rule docs, matched runbooks, past alerts, available workflows — is dispatched to every registered agent webhook. One POST. Everything the agent needs.

POST — agent webhook
{
  "event": "alert.enriched",

  "alert": {
    "uuid": "9f2a-b3c1-...", "title": "Impossible Travel Detected",
    "severity": "High", "source": "elastic", "malice": "Malicious"
  },

  "indicators":          // 3 indicators, fully enriched
  "detection_rule":     // name, MITRE, docs, blind spots
  "past_alerts":        // 2 previous (1 TP, 1 benign)
  "context_documents": // IR plan + runbook
  "workflows":          // 6 available actions
}
Agent Analysis — Impossible Travel (nick.hathaway)
Evidence: Source IP 185.220.101.47: Tor exit node, AbuseIPDB 97 Travel: 9,349 km in 148 minutes (physically impossible) Previous TP for same user: INC-2847 (sessions revoked) Detection rule blind spots: VPN exit nodes BUT: AS4224 (Tor Project) — not a corporate VPN Conclusion: True Positive — credential compromise Confidence: 0.92 Actions: Revoke sessions, Force password reset, Post finding
Calseta does not run this agent. Your agent reads the data and reasons for itself. The intelligence stays in the agent — the infrastructure stays in the data layer.
HTTPSlack BotLangChainMCP Client
webhook deliveryREST + MCPframework-agnostic
Phase 6 · Execute

Agent triggers a response.

Sandboxed. Versioned. Audited.

The agent calls execute with the indicator, a reason, and confidence score. The workflow is an HTTP automation script — Python glue that calls external APIs via ctx.http. Calseta validates the code via AST checking, runs it in a sandbox, and logs every step.

workflow — execute
{
  "workflow_uuid": "wf-8a3c-...",
  "indicator_type": "account",
  "indicator_value": "nick.hathaway@calseta.com",
  "trigger_source": "agent",
  "reason": "Confirmed Tor exit node login. AbuseIPDB: 97. Previous TP for same user.",
  "confidence": 0.92
}
revoke-user-sessions.py — v3
# Revoke all active sessions for the affected account
async def run(ctx):
    user = ctx.indicator.value
    okta = ctx.secrets["OKTA_API_TOKEN"]

    # Find Okta user ID
    resp = await ctx.http.get(
        f"https://{ctx.secrets['OKTA_DOMAIN']}/api/v1/users/{user}",
        headers={"Authorization": f"SSWS {okta}"}
    )
    user_id = resp.json()["id"]

    # Clear all sessions
    await ctx.http.delete(
        f"https://{ctx.secrets['OKTA_DOMAIN']}/api/v1/users/{user_id}/sessions",
        headers={"Authorization": f"SSWS {okta}"}
    )

    ctx.log(f"Revoked all sessions for {user}")
    return WorkflowResult.ok(
        message=f"Sessions revoked for {user}",
        data={"user_id": user_id}
    )
AST sandbox
Validated imports: stdlib + calseta.workflows only. No arbitrary code execution.
Code versioning
Every edit tracked with version history. Rollback to any previous version anytime.
Test mode
Mock HTTP interception. Run workflows against real alert data without making real API calls.
AST sandboxversionedtest mode
Phase 7 · Approve

High-risk action?

Human decides.

The workflow has approval_mode: "always" and risk_level: high. The approval gate fires — a Slack message appears in #security-approvals with the agent's reason, confidence, and approve/reject buttons.

#security-approvals
Calseta
Calseta Workflow ApprovalAPP12:42 AM
Workflow: Revoke User Sessions
Trigger: agent (Investigation Agent #1)
Risk level: high
REASON
Confirmed Tor exit node login (185.220.101.47, AbuseIPDB: 97). Previous TP for same user (INC-2847). Confidence: 0.92.
Indicator: nick.hathaway@calseta.com (account)
Alert: Impossible Travel Detected (High)
Expires in 30m
Microsoft Teams — Adaptive Card
Workflow Approval Required
Workflow: Revoke User Sessions
Risk: high
Confidence: 0.92
Approve via REST ↗Reject via REST ↗
Teams uses incoming webhook only — buttons link to REST endpoints
Slack interactive buttonsTeams adaptive cardsconfigurable timeoutalways · agent-only · never
human-in-the-loopSlack + Teamsrisk-gated
Phase 8 · Resolve

Alert closed. Metrics updated.

Everything audited.

The analyst approves. Sessions revoked. The agent posts its finding, updates the status to Closed with classification "True Positive — Credential Compromise." MTTD, MTTA, and MTTC are updated. The immutable activity log records every action.

Activity timeline
03:42:18alert_ingestedsystem
Impossible Travel Detected (High)
03:42:19enrichment_completedsystem
3 indicators, 4 providers
03:42:22agent_webhook_sentsystem
→ Investigation Agent #1
03:42:25finding_postedapi
True Positive — Tor exit node...
03:42:26workflow_executedapi
Revoke Sessions (pending_approval)
03:42:26workflow_executedapi
Force Password Reset (pending_approval)
03:42:41workflow_approvedapi
analyst@calseta.com — 2 workflows
03:42:42workflow_completedsystem
Sessions revoked
03:42:43workflow_completedsystem
Password reset forced
03:42:44status → Closedapi
TP — Credential Compromise
MTTD
8m
Mean time to detect
MTTA
4s
Mean time to acknowledge
MTTC
26s
Mean time to close
FP Rate
12.5%
False positive rate
system
api (agent / analyst)
immutable audit logMTTD · MTTA · MTTCclassification tracking

One alert. Zero tokens wasted.

That's what your agents deserve.

From raw webhook to closed investigation. Calseta handles the deterministic infrastructure. Your agents handle the reasoning.

Open source · Self-hostable · Apache 2.0