# Yeti Platform: a graph store behind DFIR artifact lookups

> Yeti keeps observables, TTPs and campaigns in one ArangoDB graph and answers both directions of the artifact question for DFIR teams. The packaging leaves two version numbers, a moving git dependency and no documented install command.

**yeti-platform/yeti** — Your Everyday Threat Intelligence

- Repository: https://github.com/yeti-platform/yeti
- Website: https://yeti-platform.io/
- Stars: 2,041 · Forks: 324
- Language: Python
- License: Apache-2.0
- Published: 2026-10-14 · Updated: 2026-10-14 · Language: en
- Canonical page: https://hysenlabs.com/projects/yeti-platform-yeti

## Observables in bulk, threats in reverse

Yeti starts from two questions a responder cannot answer quickly by hand: where have I seen this artifact before, and how do I search for IOCs related to this threat, or to every threat, inside a timeline. The answer is a platform that keeps observables, TTPs and campaigns in one store and reads that store in both directions. Push in a hash, an IP or a domain and it returns a guess at the threat behind the indicator, plus hints on how to find it on a host. Start from a threat instead and it lists the TTPs, malware and related DFIR artifacts attached to it.

The audience is narrow. DFIR teams that keep their own intelligence, and CTI analysts who would rather add intelligence than hand-maintain machine-readable export files for downstream tools. The repository topics match that reading: dfir, enrichment, infosec, intelligence, threat-hunting, threat-sharing, threatintel.

## A graph store and a queue are mandatory dependencies

Underneath sits a graph database, an API server and a task queue, and none of the three are optional. python-arango>=8.1.2 ties Yeti to ArangoDB, fastapi>=0.115 and uvicorn>=0.34 serve the web API, and celery>=5.3.4 with redis>=5.0.0 carry background enrichment.

```toml
    "python-arango>=8.1.2",
    "fastapi>=0.115",
    "uvicorn>=0.34",
    "celery>=5.3.4",
    "redis>=5.0.0",
    "click>=8.1.7",
```

click>=8.1.7 is the usual companion to a command line entry point, and the repository keeps a yetictl/ directory beside core/, contrib/, extras/ and plugins/. Data flows both ways. Sources push technical and tactical intelligence in, the API answers queries for automation, and exports hand the same records to a SIEM or another DFIR platform in a format you define. That last point sets expectations, because the API is positioned as a backend for other tools rather than a console for an analyst.

## Yara, Sigma and DFIQ live in one Python process

One of Yeti's stated jobs is to be the backend for DFIR-related queries, and it names three rule formats by hand: Yara signatures, Sigma rules and DFIQ. The dependency list shows those handled inside the Python process instead of by calling out to a separate rule service.

```toml
    "yara-python>=4.5.2",
    "plyara>=2.2",
    "idstools>=0.6.5",
    "minijinja>=2.9.0",
    "chromadb>=1.5.7",
```

yara-python>=4.5.2 compiles Yara rules, plyara>=2.2 parses rule text, and idstools>=0.6.5 handles Sigma. minijinja>=2.9.0 sits beside them as a templating engine, which pairs with the promise about user-defined export formats.

chromadb>=1.5.7 is a runtime dependency rather than an optional plugin, so semantic matching over indicators belongs to a base install. Skip that feature and you still carry its storage footprint. This is a platform that assumes every deployment needs the same feature set.

## The README hands you a docs site, not an install command

Here is the honest gap. The README documents no install command, no pip invocation and no container run. It points at https://yeti-platform.io/docs for documentation and https://yeti-platform.io/guides for guides, and that is the entire path it offers.

What the repository does show is the shape of a deployment. uv.lock records a resolved dependency set, yeti.conf.sample is the sample configuration file, and a .python-version file sits at the root, so the interpreter is pinned somewhere the README never mentions.

```toml
requires-python = ">=3.11,<3.14"
```

The first real step is therefore not a command you can copy from here. It is reading the docs site, then provisioning the three services the dependency list calls for: an ArangoDB instance, a Redis instance and a Celery worker. Plan for those three before you plan the schema.

## Three declarations of the Python version, one hidden

requires-python in pyproject.toml sets the floor at 3.11 and the ceiling at 3.14, and a separate block pins the type checker to 3.13.

```toml
[tool.ty.environment]
python-version = "3.13"
```

A .python-version file at the repository root states the interpreter a third time, and its contents are not shown next to the packaging metadata. The distance between 3.11 and 3.13 is where the risk sits. The type checker validates one interpreter while the packaging metadata admits three, so version-specific typing errors can pass the typecheck job and appear only on an older supported host. Moving from 3.11 to 3.13 is a test event, not a metadata edit, and neither the ruff config nor the pylintrc at the root changes that.

## Version 0.1.0 in pyproject against 2.12.0 on GitHub

A close reading of the numbers turns up a contradiction worth settling before you plan an upgrade.

```toml
[project]
version = "0.1.0"
```

pyproject.toml declares version 0.1.0 in its project table, yet the builds that carry version numbers are 2.10.0, 2.11.0 and 2.12.0, with 2.10.0 and 2.11.0 both dated 2026-09-01 a little over four hours apart and 2.12.0 dated 2026-10-02. Two numbering schemes sit side by side, so a published tag does not tell you what the packaging metadata will report, and any version pin in your own automation has to choose one. The README does not explain which number a deployment installs.

