Security teams collect telemetry from dozens of products that each describe the same logon, API call or process start in a different shape, and every detection rule ends up written once per source. The Open Cybersecurity Schema Framework (OCSF) is an open, vendor-neutral schema that gives those events one structure: a fixed set of categories, event classes, objects and attributes with numeric identifiers. This guide explains how the schema is built, which decisions matter when you map a source to it, how to store OCSF data in a lake, and how to write detections that survive a change of vendor. It is written for detection engineers, data pipeline owners and SOC architects who are adopting OCSF or inheriting data that already uses it.
Key takeaways
- OCSF is a schema, not a product. It is an open project under the Linux Foundation since November 2024, founded in 2022, and its core definitions live as JSON files in the public ocsf-schema repository.
- Four numbers identify every event. category_uid, class_uid, activity_id and type_uid (class_uid multiplied by 100 plus activity_id) let you filter and route events without parsing vendor strings.
- Mapping quality decides detection quality. The schema only helps if mappers populate the right class, the normalised enums and the actor and user objects consistently; a lazy mapping that dumps fields into unmapped gives you OCSF in name only.
- Pin the version you write and read. metadata.version is required for a reason: consumers such as Amazon Security Lake accept specific versions for custom sources, and attributes change between minor releases.
- Identity events gain the most. The IAM category, the actor object and user.type_id (User, Admin, System, Service) let you write one rule for service account misuse across cloud, SaaS and directory sources.
What OCSF is and where it came from
OCSF describes itself as an open standard for cybersecurity event logging and data normalisation, made up of categories, event classes, data types and an attribute dictionary. It is format agnostic: the normative form is JSON, but the same structure is stored as Parquet, Avro or rows in a SIEM. The Linux Foundation announced on 19 November 2024 that OCSF had joined it as a project; the project was founded in 2022 with support from AWS, Cisco, IBM and Splunk, the initial schema came from work contributed by Broadcom (Symantec), and the announcement cited more than 900 contributors from over 200 organisations.
The schema is versioned with Semantic Versioning. The repository changelog lists v1.0.0, then v1.1.0 (January 2024), v1.2.0 (April 2024), v1.3.0 (August 2024), v1.4.0 (January 2025), v1.5.0 (April 2025), v1.6.0 (August 2025), v1.7.0 (November 2025), v1.8.0 (March 2026) and v1.9.0 (3 August 2026); the main branch was at 1.10.0-dev when this guide was checked on 27 October 2026. Within major version 1, minor releases add classes, attributes, objects and profiles while staying backwards compatible; patch releases are reserved for non-breaking corrections such as captions.
If you are deciding where normalisation should happen in your pipeline (at the edge, in a pipeline tool or at query time), read the Security Data Pipeline Guide first. This guide assumes you have chosen OCSF as the target and focuses on the schema itself.
How the schema is organised
Every OCSF event is an instance of one event class. Classes inherit from a Base Event and are grouped into categories. The building blocks are:
- Categories: high-level groupings with a numeric uid. Current core categories are System Activity (1), Findings (2), Identity and Access Management (3), Network Activity (4), Discovery (5), Application Activity (6), Remediation (7) and Unmanned Systems (8).
- Event classes: the specific event types. A class_uid is the category uid multiplied by 1,000 plus the class number, so Authentication is 3002 and Detection Finding is 2004.
- Activities: each class defines its own activity_id enum. Authentication defines 1 Logon, 2 Logoff, 3 Authentication Ticket, 4 Service Ticket Request, 5 Service Ticket Renew, 6 Preauth and 7 Account Switch. Every class also accepts 0 Unknown and 99 Other.
- Objects: reusable structures such as user, actor, device, endpoint, process, file, session and metadata.
- Dictionary and data types: one attribute dictionary defines each attribute name once, and scalar types such as ip_t, timestamp_t and email_t carry validation rules.
- Profiles: optional overlays that add a set of attributes across classes. Examples in the core schema include cloud, host, container, security_control, datetime, incident, data_classification and ai_operation.
- Extensions: a mechanism to add attributes, objects, classes, categories or profiles without changing the core. The repository ships linux, macos and windows platform extensions.
Event classes you will map most often
| Class (class_uid) | Category | Typical sources | Fields detections depend on |
|---|---|---|---|
| Authentication (3002) | IAM | Directory sign-in logs, IdP logs, Windows logon events, VPN | user, actor, is_mfa, logon_type_id, auth_protocol_id, src_endpoint, status_id |
| Account Change (3001) | IAM | Directory and cloud IAM audit logs | activity_id (Create, Password Reset, Attach Policy, MFA Factor Disable), user, actor |
| API Activity (6003) | Application | Cloud control plane audit logs, SaaS admin APIs, Kubernetes audit | actor (user, session, invoked_by), api.operation, resources, src_endpoint |
| Process Activity (1007) | System | EDR, Sysmon, auditd | process, process.parent_process, actor, device |
| Network Activity (4001), HTTP Activity (4002), DNS Activity (4003) | Network | Flow logs, proxies, WAF, resolvers | src_endpoint, dst_endpoint, connection_info, query, http_request |
| Detection Finding (2004) | Findings | EDR alerts, SIEM rule hits, cloud threat detection | finding_info, attacks, severity_id, is_alert, evidences |
| Vulnerability Finding (2002), Compliance Finding (2003) | Findings | Scanners, posture management | vulnerabilities, compliance, resources |
The Base Event and the fields every mapping must get right
The Base Event carries the attributes that every class inherits. Required attributes are activity_id, category_uid, class_uid, metadata, severity_id, time and type_uid. Recommended attributes include message, observables, status, status_id, status_code, status_detail and timezone_offset. Getting these right is what makes cross-source queries possible.
- type_uid: the schema states that producers and mappers must compute it as class_uid multiplied by 100 plus activity_id, so Detection Finding: Create is 200401. Filter on type_uid when you need one class and one activity; it is cheaper and less ambiguous than matching captions.
- severity_id: 0 Unknown, 1 Informational, 2 Low, 3 Medium, 4 High, 5 Critical, 6 Fatal, 99 Other. Map vendor severities to this scale deliberately and document the table; do not let each source map "high" differently.
- status_id and status_detail: for an Authentication event, the normalised outcome (success or failure) goes in status_id and the vendor reason code in status_code or status_detail. Failed logon rules should read status_id, not text.
- metadata: metadata.product and metadata.version are required. product identifies the data source; version records which OCSF release the event conforms to. log_name, original_time, reporter and tenant_uid are recommended and worth populating in multi-tenant estates.
- Time: time is a timestamp_t in milliseconds since the Unix epoch, corrected for source clock skew. Keep the source string in metadata.original_time, set timezone_offset (minutes from UTC) and use processed_time and logged_time to measure pipeline latency. The datetime profile adds RFC 3339 sibling fields where human-readable times help.
- raw_data and unmapped: raw_data holds the original event for forensics; unmapped holds source fields with no OCSF home. The schema warns consumers not to rely on a stable structure in unmapped, so detections should never depend on it.
- observables: an array that surfaces key indicators (IP addresses, hashes, user names, domains) from anywhere in the event with a name (the attribute path), a type_id (2 is IP Address) and a value. It makes "is this IOC anywhere in my data" a single query instead of a search across every field that can hold an IP.
- enrichments: data added during processing, such as geolocation or threat intelligence matches. Set metadata.modified_time when you enrich so analysts know the event was changed after collection.
Mapping decisions that matter
OCSF leaves real choices to the mapper. These are the decisions that cause most of the inconsistency seen in practice, with a recommended default for each.
| Decision | Options | Recommended default | Why it matters |
|---|---|---|---|
| Which class for a cloud audit record | API Activity, Authentication, Account Change, Entity Management | Use the most specific class: sign-ins to Authentication, IAM changes to Account Change or Group Management, everything else to API Activity | Identity rules filter on class_uid; a role attachment buried in API Activity is missed by Account Change rules |
| Severity mapping | Vendor scale copied, fixed table, computed | Fixed, documented table per source | Alert routing and SLAs use severity_id |
| Unknown activities | 0 Unknown, 99 Other with activity_name | 99 Other with the vendor label in activity_name; 0 only when it truly cannot be determined | 99 keeps the original meaning searchable |
| Fields with no home | Drop, unmapped, extension attribute | unmapped for low-value fields; a registered extension for anything detections need | Extensions are type-checked and versioned; unmapped is not |
| Raw event retention | raw_data in every event, separate raw store, none | Separate raw store keyed by metadata.uid, raw_data for high-value classes | raw_data can double storage; forensics still needs the original |
| Profiles | Apply none, apply where data exists | Apply cloud to cloud sources, host to endpoint-originated network events, security_control to events produced by a control | Profiles add attributes such as cloud.account and is_alert that rules rely on |
Alerts: since v1.4 an explicit alertable signal is an event with is_alert set to true. The ocsf-docs article on modelling alerts notes that Detection Finding, Data Security Finding and the security_control profile carry it. Use Detection Finding for an analysis result and the security_control profile when a control blocked or allowed an ordinary activity (disposition_id values such as 2 Blocked or 3 Quarantined).
Extensions: an extension needs a uid. The project guidance is to request a unique extension uid through a pull request to the ocsf-schema repository to avoid collisions, even if the extension itself stays private. Extensions can also patch core classes by adding attributes to them without creating new classes.
Where identity fits
Most attacker activity in cloud and SaaS estates arrives as authenticated API calls, which makes the IAM and Application categories the most valuable part of an OCSF deployment. A few schema features deserve attention:
- user.type_id: 1 User, 2 Admin, 3 System, 4 Service. Populate it from your identity inventory during enrichment so a rule can ask "Service account performed an interactive logon" across Entra ID, Okta, AWS and on-premises Active Directory in one query.
- actor: holds the user, session, iam_role, idp, app_name, authorizations, process and invoked_by. For a cloud API call made by a workload, invoked_by and iam_role are where the assumed role or service principal context belongs; mapping it into user.name loses the distinction.
- Authentication attributes: is_mfa, auth_protocol_id, logon_type_id (2 Interactive, 3 Network, 10 Remote Interactive and others), is_remote and session. These carry the signals behind MFA bypass, token replay and service account interactive logon detections.
- Account Change activities: Attach Policy (7), Detach Policy (8), MFA Factor Enable (10) and MFA Factor Disable (11) map directly to persistence and privilege escalation hunting.
See the Non-Human Identity (NHI) Guide for why machine identities need their own detection logic, and the Threat Intelligence for Identity and NHI Guide for the behaviours worth hunting.
Storing OCSF data
OCSF is often stored in columnar formats. Amazon Security Lake is the best documented example: it converts natively supported AWS sources (CloudTrail management and data events, Route 53 Resolver query logs, VPC Flow Logs, Security Hub findings, EKS audit logs and WAFv2 logs) into OCSF and stores them as Apache Parquet in Amazon S3. Its documentation shows two source versions, one using metadata.version 1.0.0-rc.2 and a second using 1.1.0.
For custom sources, Security Lake documents specific requirements: each source delivers one OCSF event class, every record in a Parquet object uses the same class, custom sources are supported for OCSF 1.3 and earlier, objects are written under a region=, accountId= and eventDay= (UTC, yyyyMMdd) prefix, files arrive in increments between 5 minutes and one event day, zstandard compression is preferred and records should be sorted by time. Check the current AWS page before building, because these limits change.
The OCSF project has also published an article on Iceberg and Parquet storage strategies. It describes single table, by source, by category, by class, observables-based, required-only and semi-structured payload layouts, and notes that they compose: for example category tables plus an observables table plus time partitioning.
| Layout | Strength | Weakness | Fits |
|---|---|---|---|
| One table per class | Narrow schemas, simple rules per class | Many tables; cross-class hunts need unions | Detection engineering on a few high-value classes |
| One table per category | Fewer tables, identity hunting in one place | Wide sparse tables (cheap in Parquet) | Most SOCs; good balance |
| Single table | One query surface | Very wide schema, schema evolution pressure | Small estates, exploratory analytics |
| Observables table alongside others | Fast IOC sweeps across all data | Extra write path to maintain | Threat intelligence matching and retro-hunting |
Partition by time first, then by source account or tenant. See the Security Data Lake Guide for access control, retention and cost design.
OCSF compared with other common schemas
OCSF is one of several normalisation models. You may run more than one: for example OCSF in the lake and a SIEM's native model at query time.
| Model | Owner | Normalisation point | Notes |
|---|---|---|---|
| OCSF | Linux Foundation project, multi-vendor | Producer, pipeline or ingest | Numeric class and activity ids, profiles and extensions, used by Amazon Security Lake |
| Elastic Common Schema (ECS) | Elastic, open source | Ingest into Elasticsearch | Field set with Elasticsearch data types, SemVer releases, custom fields allowed |
| ASIM (Advanced Security Information Model) | Microsoft Sentinel | Query-time KQL parsers or ingest-time ASim tables | 13 event schemas such as Authentication Event and Network Session; aligns with OSSEM |
Choosing: if your detections live in one SIEM, its native model is usually the shortest path and OCSF matters at the lake or exchange layer. If you are building a vendor-neutral lake, sharing data between products, or planning to change SIEM, normalising to OCSF once in the pipeline avoids rewriting parsers for each consumer. Small organisations should not build a custom OCSF pipeline: use the OCSF output of the tools and services they already run. Large organisations should own a mapping registry with a named owner per source.
How to implement
- Inventory sources and pick a version. List sources by detection value (identity provider, cloud audit, EDR, DNS, proxy) and choose one OCSF release as your target. Record it in a mapping registry with the consumer constraints (for example the Security Lake custom source version limit).
- Map the identity and cloud audit sources first. Authentication, Account Change and API Activity carry most high-value detections. Write a mapping specification per source: class, activity table, severity table, status mapping, which fields go to unmapped.
- Validate against the schema. The schema browser at schema.ocsf.io can generate example events and also acts as a validation server through its APIs; the repository's own CI uses ocsf-validator and a schema compiler. Run validation in your pipeline tests and reject events missing required attributes.
- Run in parallel. Keep the original parsed data and the OCSF output side by side for at least one detection cycle. Compare event counts per type_uid and replay your existing rules against both.
- Port detections. Rewrite rules to use class_uid, activity_id, status_id and normalised objects. If you write rules in Sigma, maintain an explicit field mapping from Sigma fields to OCSF attribute paths and test it; see the Sigma Rules Guide.
- Cut over by source. Switch consumers one source at a time. Roll back by repointing the consumer to the original data, which is why you keep it during the parallel run.
- Govern upgrades. Review each OCSF minor release changelog, test mappings against the new version in a branch, and update metadata.version only when every consumer accepts it.
Detection and measurement
Treat the mapping layer as production code with its own telemetry. Monitor validation failures, events landing in class 0 or activity 99, unmapped field volume and the gap between time and logged_time. Useful metrics:
- Mapping completeness: percentage of events per source with all required and recommended Base Event attributes populated.
- Classification precision: share of events with activity_id 0 or 99 per source; a rising value means the vendor changed its format.
- Pipeline latency: median and 95th percentile of logged_time minus time per source.
- Detection portability: percentage of production rules that reference only OCSF attributes and no unmapped or raw_data fields.
- Identity coverage: percentage of Authentication and API Activity events with a populated user.type_id, so service and human accounts can be told apart.
- Version drift: number of distinct metadata.version values in the lake at any time.
Framework mapping
| Framework | Reference | How OCSF supports it |
|---|---|---|
| NIST CSF 2.0 | PR.PS-04 Log records are generated and made available for continuous monitoring | Consistent log records across sources |
| NIST CSF 2.0 | DE.AE-03 Information is correlated from multiple sources | Shared classes and observables make correlation possible |
| NIST CSF 2.0 | DE.AE-02, DE.CM-01 | Analysis and network monitoring on normalised data |
| NIST SP 800-53 Rev. 5 | AU-3 Content of Audit Records | Required who, what, when, where and outcome attributes |
| NIST SP 800-53 Rev. 5 | AU-8 Time Stamps | time, original_time and timezone_offset |
| NIST SP 800-53 Rev. 5 | AU-6, AU-12, SI-4 | Review, generation and monitoring across normalised sources |
| CIS Controls v8.1 | Control 8 Audit Log Management (8.2 collect, 8.9 centralise, 8.11 review) | Normalised, centralised logs |
| ISO/IEC 27001:2022 | Annex A 8.15 Logging, 8.16 Monitoring activities, 8.17 Clock synchronisation | Consistent logging and time handling |
Common failure patterns
- OCSF in name only: the mapper sets class_uid and dumps everything else into unmapped. Rules still need vendor field names and nothing is portable.
- Everything is API Activity: cloud sign-ins and IAM policy changes are mapped to API Activity, so Authentication and Account Change based rules see nothing from the cloud.
- Mixed versions without tracking: sources upgraded independently leave several metadata.version values in one table and attributes that exist only in some rows. Consumers that accept a fixed version, such as Security Lake custom sources, reject or misread the newer data.
- Lost time semantics: local time written into time without conversion, or original_time discarded, breaks timelines in investigations and violates the UTC requirement for partition keys.
- Human and machine identities merged: user.type_id left empty, so service accounts and agents are indistinguishable from people in sign-in analytics.
- Raw events discarded: no raw_data or raw store, so a mapping bug found months later cannot be corrected and evidence is lost.
Practitioner checklist
- Choose and record a target OCSF version and the version limits of every consumer.
- Maintain a mapping registry: source, owner, class, activity table, severity table, profiles applied.
- Map identity provider, directory and cloud audit logs to Authentication, Account Change and API Activity first.
- Compute type_uid as class_uid times 100 plus activity_id and validate it in tests.
- Populate user.type_id from your identity inventory to separate human, admin, system and service accounts.
- Keep raw events retrievable by metadata.uid for forensics and remapping.
- Register a unique extension uid before shipping custom extension attributes.
- Alert on rising activity_id 99, validation failures and pipeline latency per source.
- Rewrite detections to OCSF attributes only and track the share that still use unmapped fields.
Standards and references
- OCSF: ocsf-schema repository (core schema, changelog)
- OCSF: Understanding the Open Cybersecurity Schema Framework
- OCSF: Technical articles (observables, alerts, extensions, storage strategies)
- Linux Foundation: OCSF Joins the Linux Foundation
- AWS: Open Cybersecurity Schema Framework in Amazon Security Lake
- AWS: Collecting data from custom sources in Security Lake
- Microsoft Learn: Normalisation and the Advanced Security Information Model (ASIM)
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: Security Data Pipeline Guide · Security Data Lake Guide · SIEM Guide · Detection Engineering Guide · Log Source Coverage Matrix Template