We threw away our event schema and rebuilt on OCSF. It cost a quarter.
Why we replaced a perfectly functional internal schema with OCSF v1.3, what it cost, and the three things it bought that we did not anticipate.
Mohamed Nofal
Founder & CEO · 11 August 2026 · 4 min read
Our first event schema was fine. It had the fields our detections needed, it serialised efficiently, and every engineer on the team could recite it from memory. In early 2024 we deleted it and rebuilt the entire pipeline on OCSF v1.3.
That decision cost most of a quarter and it was the best engineering call we have made.
What was wrong with a schema that worked
Nothing, in isolation. The problem showed up at the boundaries.
Every customer conversation eventually reached the same place: how does this get into our SIEM? The honest answer was a mapping layer. We had one for Splunk, a different one for Elastic, and a half-finished one for a data lake. Each was a translation, each drifted from the source, and each was a place where a field could quietly stop being populated without anything failing.
The second problem was subtler. An internal schema is a private language, and a private language lets you be imprecise. We had a field called target that meant a file path in one class, a destination address in another and a process id in a third. Nobody was confused, because everybody had been there since the beginning. That is not a property you can ship.
What OCSF actually demanded
Not a rename. A restructure.
OCSF distinguishes the actor from the target with real rigour. In a process event, the actor is the parent and the target is the child — and once you have to say that out loud in a schema, you discover which of your detections were quietly ambiguous about which one they meant. We found four rules that had been matching on the wrong process for months. They still fired, because the parent and child were usually both interesting. They were wrong anyway.
It also forced us to be honest about classes we could not populate well. OCSF has classes for things a runtime sensor genuinely cannot see. The temptation was to emit them thinly and claim coverage. We wrote it into the repository instead:
Falak deliberately implements a SUBSET of OCSF — only the classes a Linux, K8s and cloud runtime sensor can actually produce with high fidelity. Adding a class here is a deliberate act: it requires a probe that can populate it and a ClickHouse projection that can store it.
Eleven classes, plus one documented extension. That is the whole list, and it is a shorter list than our marketing would prefer.
Three things we did not anticipate
The wire format became the storage format became the export format
Because field names mirror OCSF JSON attribute names exactly, protojson output is a valid OCSF document. There is no serialisation step between what the sensor emits, what ClickHouse stores, and what a customer exports. Removing two layers removed two places for a bug to live.
The export feature took an afternoon. It had been on the roadmap as a two-week project.
Detection engineering got faster
When the schema is the same as the documentation, a detection engineer writing a rule can check the field path against the spec rather than against tribal knowledge. New engineers became productive on content in days rather than weeks.
The unglamorous version: fewer rules shipped with a typo'd field path that silently matched nothing.
The extension became a design constraint we wanted
OCSF has no container lifecycle class. We needed one — the mount set on a container start is what makes escape detection possible.
The easy path was to bend Process Activity out of shape. Instead we registered a documented extension: namespace falak, extension uid 990, class_uid = 990001. Exactly one extension, written down, with a stated reason.
Having a formal cost to extending the schema meant we extended it once instead of eleven times. Every other Falak-specific fact — exec_from_memfd, path_class, crossed_pod_boundary — is an additive field inside a standard class, where it does not break anyone's parser.
What it cost
Roughly one quarter of engineering time across three people. Two weeks of that was the restructure; the rest was rewriting the detection corpus and re-backtesting every rule against replayed data.
We also broke the wire format for the customers on our early-access programme, which required a coordinated sensor and core upgrade. If we had done this six months later it would have been considerably more expensive, and eighteen months later it would probably not have happened at all.
Would we do it again
Yes, and earlier.
The general form of the lesson is: when a standard exists in your domain and it is good enough, adopting it early is cheap and adopting it late is expensive. The cost curve is not linear. It bends sharply the moment you have customers with data in your schema.
The specific form is: OCSF is good enough. It is not perfect — the finding classes carry some enterprise-SIEM assumptions that do not fit a runtime sensor cleanly — but it is thoughtfully designed, actively maintained, and its imperfections are documented rather than emergent.
If you are building anything that emits security events, start there. The quarter we spent is a quarter you do not have to.