MIT License

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

AiSOC:把“AI 研判”这一步做成可回放的审计证据

项目背景与痛点

安全运营中心(SOC)中最常见的情形是:当一名分析师打开工作日开始时,队列里已经积压了几百上千条告警。SIEM 规则、EDR 行为检测、云审计日志各自产生大量告警,真正有意义的往往只有个位数。行业里长期的做法是靠“调规则、降噪声”来解决,但规则调优存在明显的边际收益递减问题,而且每新增一个数据源,噪声就会重新上涨一轮。

于是 LLM 自然被寄予厚望:既然模型能读日志、能推理,让它做一线分诊岂不是正好?可现实是,绝大多数“AI SOC”在真正进入企业时都卡在同一处——不可复现、不可追责。同一个告警,模型今天说是误报、明天说是横向移动,中间没有任何一条中间步骤被记录下来;安全团队因此无法向审计方解释“为什么自动关闭了这条高危告警”。在安全领域,一个无法解释的自动化决策,比没有自动化更危险。

AiSOC 切入的正是这个缺口。它并没有宣称自己“更聪明”,而是把重点押在了告警融合 + 可回放的决策账本上:既能自动分诊,又能把 Agent 每一步取证、推理、结论都固化成可重放、可审计的证据链。

核心技术揭秘

从项目描述反推,它的数据流大致是三层:归一化 → 融合 → Agent 研判,而账本贯穿始终。

graph TD A[告警源<br/>SIEM / EDR / 云审计] --> B[归一化层<br/>统一实体与时间模型] B --> C[融合引擎<br/>实体图聚类与去重] C --> D[案件 Case<br/>攻击链假设] D --> E[Agent 编排器<br/>规划-取证-研判] E --> F[工具层<br/>ATT&CK 知识库与资产上下文] E --> G[决策账本<br/>逐步哈希留存] F --> E G --> H[重放与审计<br/>复盘每一次判断] E --> I{"研判结论"} I -->|"确认威胁"| J[升级响应] I -->|"判定误报"| K[自动关闭并记录依据] I -->|"证据不足"| L[转人工复核] H --> M[MCP Server<br/>Claude / Cursor / Continue]

第一层是实体图聚类。告警融合的难点不在于“去重”,而在于判断两条来源不同的告警是否描述同一件事。AiSOC 的做法大概率是把告警抽象成实体(主机、账号、IP、进程、云资源)与时序边,在同一时间窗内做图上的连通分量聚合——同一个 IP 在五分钟内触发了 EDR 和云审计的两条告警,就会被收敛为同一个 Case,而不是两条独立工单。这样做的价值在于:Agent 处理的是一个案件,并非一条告警,上下文和推理成本都会因此下降一个数量级。

第二层是Agent 编排与 ATT&CK 约束。纯粹的 ReAct 式 Agent 在安全场景容易发散,AiSOC 引入 MITRE ATT&CK 作为先验知识骨架:把观测到的行为先映射到候选 Technique,再让 Agent 沿着战术链(初始访问 → 执行 → 持久化 → 横向移动)去补证据、做验证。这本质上是给搜索空间加了一个强约束,既提升准确率,也让最终输出天然就是一份“攻击叙事”而非一堆零散结论。

第三层,也是最关键的一层,是可回放决策账本。它应该是 append-only 的结构,每步记录输入的上下文快照、调用的工具与参数、模型原始输出,并用哈希链把相邻记录串起来以防篡改。所谓“重放”,意味着给定同一份上下文快照与同一套工具返回,可以完整复现当时的推理路径。这正是安全审计真正需要的东西:事后复盘攻击链时,能看清“机器当时看到了什么、忽略了什么”。这也解释了它为什么强调无需 API Key 即可运行——本地模型或规则回退保证在 air-gapped 环境和演示场景下整条链路能够闭环,账本逻辑与模型供应商完全解耦。

功能亮点与差异

