Security Incident OCSF Mapping
An exported security incident is one OCSF Detection Finding event (class 2004, schema version 1.9.0). This page lists each field and where its value comes from. To set up the export, see Export security incidents to a SIEM.
Class and version
| Attribute | Value |
|---|---|
class_uid | 2004 (Detection Finding) |
category_uid | 2 (Findings) |
metadata.version | 1.9.0 |
metadata.profiles | ["incident"], which carries assignee and verdict_id |
metadata.product | name "Nirmata AIControls", vendor_name "Nirmata", and the product version |
metadata.log_name | aicontrols.security_incident |
metadata.uid | A new ID for each manual export. An automatic export reuses one stable ID for the same destination, incident and activity, so a receiver can deduplicate a retry. |
metadata.labels | trigger:manual or trigger:auto |
type_uid is class_uid * 100 + activity_id, as OCSF defines it. One incident is one event. finding_info.uid is the incident ID and stays the same across exports, so a SIEM can correlate an update or a close with the event that opened it.
Activity
activity_id | Name | When |
|---|---|---|
| 1 | Create | The first successful export of this incident, even when it is already resolved. The event then carries the resolved status and verdict. |
| 2 | Update | A later export of an incident that is not resolved. |
| 3 | Close | A later export of a resolved incident. |
Field mapping
| OCSF field | Source |
|---|---|
time, end_time | Last finding time, in epoch milliseconds. |
start_time | First finding time. |
severity_id, severity | The incident's highest severity: critical 5, high 4, medium 3 (also the baseline "warning" band), low 2, informational 1, otherwise 0 (Unknown). |
is_alert | true for high and critical. |
status_id, status | New 1, Acknowledged 2 (In Progress), Resolved 4. |
assignee | The triage assignee, with type_id 2 (Admin). Omitted when unassigned. |
verdict_id, verdict | The resolve disposition: true positive 2, false positive 1, benign 5. Omitted until resolved. |
count | Number of findings in the incident. |
message, finding_info.title | The plain-English title from the Security Finding Catalog. When the type is not in the catalog, the policy or event type. |
finding_info.desc | The catalog "why it matters" text. |
remediation.desc | The catalog recommended action. |
finding_info.uid | The incident ID. When the destination redacts actors, an opaque hash of it keyed on a server secret of the deployment, stable across credential rotation, or the random event ID when the deployment has no such secret (the incident ID encodes the actor); src_url, unmapped.aicontrols.follows and entity are then omitted too. |
finding_info.types | The detector kind and the event type. |
finding_info.analytic | The catalog title (or the policy or event type) and the catalog key. type_id is 2 (Behavioral) for sequence detectors, 3 (Statistical) for anomaly and drift detectors, otherwise 1 (Rule). |
finding_info.first_seen_time, last_seen_time, created_time, modified_time | First and last finding times. |
finding_info.related_events | The newest 25 member findings: uid, type and severity_id. related_events_count holds the total. |
finding_info.data_sources | The distinct sources of the member findings, such as audit or sequence. |
resources | The incident target (role_id 1) and, for a workload actor, the workload (role_id 2). The cluster is a cluster:<name> label. |
actor.user | The user, or the user an agent acts for. A service account has type_id 4 (Service). Omitted when the destination redacts actors. |
evidences[].ai_agent | The agent identity for agent and service-account actors. Omitted when the destination redacts actors. |
tickets | The Jira or ServiceNow tickets already created for the incident: uid is the ticket key, src_url its link, title the ticket title, type_id 2 (External). Omitted when there are none. See Security Incident Tickets. |
src_url | A link to the incident in the UI. Present only when ui.publicURL is an absolute URL that doesn't name this machine (such as localhost or 127.0.0.1); any user info, query or fragment in it is dropped. |
MITRE techniques
The techniques come from the finding catalog. Each is exported twice, in attacks and in finding_info.attacks, because consumers read either.
- An ATLAS technique such as
AML.T0086goes intechnique.uid. OCSF documentstechnique.uidfor both ATT&CK and ATLAS IDs, so theAML.prefix tells them apart. No extension is needed. - An ATT&CK sub-technique such as
T1552.001becomestechnique.uidT1552plussub_technique.uidT1552.001. tacticslists every tactic the technique achieves andtacticis the first. ATLAS tactics use IDs likeAML.TA0010; ATT&CK tactics use IDs likeTA0006.attack.versionis the matrix version the technique and tactics were checked against: ATLAS2026.09and ATT&CK20.0.- A finding type with no supported mapping exports no
attacksat all (the field is omitted), never a guessed technique.
Product fields in unmapped
Values with no OCSF home are under unmapped.aicontrols: groupingVersion, windowSeconds, detectorKind, eventType, policy, plugin, entity, membersIncluded, membersTotal, membersTruncated (the counts below cover the included findings only, at most 100), completeness (partial and truncated), counts of findings by event type, severity and evidence status, counts of control decisions, the names of the policies that acted (at most 20), follows (the ID of the resolved incident this one follows), actorUnknownReason, actorsRedacted (when the destination redacts actors) and summaries (when the destination includes them).
What is never exported
- Evidence items and excerpts, prompts, model responses, request and response bodies, and blob references.
- The text of finding summaries, unless the destination turns on Include finding summaries. Detectors write them, and they can quote matched values, so they are sent only after the credential and personal-data redactor has run on them, and each is cut to 500 characters. The redactor removes credentials and personal data, not every sensitive value: whatever else a summary contains, such as a file name or an internal host name, is sent as is. Turn the option on only for a destination you trust with that content.
- Triage notes.
- Destination credentials: the token, the signing secret and the URL.
User, agent and workload identities are exported by default because analysts need them to act. They are already visible to every portal user. A destination with Redact actors on omits them: actor, assignee and the agent evidence are left out of the event. They are omitted rather than hashed, because a hash of an email address is guessable and still identifies the person across events.
Splunk HEC format
With the Splunk HEC format, the OCSF event is wrapped as event in a Splunk HTTP Event Collector envelope:
{
"time": 1791977400.0,
"source": "nirmata-aicontrols",
"sourcetype": "nirmata:aicontrols:ocsf",
"index": "security",
"event": { "class_uid": 2004, "...": "..." }
}
time is the incident's last finding time, so an older incident sits where it happened on the Splunk timeline. index is sent only when you set it. The request carries Authorization: Splunk <token>.
Delivery and audit
You can configure up to 10 destinations. Each has a name, its own URL, format and credentials, and its own routing: a severity filter and an optional list of event types decide which incidents go there with Export to all and with automatic export. Choosing one destination by name ignores the filters.
Each export is one POST with Content-Type: application/json. When you set a signing secret, the request carries X-AIControls-Signature: sha256=<hex>, an HMAC-SHA256 of the exact request body. A request is retried up to 3 times, with 1 and 2 second backoff, on a network error, 429 or 5xx. Other 4xx responses are not retried. Redirects are not followed, and environment proxy settings are ignored. The destination URL may not be a cloud metadata address (169.254.169.254, fd00:ec2::254, 100.100.100.200, 192.0.0.192 and 168.63.129.16) or contain a query string, fragment or user info. An automatic export uses the same metadata.uid for the same destination, incident and activity, so a receiver that deduplicates on it drops a repeat after a crash.
Every attempt is recorded in the configuration audit trail as security_incident.exported with the outcome (success or failed), the trigger, the format, the destination name and host (no path or query), the event ID, the attempt count and the HTTP status. The metric aicontrols_security_export_total{trigger,outcome} counts attempts.
Amazon Security Lake format
Amazon Security Lake accepts OCSF 1.3 and earlier for custom sources, so a destination with the Amazon Security Lake (Parquet) format does not send the 1.9.0 event above. It writes the same incident, with the same routing, redaction and activity rules, as an OCSF 1.3.0 Detection Finding (class 2004) row in a Parquet object. The 1.3.0 schema has no incident profile, so these fields change:
| 1.9.0 event | 1.3.0 Parquet row |
|---|---|
metadata.version, metadata.profiles | 1.3.0; no profile is declared. |
actor.user | evidences[0].actor.user. A service account has type_id 99 and type Service, because 1.3.0 has no type_id 4. |
assignee, verdict, verdict_id, is_alert, evidences[].ai_agent | Not in 1.3.0. Kept in unmapped.aicontrols.ocsf19. |
attacks[] | Not a 1.3.0 class attribute. finding_info.attacks[] already carries the same entries. |
src_url | finding_info.src_url. |
resources[].role_id | A label on the resource: role:target or role:actor. |
finding_info.related_events[].severity_id | Not in 1.3.0. Kept in unmapped.aicontrols.ocsf19.relatedEvents. |
Nested OCSF objects are Parquet struct and list columns; ids are 32-bit integers (type_uid 64-bit); times are epoch milliseconds. unmapped is a string map whose value aicontrols is a JSON document. Files are zstd-compressed, sorted by time, and written to ext/<source>/region=<region>/accountId=<accountId>/eventDay=<YYYYMMDD>/. See Export security incidents to Amazon Security Lake for the setup and the batching rules.
Microsoft Sentinel format
A destination with the Microsoft Sentinel (Logs Ingestion) format sends the same 1.9.0 event as OCSF JSON, in a one-element array, to an Azure Monitor data collection rule stream with a Microsoft Entra token. The columns and the rule are in Sentinel table and rule schema; the setup is in Export security incidents to Microsoft Sentinel.
API
| Route | Access | Purpose |
|---|---|---|
GET /api/v1/security-incidents/{id}/export | Administrators and viewers | Whether any destination is configured, and for each its name, format, automatic mode, severity filter and the last successful export of this incident. |
POST /api/v1/security-incidents/{id}/export | Administrators | Export the incident now. The optional body {"destination": "name"} picks one destination; without it the event goes to every destination whose filters accept the incident. Returns 200 with a results list (delivered, failed or in_progress for each destination, with eventUid, activity, attempts or a failure reason); status is delivered or partial. 502 when no destination accepted the event; 409 when none is configured, none accepts this incident, or every destination was exported in the last 2 minutes. |
Destination settings
Destinations are saved as the siem managed integration, {"destinations": [...]}. Credentials (webhookUrl, token, secret, for Security Lake securityLake.credentials.roleArn, externalId and bucket, and for Sentinel sentinel.clientSecret and sentinel.privateKey) are masked when the configuration is read and redacted in the configuration audit.
| Field | Meaning |
|---|---|
name | Required and unique. Letters, digits, space, dot, dash and underscore, at most 40. |
webhookUrl | Required for ocsf and splunk_hec. HTTPS (HTTP only for loopback). Refused for security_lake and sentinel. |
format | ocsf (default), splunk_hec, security_lake or sentinel. |
token, secret | Optional. The token is required for splunk_hec. |
hecSourcetype, hecIndex | Optional, for splunk_hec. |
minSeverity | medium, high or critical. Empty means no filter for Export to all. |
eventTypes | Optional list of event types. |
autoExport | off (default) or on. When on, the threshold is minSeverity, or critical when it is empty. |
securityLake.sourceName | Required for security_lake. The custom source name, at most 20 characters. |
securityLake.region | Required for security_lake. The Security Lake region. |
securityLake.accountId | Optional. 12 digits or external...; default external. |
securityLake.ocsfVersion | Optional. Only 1.3.0 is accepted. |
securityLake.credentials.roleArn, externalId, bucket | Required for security_lake. Masked and redacted. AWS credentials come from the ambient chain; the role is assumed with the external ID. |
sentinel.* | Required for sentinel: tenantId, clientId, dceUrl, dcrImmutableId, streamName, and the credential: either clientSecret or certificate with privateKey, exactly one. See Sentinel table and rule schema. |
redactActors | Off by default. Omits user, agent and assignee identities. |
includeSummaries | Off by default. Adds finding summaries after redaction. |