XLog is a security testing and simulation platform that combines synthetic log generation, scenario-based attack telemetry, and AI-orchestrated workflows through MCP.
- Synthetic log generation in SYSLOG, CEF, LEEF, WINEVENT, JSON, Incident, XSIAM Parsed, and XSIAM CEF formats.
- Scenario-based telemetry with multi-step MITRE ATT&CK tactics from JSON scenarios or on-the-fly scenario input.
- Streaming workers that continuously send logs to UDP, TCP, HTTP(S), XSIAM PAPI, or XSIAM webhook collectors.
- Field catalog and observables tooling to discover supported fields and generate realistic observables and technology stacks.
- Simulation skills library with CRUD tooling for skill files (foundation, scenarios, validation, workflows).
- MCP integrations for CALDERA (abilities, adversaries, operations, agents, payloads) and XSIAM (XQL, datasets, lookups, assets, cases, issues).
- Web agent for chat-based orchestration and skills management built in Next.js with Gemini/Vertex support.
xlog/
├── app/ # GraphQL API for log generation and workers
├── scenarios/ # Scenario definitions (ready and drafts)
├── mcp/
│ ├── server/ # MCP server exposing XLog, CALDERA, XSIAM tools
│ └── agent/ # Next.js MCP chat and skills UI
├── scripts/ # Utility scripts
├── examples/ # GraphQL request examples
└── img/ # Documentation images
- Run the core GraphQL API:
pip install -r requirements.txt uvicorn main:app --host 0.0.0.0 --port 8000 --reload
- Run example queries:
python examples/graphql_generate_fake_data.py python examples/graphql_workers_and_scenarios.py
- For MCP server and agent setup, follow their READMEs below.
The GraphQL endpoint is served at http://localhost:8000/.
getSupportedFields-> returns the supported fields list used for observables and required fields.generateFakeData(requestInput: DataFakerInput)-> returns a batch of synthetic logs.generateScenarioFakeData(requestInput: DetailedScenarioInput)-> returns multi-step scenario logs without starting workers.createDataWorker(requestInput: DataWorkerCreateInput)-> starts a streaming worker.createScenarioWorker(requestInput: ScenarioWorkerCreateInput)-> starts workers from ascenarios/ready/*.jsonfile.createScenarioWorkerFromQuery(requestInput: ScenarioQueryWorkerCreateInput)-> starts workers from inline scenario steps.listWorkers-> lists active workers.actionWorker(requestInput: DataWorkerActionInput)-> stops a worker or checks status.generateObservables(requestInput: GenerateObservablesInput)-> generates observables from threat intel feeds.
type(required):SYSLOG,CEF,LEEF,WINEVENT,JSON,Incident,XSIAM_Parsed,XSIAM_CEFcount(default1)vendor,product,versiondatetimeIso(YYYY-MM-DD HH:MM:SS)fields(comma-separated field list)observablesDict(object of supported fields)requiredFields(list of supported field enums)
name(required)tags(optional list)steps(list ofDetailedScenarioStep)
DetailedScenarioStep:
tactic,tacticId,technique,techniqueId,procedure,typelogs(list ofDataFakerInput)
type(required):SYSLOG,CEF,LEEF,WINEVENT,JSON,Incident,XSIAM_Parsed,XSIAM_CEFdestination(required):udp:host:port,tcp:host:port,https://...,XSIAM, orXSIAM_WEBHOOKcount(default1),interval(default2)vendor,product,versionfields,observablesDict,requiredFields,datetimeIsoverifySsl(defaultfalse)
When sending logs to a XSIAM custom HTTP collector (for example, alongside a SYSLOG destination), configure the collector with:
- Compression:
uncompressed - Log format:
json
scenario(required): filename without.jsoninscenarios/ready/destination(required)count,interval,vendor,datetimeIso,verifySsl
name(required)destination(required)tags(optional list)steps(list ofDetailedQueryScenarioStep)
DetailedQueryScenarioStep:
tactic,tacticId,technique,techniqueId,procedure,typelogs(list ofWorkerFakerInput)
WorkerFakerInput:
type(required),count,intervalvendor,product,versiondatetimeIso,fields,observablesDict,requiredFields,verifySsl
worker(required)action(required):STOPorSTATUS
count(required)observableType(required):IP,URL,SHA256,CVE,TERMSknown(defaultBAD):BADorGOOD
Generate fake data (SYSLOG):
query Example($input: DataFakerInput!) {
generateFakeData(requestInput: $input) {
count
type
data
}
}Generate fake data with observables (JSON):
query ExampleJson($input: DataFakerInput!) {
generateFakeData(requestInput: $input) {
count
type
data
}
}Example variables:
{
"input": {
"type": "JSON",
"count": 2,
"datetimeIso": "2025-01-05 18:29:25",
"observablesDict": {
"remoteIp": "203.0.113.10",
"localIp": "10.0.0.5",
"user": "svc-backup",
"url": "https://example.com/login"
}
}
}Create a worker:
query CreateWorker($input: DataWorkerCreateInput!) {
createDataWorker(requestInput: $input) {
worker
status
type
destination
}
}List workers:
query ListWorkers {
listWorkers {
worker
status
type
interval
destination
}
}Stop a worker:
query StopWorker($input: DataWorkerActionInput!) {
actionWorker(requestInput: $input) {
worker
status
}
}Generate scenario fake data:
query Scenario($input: DetailedScenarioInput!) {
generateScenarioFakeData(requestInput: $input) {
name
steps
}
}scenarios/README.md- Scenario format and examplesmcp/server/README.md- MCP server capabilities and setupmcp/agent/README.md- Next.js agent setup and usagemcp/server/skills/README.md- Skill library structure