最明显的差异化是审计优先的设计取向。市面上的 AI SOC 大多在拼“检测准确率”和“自动化处置率”,AiSOC 拼的是“每一个自动决策是否可举证”。对受监管行业来说,这条价值远高于几个百分点的准确率。

其次是MCP Server 这一手。把 SOC 能力暴露成 MCP 工具后,Claude、Cursor、Continue 这类客户端可以直接充当分析师的工作台——你可以在编辑器里问“昨天那台跳板机的告警到底怎么回事”,Agent 去查案、拉证据、给结论,而不是切到另一个笨重的 Web 控制台。这是很聪明的定位:不跟 SIEM 抢界面,而是把自己做成安全数据的“能力层”。

第三是自托管 + MIT 许可。安全数据不出内网,这一点在采购环节几乎是硬性门槛。

应用场景与落地建议

适合的场景很明确:中小型安全团队、云原生环境的告警降噪、以及作为大型 SOC 的二级研判辅助。尤其适合已经有 SIEM 但缺人手的团队——把它挂在告警管道下游做收敛和初筛,收益最直接。

落地时有几点必须注意。一是权限只读。Agent 的工具调用应严格限制在查询类操作上,处置动作(隔离主机、禁用账号)必须保留人工确认门禁,不要让模型幻觉直接变成生产事故。二是账本存储要单独规划,哈希链加上完整上下文快照,体积增长会很快,需要明确保留周期以满足合规要求。三是先跑影子模式:让它只输出研判建议,与人工结论做对比,积累了足够的基线数据再放开自动关闭。四是融合规则(时间窗、实体权重)需要按自己的资产拓扑调优,默认参数大概率不适配你的环境噪声特征。

综合评价

优点:抓住了 AI 安全运营里最容易被忽视却最致命的可解释性/可复现性问题,决策账本的设计思路正确且稀缺;ATT&CK 作为推理骨架是务实的工程选择;MCP 集成让它天然嵌入开发者工作流;自托管 + MIT 大幅降低了试用门槛。

不足:项目仍处于早期,融合算法与 Agent 编排的内部细节在文档层面披露有限,规模化(万级 EPS)下的表现缺乏公开验证;无 API Key 模式下只能用本地模型或规则回退,研判质量与云端大模型存在明显差距,容易被误当成“开箱即用的成品”;此外,安全领域的 LLM 幻觉问题不会因为账本而消失——账本解决的是“可追责”,不是“更准确”。

一句话总结:它更像一套“AI 研判的取证基础设施”,而非一个检测引擎。如果你的痛点是“AI 说不清为什么”,它值得认真看;如果你指望它替你把误报率砍掉一半,那还得再等等。

关于

GitHub 原始描述(英文)

Open-source AI Security Operations Center: alert fusion, LLM-agent triage, MITRE ATT&CK investigation, and a replayable decision ledger for every agent step. Self-hostable, runs with no API keys, MIT licensed. Ships an MCP server for Claude, Cursor and Continue.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

语言占比

CSS
Dockerfile
Go
Go Template
HCL
HTML
JavaScript
MDX
Makefile
PLpgSQL
PowerShell
Python
Shell
Smarty
TypeScript

Release

README

AiSOC

AiSOC

An open-source, self-hostable AI Security Operations Center. It ingests your security telemetry, detects and correlates threats, investigates them with AI agents whose reasoning is fully auditable, and proposes responses a human approves.

License: MIT Version CI CodeQL OpenSSF Scorecard Technical Guide

Technical Guide (PDF) · Docs · Architecture · What actually works · Discussions


What AiSOC does

Telemetry arrives from your security tools. AiSOC normalizes it, runs the 2966 executable rules of its 7407-rule library, groups what fires into incidents, investigates each one with an AI agent whose every prompt and tool call is recorded, and proposes an action. New threat intelligence re-sweeps the history you already collected, and a human approves before anything reaches a vendor.

What it looks like running

