Check out the Largest Integration Ecosystem in Cybersecurity and IT and request to be included. 

How to Map Your Product’s Data to OCSF: A Field Guide for Security Vendors

Most security vendors agree the Open Cybersecurity Schema Framework (OCSF) is a good idea. Far fewer have shipped it, and the standard itself is rarely what holds them back. The mapping work is. 

This guide takes one EDR alert and maps it to the OCSF Detection Finding class (2004), using schema version 1.9.0, in seven steps: 

  1. Pick the event class 
  1. Fill the required base fields 
  1. Map the detection details 
  1. Handle fields that don’t fit 
  1. Apply profiles 
  1. Validate the output 
  1. Plan for version changes 

None of the steps is hard on its own. The cost comes from repeating them for every product you integrate with, every time that product or OCSF changes. 

If you’re new to OCSF, start with our explainers, OCSF Explained: Why Cybersecurity Vendors Should Care About Integration Standards and How OCSF Transforms Cybersecurity Integrations. This guide assumes you know what OCSF is and want to see how mapping works in practice. Every class, object, and profile named below can be looked up in the OCSF schema browser. 

Why Mapping Is Where OCSF Adoption Stalls 

In conversations with Synqly customers, cybersecurity engineering leaders estimate that 30 to 40 percent of their integration effort goes to schema mapping and normalization rather than integration logic. That time is spent deciding which vendor field goes where, what to do with fields OCSF doesn’t define, and how to keep it all working when either side changes. 

Most of that effort lands after launch, as maintenance. We’ve written about what that maintenance costs vendors and why inconsistent data formats are one of the integration problems a unified API is built to solve. This guide shows where those hours actually go. 

The Alert We’ll Map 

Here’s a typical alert from a fictional EDR product, ExampleEDR. A suspicious PowerShell command ran on a Windows laptop, matched a detection rule, and the EDR killed the process. 

{
“alert_id”: “ALR-88213”,
“detected_at”: “2026-10-14T15:42:07Z”,
“rule_name”: “Encoded PowerShell Command”,
“rule_id”: “R-1042”,
“sev”: “high”,
“confidence”: 85,
“state”: “open”,
“action_taken”: “process_killed”,
“mitre”: [“T1059.001”],
“host”: {
“hostname”: “FIN-LT-0442”,
“ip”: “10.20.4.17”,
“os”: “Windows 11”,
“agent_id”: “a7f3-22c9”
},
“process”: {
“pid”: 6120,
“name”: “powershell.exe”,
“cmdline”: “powershell.exe -enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoA…”,
“sha256”: “9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08”,
“user”: “CORP\jsmith”
},
“tenant_ring”: “blue-3”,
“sensor_build”: “7.4.2”
}

Every EDR produces some version of this. Field names, value formats, and nesting differ from product to product, and the mapping has to absorb those differences. 

Step 1: Pick the Event Class 

Every OCSF event belongs to exactly one class, and the class decides which fields exist. Pick the wrong one and every later step fights you. 

Our alert is the output of an analytic: a rule evaluated process activity and decided it was suspicious. In OCSF, that’s a Detection Finding (class 2004, in the Findings category). OCSF’s guide to modeling alerts names EDRs, SIEMs, and UEBA tools as typical Detection Finding producers. 

Two classes are easy to confuse here: 

  • Process Activity (1007) records that a process ran. Use it for raw telemetry, not for the judgment that the process was bad. 
  • Detection Finding (2004) records the judgment. It has a lifecycle, with activity_id values of Create (1), Update (2), and Close (3), so you can track one alert from open to resolved. 

If your product sends both raw telemetry and alerts, you’ll map to both classes. Keep them separate. 

Step 2: Fill the Required Base Fields 

Every OCSF event needs the same base fields, whatever its class. They tell a consumer what kind of event this is, when it happened, and which schema version it follows. 

OCSF field Requirement Value for our alert Where it comes from 
category_uid Required 2 (Findings) Fixed by the class 
class_uid Required 2004 (Detection Finding) Fixed by the class 
activity_id Required 1 (Create) state: “open” on a new alert 
type_uid Required 200401 class_uid × 100 + activity_id 
time Required 1791992527000 detected_at, converted to epoch milliseconds 
severity_id Required 4 (High) sev: “high” 
metadata.product Required ExampleEDR, vendor ExampleCo Your product details 
metadata.version Required 1.9.0 The OCSF version you map to 
finding_info.uid Required ALR-88213 alert_id 