The same file pins one dependency twice. artifacts appears unpinned in the runtime list, then returns in the plugins group as a git reference to the main branch of forensicartifacts/artifacts.

```toml
    "artifacts @ git+https://github.com/forensicartifacts/artifacts.git@main",
```

An install that includes plugins therefore tracks a moving commit rather than a fixed artifact version. The repository is not archived, its last push was on 2026-10-04, and Apache-2.0 lets you embed the result inside a closed product.

## Type checking stops at the core and yetictl boundary

Static checking stops at a boundary the packaging file states in plain text.

```toml
[tool.ty.src]
include = ["core", "yetictl"]
```

core and yetictl are fully enforced, while plugins/ is deferred to a follow-up, with a comment giving the reason: its third-party dependencies are not installed by the typecheck job, and it needs its own ratchet. The same comment block marks a phase 2 ratchet as complete, which makes the remaining gap a deliberate deferral rather than an oversight.

Two more details sit beside that decision. ruff>=0.15.0 and pylint>=2.16.1 both run over the tree, and ruff selects the isort rules, ignores E402 and F401, and excludes deprecated directories. Then there is parameterized>=0.9.0, which appears in the runtime dependency list while pytest, ruff and httpx sit in the dev group, so those two groups are not split along a line you could reconstruct from the file. Anyone auditing a runtime image has to assume extra packages ride along.

## Bring your own enrichers or keep your own pipeline

The alternative to adopting Yeti is to keep enrichment in scripts you already control and store observables where you already operate. The difference in approach is concrete, because the plugin list names exactly what Yeti would own for you.

```toml
plugins = [
    "pymisp>=2.4.176",
    "otxv2>=1.5.12",
    "shodan>=1.30.0",
    "timesketch-api-client>=20260312",
    "censys>=2.2.10",
    "pyopenssl>=23.3.0",
]
```

shodan>=1.30.0, censys>=2.2.10, otxv2>=1.5.12, ipwhois>=1.2.0, maclookup>=1.0.3 and pyopenssl>=23.3.0 cover host, address and certificate lookups, pymisp>=2.4.176 handles MISP exchange, pygithub>=2.3.0 reaches repository data, and timesketch-api-client>=20260312 reaches timeline data. A separate s3 group carries boto3>=1.35.22 for object storage.

Scripts plus a store you already run give you the same enrichment answers without three extra services in one deployment. You also give up the reverse lookup from a threat to its artifacts, the three rule formats and the export layer, which are the parts the README names as the reason for the project. The timesketch-api-client entry is the only visible implementation behind the timeline complaint in the project description.

## Conclusion

Yeti suits teams that already run a forensics function and want one store answering both directions of the artifact question, with Yara, Sigma and DFIQ handled in the same process. It suits teams that want a product with a documented install path badly, because the README sends you to a docs site instead. Before adopting, price the ArangoDB, Redis and Celery services the dependency list demands, then read the plugin boundary: plugins/ carries no type checking, and pyproject.toml still reports version 0.1.0 while 2.12.0 is the highest numbered build you can install.

## FAQ

### What is Yeti Platform and who is it built for?

It is a forensics intelligence platform and pipeline for DFIR teams, storing observables, TTPs and campaigns so that artifact questions can be asked in both directions. The README also frames the web API as a backend for an incident management platform or a malware sandbox rather than a standalone console.

### How do I install Yeti Platform?

The README gives no install command and points to https://yeti-platform.io/docs and https://yeti-platform.io/guides instead. The dependency list is the only concrete signal, and it points to an ArangoDB instance through python-arango, a Redis instance, and a Celery worker alongside the FastAPI service.

### What can Yeti Platform query?

Observables in bulk, the reverse direction from a threat to its TTPs, malware and related DFIR artifacts, plus Yara signatures, Sigma rules and DFIQ. Records can then leave in user-defined formats for ingestion by a SIEM or another DFIR platform.

### Which Python versions does Yeti Platform support?

pyproject.toml sets requires-python to >=3.11,<3.14, and the type checker is configured for python-version 3.13. The repository also carries a .python-version file at the root, whose contents are not shown alongside the packaging metadata.

### Is Yeti Platform still being worked on?

The repository is not archived and its last push was on 2026-10-04. Builds numbered 2.10.0 and 2.11.0 are dated 2026-09-01 and 2.12.0 is dated 2026-10-02, although pyproject.toml itself still declares version 0.1.0.

### Can I add my own data sources to Yeti Platform?

The README says you can incorporate your own data sources, analytics and logic. The plugins dependency group shows the expected shape with pymisp, shodan, censys, otxv2, ipwhois, maclookup, timesketch-api-client and pygithub, and a separate s3 group with boto3.

## Sources

- [License: Apache-2.0](https://github.com/yeti-platform/yeti/blob/main/LICENSE)
- [Project website](https://yeti-platform.io/)
- [README](https://github.com/yeti-platform/yeti/blob/main/README.md)
- [Releases](https://github.com/yeti-platform/yeti/releases)
- [yeti-platform/yeti on GitHub](https://github.com/yeti-platform/yeti)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yeti-platform-yeti