AiSOC on one host: make up brings the stack up and prints the sign-in address, the console shows real CISA KEV rows, a pushed event becomes an alert, and the cost dashboard reports the tokens triage spent

Watch the full three minutes — install to AI verdict on one server against the published images, terminal waits shortened and the recording saying so on screen. The stills below are from a v20.1.0 run under the same rules — the recording is older than they are. (step by step · what is real)

Alerts queue AI triage verdict in the Investigation Rail
Alerts — each attributed to the connector that fed it. Automated triage — the bundled local model’s verdict, confidence and rationale, verbatim.
Threat intelligence page showing CISA KEV entries SOC operations dashboard with honest empty states
Threat intelligence — the real CISA KEV catalog, minutes after boot, with no API key. SOC operations — with nothing connected yet, and it says so rather than showing a placeholder.

Quick start

git clone https://github.com/beenuar/AiSOC && cd AiSOC
make up

On Windows, or on a machine with nothing installed yet, one line does the prerequisites too: iwr -useb https://raw.githubusercontent.com/beenuar/AiSOC/main/install.ps1 | iex (curl -fsSL https://raw.githubusercontent.com/beenuar/AiSOC/main/install.sh | bash on Linux and macOS). Without Docker at all, pip install aisoc-sandbox && aisoc-sandbox demo walks one alert through the agent funnel offline in under 30 seconds. Without your own machine, open the repo in GitHub Codespaces and run make up in its terminal. All four end at the same console; only the first three install anything.

The Technical Guide covers this in depth: server sizing, where the model runs, every failure mode with its cause and fix, the REST API, MCP, and every console surface.

Needs Docker Compose v2 with 8 GB memory and 20 GB free disk in the Docker VM, plus python3 (3.9+) and bash; make doctor checks all of it and Installation says what each number was measured against. The first run downloads a ~2 GB model into a volume only make clean clears.

make up also creates .env and generates the fifteen secrets in it — the credential vault, the session signing key, five service-to-service credentials and four datastore passwords — then creates an administrator and prints its password, generated on your machine, shown once and stored nowhere. Lost it? make bootstrap ARGS=--reset-password mints another.

A port already in use does not stop the install. AiSOC publishes on a free one, names what held the old one, and moves the console address with it: 64 seconds to a signed-in console on a bare clone with 5432 and 11434 both taken.

Then prove it works. make smoke posts one real event to the ingest API and follows it through Kafka, detection, correlation and Postgres, then reads the alert back out of the public API. Every stage reports PASS or FAIL:

$ make smoke
[PASS] raw telemetry accepted by ingest
[PASS] event traversed the spine and became an alert
PASS: 10/10 stages

Sign in at the address make up printed. A tenant with nothing connected lands on a setup wizard rather than an all-zero dashboard, and its state is read from your own data so it stays right if you connect a source through the API. The spec is docs/openapi.yaml — interactive docs are off in this production-class stack. Stuck? make doctor, which on a host where you have not run make up yet says exactly that.

Press Load sample data in the wizard. Five scenarios take the same ingest path a real connector uses — not inserted rows — so watching them become alerts means watching the pipeline work. They span low to critical on purpose, because a first run where everything is a crisis teaches you nothing about how triage separates signal from routine. They are attributed to AiSOC in the source column, refuse to load into a tenant that already has real alerts, and do not mark setup complete. (what each step proves) For the larger fixed corpus used by demos and evals, make demo loads a synthetic dataset — the pipeline shape, never a benchmark, a customer or an incident. Every row is is_synthetic = true and labelled in the console.

Connect real data

Push, with a credential from make ingest-token (the tenant comes from it, not a header):

curl -X POST http://localhost:8081/v1/ingest/batch \
  -H 'Content-Type: application/json' -H "Authorization: Bearer $AISOC_INGEST_TOKEN" \
  -d '{"connector_id":"edr-1","connector_type":"crowdstrike","events":[{"severity":"high",
       "title":"Encoded PowerShell from Office","host":"WIN-FIN-01"}]}'