Three things trip teams up here: 

  • Enums are integers. OCSF stores severity_id: 4, not “high”, so your mapping needs a lookup table from your values to OCSF’s. You can also send the caption (severity: “High”) for readability. 
  • Time is epoch milliseconds. ISO strings, epoch seconds, and local times all need converting. 
  • metadata.version is a promise. It tells consumers which fields to expect, so it has to match the version you actually validate against. See the metadata object for the full list of fields. 

Step 3: Map the Detection Details 

The base fields say an alert exists. The detection details explain it: what fired, why, and what it touched. 

finding_info describes the finding itself. Only uid is required, but title and analytic are recommended, and consumers rely on both. 

  • title ← rule_name (“Encoded PowerShell Command”) 
  • analytic.name and analytic.uid ← rule_name and rule_id, with analytic.type_id 1 (Rule) 
  • attacks ← mitre. OCSF wants the tactic, technique, and sub-technique with names, not only an ID: sub-technique T1059.001 (PowerShell) under technique T1059 (Command and Scripting Interpreter) and tactic TA0002 (Execution). If your product stores only IDs, your mapping has to look up the names. 

evidences holds the artifacts that triggered the detection. OCSF requires at least one evidence field, such as process, device, file, or user. For our alert: 

  • evidences[0].process ← process.pid, process.name, and process.cmdline (renamed to cmd_line) 
  • The SHA-256 hash moves into process.file.hashes, with algorithm_id: 3 (SHA-256) in place of a key name 
  • process.user ← CORP\jsmith, split into name: “jsmith” and domain: “CORP” 
  • device ← the host block. hostname and ip carry over, and the OS becomes an object with os.type_id: 100 (Windows) 
  • device.agent_list[0].uid ← agent_id, with type_id: 1 (Endpoint Detection and Response). The agent object exists for exactly this kind of sensor ID. 

Status, confidence, and alerting: 

  • status_id ← 1 (New), from state: “open” 
  • confidence_score ← 85, kept as is. confidence_id ← 3 (High), using a threshold you define and document. 
  • is_alert ← true. The OCSF docs advise setting it on Create and leaving it false or empty on Update and Close. 

Splitting CORP\jsmith and turning 85 into “High” are judgment calls. Your team makes each one, documents it, and defends it when a customer asks why their SIEM shows something different. 

Step 4: Handle Fields That Don’t Fit 

Every product has data OCSF doesn’t define. Before you set any of it aside, check whether OCSF already has a home for it. 

In our alert, sensor_build looks product-specific, but it’s the version of the EDR sensor, and the agent object has a version attribute for that. It goes into device.agent_list[0].version, next to the agent ID from Step 3. 

That leaves tenant_ring, an internal deployment label with no OCSF equivalent. You have three options, from least to most effort. 

Option When to use it Tradeoff 
Drop the field It has no value to customers downstream Gone for good, so make sure nobody needs it 
Put it in unmapped It matters to some customers, but only in your context Consumers can see it but can’t query it in a standard way 
Build an extension It matters, recurs across events, and needs proper typing You define and maintain it, and consumers need your extension to read it 

For most teams, unmapped is the right default. It’s an optional base field that keeps your data without breaking compatibility: 

“unmapped”: {
“tenant_ring”: “blue-3”
}

Extensions are the heavier option. An extension adds attributes, objects, or classes to the core schema under your own namespace, and each event lists the extensions it uses in metadata.extensions. OCSF publishes official extensions for Linux, Windows, and macOS that show how this works. Build one only when a field recurs across many events and customers need to query it. 

Teams get this wrong in both directions. Mapping a field to a core attribute because it looks close enough poisons detections downstream. Parking a field in unmapped when OCSF already has a real home for it, as sensor_build almost was, hides data customers could have queried. Check the schema browser first. If you’re still unsure, unmapped is the safer choice. 

Step 5: Apply Profiles 

Profiles are reusable sets of fields you add to a class when they apply. The same context (a host, a cloud account, a security control’s decision) shows up across many classes, and profiles let you describe it the same way each time. 

Our alert has one field left: action_taken: “process_killed”. The EDR didn’t just detect something. It acted. That’s what the Security Control profile is for. The OCSF docs say an EDR-like enforcement point can apply it to a Detection Finding to convey both the detection and the outcome. 

  • action_id ← 2 (Denied). The profile’s action values are Unknown, Allowed, Denied, Observed, Modified, and Other. 
  • disposition_id ← 2 (Blocked), sent with the caption disposition: “Blocked”. Blocked is the closest fit for a killed process, and like the confidence threshold, it’s a choice worth writing down. 
  • attacks, policy, and malware are also available on this profile if your product reports them. 

