workflow-audit source copies your organization’s workflow audit trail — who approved a run, who changed a policy, who exported what — into the same log drain as everything else. Selecting it is how an organization ships its audit to a SIEM from this release onwards, and it replaces the per-organization workflow SIEM webhook.
workflow-audit is off by default, on a new drain and an existing one alike. It is a compliance stream you opt into:
Opting in has nothing to do with
--include-content. workflow-audit is not a content source: selecting it never prints the content acknowledgement, and a drain that selects only it is not a drain that carries end-user messages. --include-content changes only which five attributes arrive.One event name, not one per action
lua.<source>.<suffix> with the suffix restricted to lowercase letters, and every audit action is dotted and underscored (workflow.run.step_parked), so an action could never be the suffix — and widening the name pattern would be a breaking schema change rather than an additive one.
The action is an attribute. Switch on lua.audit.action, with a default branch, exactly as you would switch on lua.source rather than on a per-server MCP event name. New actions appear within this major version and must not break your ingest.
Every audit record is INFO
severityNumber is 9 on all of them. There is deliberately no severity ladder over the actions: a compliance sink wants the whole trail rather than the alarming part of it, and a second vocabulary to keep in step with the first is a source of drift.
That has one consequence big enough to have its own row below: a drain whose --min-severity is warn or error receives no audit records at all, even though it selects the source.
Selectors that will silently deliver nothing
Three of a drain’s selectors can leave you with a correctly configured audit drain and an empty destination. There is no error and no delivery-log row — the records are simply never matched.--sampling is not a fourth trap, but it is not a volume knob here either: only debug records are sampleable and audit records are always info, so a sampling rule has no effect on this source.
Attributes
There is no
body on an audit record, with or without content.
lua.audit.metadata is a JSON string
Attribute values in this schema are scalars, and that does not change. Audit metadata is free-form per action, so flattening it would put unbounded per-action key names into every destination’s attribute index — a cost bug at the destination, not a convenience. Parse it at ingest:
JSON.parse still succeeds, which is why the marker is an object rather than a string.
The content rule
The five attributes marked content only are free text about a person. They are withheld unless the drain has--include-content, and the record still arrives, carrying lua.content.withheld: true. Ids, the action, the target and the surface are never withheld, so an organization can always see that the action happened.
lua.workflow-audit.info carries lua.content.withheld whenever content is off — even for an entry that recorded no evidence at all. That is deliberate: an entry with nothing to show must not be indistinguishable from one whose evidence you were not sent. Treat the flag as advisory and the presence of each key as authoritative.
One audit entry produces a different record per drain: a drain with content on and a drain with content off in the same organization each receive the record they asked for, under the same record id.
Content or not, every attribute passes the scrubber. An organization scrub rule that matches inside lua.audit.metadata masks it there exactly as it would in a log body.
Delivery, ordering and duplicates
The record id is the audit entry’s own id, so a retried write or a replayed sweep cannot double-deliver. Delivery is at-least-once like every drain: deduplicate onrecords[].id.
Records are enqueued only after the audit entry is durable, so a drain never carries an entry the platform’s own audit trail does not have. The reverse is possible and intended: the drain is fire-and-forget, and a drain outage never fails the action that was audited. Your SIEM is a copy, not the system of record.
Audit entries are written by more than one part of the platform, so the trail a drain carries is the whole one — run and ledger actions alongside read-access, policy, export and artefact actions. A newly created or newly edited drain starts (or stops) receiving audit within about 30 seconds.
Migrating from the workflow SIEM webhook
The per-organization workflow SIEM webhook (audit.siemWebhook on the workflow policy) is replaced by a drain that selects workflow-audit. It was a second delivery pipeline with its own signing, its own backoff and its own ordering, and none of the health, quota, delivery log or replay a drain already has.
Existing webhooks are migrated for you. You do not have to create the drain.
What changes for your receiver
Every field of the old body is present on the new record, as an attribute — the table above maps them. The old
action is lua.audit.action; the entry’s metadata is lua.audit.metadata, a JSON string.
Verify signatures has the new format, working verifiers and published test vectors.
The overlap release
A drain created by the migration adds two extra headers to every delivery, for one release only:<body> is the uncompressed batch body — the same bytes X-Lua-Signature covers. So a receiver written against the old webhook can keep its existing verification code pointed at X-Lua-Signature-Legacy and X-Lua-Timestamp while it moves to X-Lua-Signature, and the two headers can never disagree about which bytes were signed.
The legacy value ships under its own header name because X-Lua-Signature is already the drain protocol’s header and the two values are not interchangeable: a different signed string and a different timestamp unit. Overwriting it would break every conforming verifier at once.
What to check after your organization is migrated
1
Verify the drain
The migration leaves the drain in
pending_verification, which buffers rather than delivers. Prove ownership of the endpoint and it moves to healthy:2
Watch the test record land
A
lua.drain.test record is enqueued for you and delivered by the normal flush, not by the migration. Confirm it arrived rather than trusting that the migration finished:3
Check the quota
The drain’s allowance is recomputed from your plan on its next write. Confirm it is not sitting at a zero allowance before you call it live:
Two things the migration changes on purpose
--include-contentis turned on. Creating such a drain by hand would require the content acknowledgement first. The migration does not ask for one, because nothing is transitioning: the webhook had been delivering this organization’s auditmetadatato this same endpoint under the policy you already set, and leaving the flag off would silently halve every record you receive. The drain selects onlyworkflow-audit, so no end-user message content is in scope — but the flag is on, and adding a content source to that drain later will not re-ask.- You may receive more actions than before. A drain selector has no per-action filter:
workflow-auditis the whole vocabulary. An organization whose webhook was narrowed to a subset of actions therefore receives more audit actions than before, never fewer. Plan for the ingest volume.
If your organization was not migrated
A migration run can refuse an organization rather than guess. The three reasons you can act on:
The run is idempotent, so a re-run adopts the drain it already made rather than creating a second one.
The workflow policy field is deprecated
PATCH /admin/orgs/:orgId/workflow-policy with audit.siemWebhook still works in this release. The write happens; the notice is advisory, not a refusal. A request that names the field answers a deprecations entry in the body:
audit.siemWebhook carries neither the key nor the headers, so watching for Deprecation: true is enough to find the callers that still set it. Point new configuration at a drain instead.
See also
Ship logs to your stack
Every selectable source, and what a drain is.
Event schema
The full attribute catalogue and the content rule.
Verify signatures
The
X-Lua-Signature format and working verifiers.Delivery records
The other phase-2 source with its own page.