Or pull, by configuring one of 91 click-and-connect data connectors in Settings → Connectors — Splunk, Sentinel, Elastic, CrowdStrike, Okta, AWS and Kubernetes audit among those with vendor-specific normalization and setup docs (coverage). Without a vendor profile a connector still ingests through a generic mapping that resolves host, user and source IP.

A real cloud estate does not hand you its logs over a REST call. Four collectors read the surfaces one actually emits to: a CloudTrail organisation trail on S3 notified over SQS (management events, data events and VPC flow logs), a GCP Pub/Sub subscription on a Cloud Logging sink, an Azure Event Hubs capture, and a syslog/CEF listener. Each keeps a resumable cursor and a bounded per-poll budget, so a backlog applies backpressure instead of flooding ingest.

Bringing existing detections? packages/aisoc-migrate translates Splunk SPL, Sentinel KQL and Elastic EQL and refuses rather than approximating what it cannot carry, because an almost-right rule is harder to find than a missing one: of the 2,005 Splunk rules bundled here 1,734 translate and 1,711 of those are partial (what that means).

How it works

Ingest normalizes to a common shape and stamps an activity projection on every event — actor, action, resource, location, outcome, with actor.kind read from each vendor’s own documented field rather than inferred — then Kafka carries it. Then fusion runs 2966 executable detection rules, of 7407 on disk, plus 76 sliding-window rules (73 count across events; 3 match an ordered sequence), applies your tenant’s own tuning on top — the disables, floors and suppressions the console writes, so a rule you turned off actually stops firing — and decides what becomes an alert. Correlation groups related alerts, an agent investigates and writes its reasoning to the Investigation Ledger, and a playbook may start from the result. Separately, new threat intelligence sweeps the lake for sightings you already collected, and a hypothesis becomes a hunt without anyone writing a query — the model fills a closed schema and every value is bound as a parameter, so it cannot express a query at all.

A playbook triggered by an alert previews before it acts. Three switches must agree — the deployment, the tenant, the playbook — and every default is off; anything less runs in preview with its plan attached to the alert. An approval step is a durable pause: the run suspends to Postgres, survives a restart, resumes after the approval, and expires with a recorded outcome rather than hanging.

Executable is earned, not declared. A rule joins the compiled ruleset only after a vendor-shaped event is replayed through the real connector and engine and that rule is watched to fire — never inferred from a directory or an enabled: flag. The proof can fail: --prove-gate reverts the Windows connector and requires all 1,687 Windows rules to go silent. It means reachable, not that it detects an attack. Two rules still cannot fire — down from 119, because a rule that could not fire stopped being counted as executable — and both are waiting on a behavioural baseline. The ratchet only moves down. (why 1,362 were refused)

Every answer carries its receipts. The copilot cites each checkable claim to the ledger entry behind it and labels the rest uncited rather than dropping them, and any investigation exports as a signed evidence bundle — byte-identical, prompts as digests, OCSF 1.9.0. (how)

Where state lives. Twenty service trees (14 Python, 4 Go, 2 TypeScript) behind the Next.js console. Kafka is the spine; Postgres holds the alerts, cases and the tamper-evident audit chain; Redis and Qdrant are in CORE too, and full adds ClickHouse (the event lake), Neo4j (the entity graph) and OpenSearch (full-text search).

docs/architecture/README.md walks that path one step at a time — eleven steps, five diagrams, every box linking to the code — and mirrors to the docs portal.

Deployment profiles

Profile Command Services RAM What you get
core make up 16 ~8 GB The full alerting pipeline: ingest → detect → correlate → alert → triage → console, plus the LLM gateway, a local model, the CISA KEV threat feed, and the connector and response services the agent’s vendor tools reach
full make up-full 22 ~12 GB Core plus event lake, entity graph, full-text search, enrichment
demo make up && make demo 16 ~8 GB Core plus labelled synthetic data