The Host profile is the other common fit for endpoint products, since it carries the device and actor context. 

List every profile you apply in metadata.profiles, for example [“security_control”, “host”]. Consumers use that list to know which extra fields to expect. 

Step 6: Validate the Output 

A mapping that has never been validated is a guess. Validation catches missing required fields, wrong types, and invalid enum values before a customer’s SIEM does. 

Tool What it checks Notes 
OCSF schema server, POST /api/v2/validate Event payloads against a schema version The reference behavior other validators copy 
OCSF Toolkit (Go) Events against a compiled schema, with a –validate CLI flag Fits into a build pipeline 
Ocsf.Validation (.NET) Events against v1.9.0 Community project, not official OCSF 
ocsf-validator (Python) Schema definitions, not events Use it if you build an extension 

Two habits make validation stick: 

  1. Run it in CI. Keep a set of real sample events for each integration, and fail the build when any of them stops validating. 
  1. Treat warnings as work. A missing recommended field passes validation, but title, analytic, and evidences are what make an alert useful downstream. 

Step 7: Plan for Version Changes 

Your mapping is never finished. OCSF has shipped a minor release every three to five months, and each one is listed on the OCSF schema releases page: 

Version Released Change that can affect a mapping 
1.9.0 Aug 3, 2026 comment on findings deprecated in favor of notes; new User Management and Role Management classes 
1.8.0 Mar 16, 2026 New ai_operation profile for AI workloads 
1.7.0 Nov 14, 2025 New Peripheral Activity class 
1.6.0 Aug 1, 2025 group and credential_uid deprecated 
1.5.0 Apr 28, 2025 New Application Security Posture Finding class 

Minor releases aim for backward compatibility, and deprecated fields keep working for a while. The risk is drift: your mapping stays valid while the schema moves on, and your events fall behind what customers expect. 

A workable policy: 

  • Pin one version. Set metadata.version to the version you validate against, and change both together. 
  • Review every release. Check the release notes for deprecations in the classes you emit. 
  • Watch both sides. Your own product and every vendor you integrate with also change their formats. Any change on either side can mean a mapping update. 

The Finished OCSF Event 

Here’s the same alert after all seven steps:

{
“category_uid”: 2,
“class_uid”: 2004,
“activity_id”: 1,
“type_uid”: 200401,
“time”: 1791992527000,
“severity_id”: 4,
“severity”: “High”,
“status_id”: 1,
“is_alert”: true,
“confidence_id”: 3,
“confidence_score”: 85,
“action_id”: 2,
“disposition_id”: 2,
“disposition”: “Blocked”,
“metadata”: {
“version”: “1.9.0”,
“product”: { “name”: “ExampleEDR”, “vendor_name”: “ExampleCo” },
“profiles”: [“security_control”, “host”]
},
“finding_info”: {
“uid”: “ALR-88213”,
“title”: “Encoded PowerShell Command”,
“analytic”: { “uid”: “R-1042”, “name”: “Encoded PowerShell Command”, “type_id”: 1 },
“attacks”: [{
“tactic”: { “uid”: “TA0002”, “name”: “Execution” },
“technique”: { “uid”: “T1059”, “name”: “Command and Scripting Interpreter” },
“sub_technique”: { “uid”: “T1059.001”, “name”: “PowerShell” }
}]
},
“device”: {
“hostname”: “FIN-LT-0442”,
“ip”: “10.20.4.17”,
“os”: { “name”: “Windows 11”, “type_id”: 100 },
“agent_list”: [{ “uid”: “a7f3-22c9”, “type_id”: 1, “version”: “7.4.2” }]
},
“evidences”: [{
“process”: {
“pid”: 6120,
“name”: “powershell.exe”,
“cmd_line”: “powershell.exe -enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoA…”,
“file”: {
“name”: “powershell.exe”,
“hashes”: [{ “algorithm_id”: 3, “value”:
“9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08” }]
},
“user”: { “name”: “jsmith”, “domain”: “CORP” }
}
}],
“unmapped”: {
“tenant_ring”: “blue-3”
}
}

One alert from one product took more than 20 mapping decisions, from enum lookups to splitting a username to choosing between unmapped and an extension. Each one has to be written, tested, documented, and maintained. 

Now Multiply by Every Integration 

Everything above covers one alert type from one product. A real integration program multiplies it: 

  • Every partner product formats alerts differently, so each one needs its own mapping. 
  • Every event type (alerts, process events, vulnerabilities, inventory) maps to a different class. 
  • Every release, from OCSF or from any vendor you connect to, can break a mapping you already shipped. 

That’s where the 30 to 40 percent of integration effort goes: hundreds of small decisions, none of which stay decided. 

How Synqly Removes the Mapping Work 

The Synqly unified API uses OCSF as its foundational data model. Instead of writing and maintaining a mapping for each product you connect to, you integrate once with Synqly, and Synqly maintains the translation for every connector in its integration catalog. For an EDR alert like the one in this guide, that’s the Endpoint Security connector. 

The seven steps still happen. Your team just stops being the one doing them for every connector, every release, forever. That’s how Halcyon AI skipped 12 months of Microsoft Sentinel integration work. 

Two capabilities matter most for teams that have already made some of the decisions in this guide their own. 

You can change the built-in mappings 

Synqly ships a default OCSF mapping for every connector, and it applies automatically when you haven’t defined one. The defaults won’t match every call your team would make. You might threshold confidence differently, want tenant_ring in a field customers can query, or need a username kept whole instead of split. 

Adaptive Data Mapping lets you change the mapping yourself, without writing code or waiting on a Synqly release. You can: 

  • Add custom fields to an existing mapping by defining the field path and data type 
  • Set a mapping at the integration point, which acts as a template for every integration created under it, scoped to specific providers or to all of them 
  • Override that template on a single integration, per operation, when one customer or one vendor needs something different 
  • Chain your own transform with Synqly’s default, or pass provider data through untouched 

One detail matters for change control: updating a template doesn’t rewrite the integrations that already exist under it, so a change aimed at new customers won’t quietly alter what existing customers receive. The Adaptive Data Mapping configuration guide covers the syntax. 

You don’t have to rebuild your data model around OCSF 

Adopting OCSF doesn’t mean replacing your internal schema. Synqly maps in both directions, with OCSF in the middle: 

  • When you read data, such as querying events from a customer’s SIEM, Synqly converts the vendor’s native format to OCSF. If you register a transform, it then converts OCSF to your own format. 
  • When you write data, such as sending your alerts into that SIEM, Synqly takes your format, converts it to OCSF, and then converts it to the vendor’s native format. 

You map your schema to OCSF once. Synqly handles the hop between OCSF and each vendor’s native schema, for every connector and every time a vendor changes its format. Your internal model stays as it is, and your customers still get data in the format their tools expect. 

Evaluating OCSF for your product? Talk to the Synqly team about your integration roadmap and mapping options. 

Frequently Asked Questions About OCSF Mapping 

How do I map my logs or findings to OCSF? 

Pick the OCSF event class that matches your data, fill the required base fields, map your product’s details into that class’s objects, put leftover fields in unmapped or an extension, apply any profiles that fit, validate the result against a schema version, and review your mapping with each OCSF release.

Which OCSF class should an EDR or SIEM alert use? 

Detection Finding (class 2004). Use it for the output of an analytic, such as a rule match. Raw activity, such as a process starting, belongs in an activity class like Process Activity (1007). 

What do I do with fields OCSF does not define? 

First confirm OCSF really doesn’t define them, since some product-specific fields, such as a sensor version, have a home in the core schema. For the rest, use the unmapped object, which keeps the data without breaking compatibility. Build an extension only when a field recurs across many events and customers need to query it. 

What is the difference between an OCSF profile and an extension? 

A profile is an official, reusable set of fields you add to a class when it applies, such as Security Control or Host. An extension is your own addition to the schema, for attributes or classes the core schema doesn’t cover. 

How do I validate OCSF events? 

Use the OCSF schema server’s validation endpoint (POST /api/v2/validate) or a tool that mirrors it, such as OCSF Toolkit for Go. Run it in CI against real sample events. 

How often does OCSF change? 

OCSF has shipped a minor release every three to five months. The latest is v1.9.0, released August 3, 2026. Minor releases aim for backward compatibility but do deprecate fields. 

Sources 

https://www.synqly.com

Steve brings a proven track record of turning complex technical challenges into scalable, user-centric products. Drawing on his experience leading engineering organizations at Styra, Illumio, and Juniper Networks, Steve shares his insights on product innovation, cloud-native security, and modernizing cybersecurity solutions. He is dedicated to building high-performing teams to fix the broken state of security integrations.


  • Platform
  • Integrations
  • Resources
  • About
  • Blog