CORE is the smallest deployment that takes a real event and produces a real alert, and it needs no credentials to do either.

The model ships with the gateway. Ollama runs a pinned ~2 GB llama3.2:3b-instruct-q4_K_M sized for CPU-only inference, so make up produces real triage verdicts with real token counts in the Investigation Ledger — not a stub. It is not a frontier model: over 50 alerts it gave triage usable output 44 times before the reply was constrained to JSON and 50 after (method), and the rail labels which path answered. Run it faster with make up-gpu, make up-host-llm, or your own provider from the console (all four). No hosted provider has ever been exercised here — there is no funded key, so per-model rows read not measured rather than zero. (ADR-0006)

One real external feed ships too. services/threatintel polls the CISA Known Exploited Vulnerabilities catalog — public, no API key — into the console’s Threat Intelligence page: the one thing in a fresh install that is neither synthetic nor yours.

Evaluation, reflex and replay

The published numbers carry their own provenance. (methodology · real vs synthetic data)

  • Every verdict scorecard names the model that actually served it — gateway-attested or self-reported, with an explicit provenance status. A run with missing attribution, zero real calls or a deterministic fallback cannot be advertised as a named model’s performance, and a measurement that cannot be bound to an attributed call cannot authorize closures.
  • Denominators are published, and the uncomfortable direction wins. Full-cohort recall keeps abstentions and failures in the malicious denominator; closure claims ship with their contamination rate; alert reduction has three labelled figures (75.3% legacy grouping, 33.3% production key, 24.5% on a detection-shaped cohort after a missing identifier was fixed to narrow the group instead of widening it). Unmeasured reads not measured, never 0.
  • The reflex path is observable — nine named stages from queue delay to verification, and a decision contract carrying supporting evidence, contradictory evidence, missing prerequisites and the escalation reason.
  • Replay is time-frozen; re-hunting is labelled. Historical replay enforces evidence cutoffs in the retrieval queries (never by prompt), discloses the model-knowledge limit, and cannot execute real actions — the mutation boundary is the write adapter. Applying new intelligence to old telemetry is a distinct, rehearsable mode, and its discoveries are never counted as predictions at the original event time.
  • Model suitability is per task. The matrix grades each configured model on the same locked evidence against a deterministic baseline floor (balanced accuracy exactly 0.250); unfunded rows read not measured, with one-command reproduction against any local OpenAI-compatible endpoint.

AI agents

Agents triage alerts and investigate incidents. What they can and cannot do:

  • They read the alert, its correlated siblings, entity context, and prior verdicts for the same signature.
  • They call typed tools — lake queries, graph traversals, enrichment lookups. The model picks the tool and passes arguments; it never writes SQL.
  • Everything is logged to the Investigation Ledger — prompts, tool calls, citations, verdict, token cost — and exports as a signed bundle.
  • Grounding is checked. A verdict citing an indicator the evidence never contained is demoted to human review rather than auto-closed.
  • A prompt is validated before it is sent. Raw logs, OCSF payloads and secret-shaped values are refused, not redacted after the fact.
  • No vendor is touched without a human, unless a tenant has explicitly granted autonomy for that verb. Every response step is graded against its own capability contract at dispatch, so approving a playbook never authorises whatever its steps happen to contain, and an approver must hold the required permission tier and must not be the person who requested the action.

Project maturity

Stable is defined, and a gate enforces it. It was ungated prose until three rows were found describing coverage that did not exist. A row is Stable only with a check that runs on every pull request with no path filter, drives the real production path against real infrastructure, and has a negative control proven by breaking the thing and watching it go red. (the bar)

Capability Status Tested Production ready
Ingest → detect → correlate → alert Stable E2E + unit Yes
Detection engine (2966 executable rules) of 7407 Stable Replay proof Yes
Alert correlation into incidents Stable Unit Yes
REST API + web console Stable Unit + integration Yes
AI triage + Investigation Ledger Stable Live Postgres ledger + a PR-gated local-model agent run. No hosted provider has been exercised Yes, copilot mode
Event lake + hunting (ClickHouse) Stable Live ClickHouse on the shipped DDL, with a negative control Yes, full profile
Retro-hunts when new intel arrives Stable Live ClickHouse + Kafka with the flag on, with a negative control Opt-in, full profile
68-hunt YAML library, compiled against tenant events in the lake Stable Live ClickHouse: scheduled hunts read tenant data and refuse to fall back to the fixture; all 114 field names the corpus filters on compile, via a lake column or the stored payload Yes, full profile
SCIM 2.0 provisioning Stable Live Postgres through the real app: PATCH in both providers’ dialects, group membership, deprovisioning proved by its consequences, with a negative control Yes
White-label branding Stable Live Postgres: the scheduled report and its covering email carry the organisation’s brand, with two negative controls Yes
Usage metering Stable Live ClickHouse on the shipped DDL, with a negative control that makes an unscoped meter fail Yes
Entity graph (Neo4j) Stable Live Neo4j against the production reader, with a negative control Yes, full profile
Governed response actions Stable Live socket: permits, refuses, never leaks a refusal, with a negative control Human-approved only
Alert-triggered playbooks, with a durable approval pause Stable Live Postgres: suspend, restart, resume, expiry, with a negative control Yes — three opt-ins deep, preview by default
Per-tenant detection tuning in the live engine Stable Live Postgres: tuning written changes what the engine fires, with a negative control Yes
Scheduled connectors Stable Live scheduler polls a stub vendor into ingest, with a negative control Yes
UEBA Stable Live Postgres: migrations, scoring, persistence, isolation, with a negative control Yes, full profile
Package distribution (npm/PyPI) Beta The five PyPI packages resolve at the tree’s versions, checked against the live registries in both directions with a self-test; the npm half has no registry state to verify pip install aisoc-sandbox (and the other four) works today; the three npm packages still need the first-upload NPM_TOKEN, an account action

What AiSOC is not

  • Not a drop-in SIEM replacement. It correlates and investigates; it does not replace long-term log retention and compliance search.
  • Not able to see telemetry you have not connected. There is no discovery.
  • Not autonomous by default. Response requires explicit policy authorization and a human approver.
  • Demo and sample incidents are not real incidents, and benchmark numbers are substrate self-consistency measures, not live agent accuracy — labelled as such wherever published.

Troubleshooting

make doctor checks host tools, memory, disk, every port and each datastore by querying it rather than asking whether its container is up, then prints the command to run next. A container killed by a full Docker VM is named as that, not as the service that happened to die. (the six most common failures)

Security

Secrets are generated per deployment and never committed; connector credentials are encrypted at rest. Services connect to Postgres as a DML-only role, so row-level security actually applies, and tenant isolation is enforced at the query layer in every store. RBAC gates every mutating route, ingest is authenticated, and the default install sends no prompt anywhere — the model runs beside it.

SAML and OIDC sign-in with per-connection tenant and group mapping, SCIM provisioning, and console MFA — TOTP with recovery codes, enforceable per tenant. Attribute conditions, time-boxed elevation and workload identities run inside the one permission path, where a condition can only narrow a permission and never grant one. (SSO · access governance)

A service with no credential refuses to serve rather than serving unauthenticated. The changelog records each fix; report via SECURITY.md.

Developing

make test        # unit tests for every service
make smoke       # the golden pipeline, against a running stack
make stats       # recount every figure this README publishes

Guides: add a connector · add a detection · plugin lifecycle. Every count above is recounted from the tree, and CI fails if this README disagrees.

Funding · Roadmap · Contributing · License

Development is funded and supported by Cyble, who pay for the engineering time behind AiSOC and release it under the MIT licence rather than keeping it. That buys no special treatment here — no Cyble-only features, no gated modules, no telemetry. (full credits)

ROADMAP.md · CONTRIBUTING.md · SECURITY.md · MIT

评论

暂无评论