A log says something happened. Evidence proves it.
An audit trail that the audited system can rewrite is not evidence. The decision evidence fabric is the difference between a record of what B5 decided and a record an examiner can verify independently.
This capability is available in Preview today. The Q4 2026 roadmap extension adds the capabilities described below; production availability has not yet been declared. Both badges above are rendered from the Product Truth Registry.
1. What this enforces
Nothing directly. This is the output side of enforcement: every decision B5 makes becomes a record with the caller, the record acted on, the purpose, the delegation in force, the reason code and the timestamp.
2. Where it enforces
At the decision point, written as part of the same operation rather than afterwards by a collector. Evidence assembled later cannot prove it was not assembled selectively.
3. What evidence it produces
Two forms, for two audiences. A human-readable decision graph that explains why a decision came out the way it did, and a machine-readable form that is signed, hash-chained, timestamped and verifiable by a party that does not trust the system that produced it.
4. Why you cannot assemble this from what you already own
A SIEM ingests what it is sent, and cannot attest to what it was not sent. Application logs are written by the application being audited. Database audit captures the statement, not the authority under which it ran. None of them can answer the question an examiner actually asks: show me that this specific action was authorised, by whom, under what grant, at that moment.
5. What Q4 2026 adds
Decision Explainability Graph
Human-readable and machine-readable explanation of the identity, action, resource, policy, attributes, relationship path and final decision.
Cryptographically Verifiable Evidence
Signed and hash-chained events, trusted timestamps, WORM export, policy hashes and independent verification tools.
6. Acceptance criteria
These are the conditions the capability must satisfy to be considered complete. They are quoted from the specification rather than paraphrased, because an acceptance criterion that has been reworded is no longer the criterion.
- Evidence tampering is detectable without trusting the primary B5 database. MF-023
- Verification tools work against customer-exported evidence. MF-023
- Each record includes policy hash, actor, action, resource, outcome, reason and trace correlation. MF-023
7. What is still open
The following are genuinely undecided rather than merely undocumented, and each one changes what the capability is:
- Which external verifier interface is published, and whether verification requires B5 software at all — it should not.
- WORM retention: which storage classes are supported and who holds the keys.
- How much of the decision graph is exposed to the end user versus the administrator versus the examiner.
Every Q4 2026 extension is also held to four platform-wide requirements, six test classes and four release gates. They are published once, on the Q4 2026 roadmap, rather than repeated on every page.
The schema, and why we wrote it
Every SIEM can record who acted and whether it was allowed. None of them can record the authority under which it was allowed. We checked: the Open Cybersecurity Schema Framework has Authorize Session for session-level privilege assignment and API Activity for requests, and no class at all for a decision about an individual record.
So we wrote one. The OCSF Authority extension defines a data-element authorization decision carrying the actor, the record, the decision, the reason code, the delegation in force, the enforcement point, the aggregate limits consulted, the age of the state consulted, and whether the decision was a simulation. It also defines a profile — a mixin any vendor can apply to their own event classes to carry authority context without adopting ours.
An event stream that cannot distinguish a simulated decision from a
real one will produce detections built on traffic that never happened. That is why
is_shadow is in the schema and not an afterthought.
Status: Q4 2026 Roadmap Extension
One decision, both sides of the seam
An advisor with a real, unexpired grant tries to move money from an account the grant does not cover.
This is the case worth showing, because it is the one every other layer gets wrong. The caller is authenticated. The session is valid. The endpoint is permitted. A gateway sees a well-formed request from a known user and passes it. The account is simply not in the grant — and that is a fact about authority, which only the layer holding the grant can know.
Submit a transfer instruction
Custody.Instructions.InstructionService.Submit is called for account AC-77310 by advisor-338, acting for user-1042 under grant grant-4471.
Denied, with a reason
DENY_SCOPE_ACCOUNT_NOT_IN_GRANT. The grant covers AC-99120; the instruction targeted AC-77310. Decided in-process, before the method body ran.
The decision is emitted in the OCSF authority extension B5 authored, because the Open Cybersecurity Schema Framework has no class for “may this actor perform this action on this record, under which grant, and why”. Authorize Session is session-level; API Activity is request-shaped. Neither can carry a grant.
{
"category_uid": 3,
"category_name": "Identity & Access Management",
"class_name": "Authorization Decision",
"metadata": {
"extension": { "name": "authority", "uid": "PENDING-OCSF-REGISTRATION", "version": "0.1.0" }
},
"time": 1785225601456,
"activity_id": 9,
"activity_name": "Transfer",
"is_permitted": false,
"reason_code": "DENY_SCOPE_ACCOUNT_NOT_IN_GRANT",
"actor": { "user": { "uid": "advisor-338", "name": "j.okafor" } },
"resource": { "uid": "AC-77310", "type": "custody_account" },
"enforcement_point": {
"type": "in_process_method",
"runtime": "aspnet_core",
"name": "Custody.Instructions.InstructionService.Submit"
},
"delegation": {
"uid": "grant-4471",
"grantor": "user-1042",
"grantee": "advisor-338",
"purpose": "portfolio_rebalance",
"scope": "account:AC-99120;action:transfer",
"on_revoke_in_flight": "fail",
"is_revoked": false
},
"purpose": "portfolio_rebalance",
"policy": { "uid": "pol-cust-14", "name": "Custody Servicing", "version": "14" },
"decision_evidence": {
"uid": "ev-01J8ZA",
"hash": "b7c1f0e2a9",
"prev_hash": "4d0aa71cc3",
"chain_uid": "chain-t-8f21c0",
"sequence": 918234,
"signing_key_uid": "key-2026-07-a"
},
"is_shadow": false,
"state_age": 240,
"duration": 2,
"message": "The grant covers AC-99120; the instruction targeted AC-77310."
}The extension identifier is deliberately unregistered. OCSF assigns each extension a reserved identifier range so two vendors cannot ship colliding schemas. Until that range is issued the sample carries PENDING-OCSF-REGISTRATION, which is not a valid integer — so this cannot be mistaken for a registered schema, including by us.
Four fields nobody writes unless they have built this
The argument for authoring the schema rather than mapping into someone else’s.
Was this decision real?
A simulated decision must be distinguishable from an enforced one, or shadow traffic silently poisons every detection and every metric built on the stream.
How fresh was the state?
A permit against three-second-old state is not the same permit as one against three-hour-old state. Same outcome, different assurance.
Which aggregate was consulted?
Without it, a denial on a spending threshold is indistinguishable from a denial on scope — and the remedies are opposite.
What happens to work already moving?
fail or allow_completion. It is a property of the grant, so it belongs on the record, decided when the grant was written rather than during the incident.
For a Microsoft security team
Where this lands today, and where it is lossy.
ASIM, Sentinel’s normalisation layer, has schemas for Authentication, Audit Event, DHCP, DNS, File Event, Network Session, Process Event, Registry Event, User Management and Web Session. There is no authorization-decision schema. The nearest fit is Audit Event, and it is lossy in two specific ways:
The reason collapses
EventResult reduces a denial to pass or fail, so the reason code — the field an analyst actually needs — survives only as free text in EventOriginalResultDetails.
The grant has nowhere to go
There is no field for the delegated authority in force. The one thing that distinguishes this event class from an audit line is the thing that cannot be normalised.
That is not an integration gap to be worked around with custom fields; it is a missing schema. Emitting OCSF and mapping to ASIM alongside it is the route we intend — OCSF for portability, ASIM because it is what makes the data work with Sentinel’s built-in analytics rules. The mapping notes mark every inferred field name as unconfirmed rather than presenting a half-guessed table as authoritative. Q4 2026 Roadmap ExtensionThird-Party Integration
Verify it yourself, offline
Twenty-one checks, no network, no login, nothing of ours to trust.
The evidence format is published, and the verifier is a single Python file using only the standard library. It has no B5 dependency and makes no network calls. Each record’s digest binds its own body and its position in the chain, so altering one record changes every hash after it, which moves the chain head, which breaks the signature.
$ python3 b5verify.py ./example-export-ed25519 b5verify — ./example-export-ed25519 ok every record carries the required fields ok every record hashes to its stated digest ok the hash chain is unbroken ok sequence numbers are contiguous and in order ok the manifest's declared head is the last record's hash :: manifest 281e0ac6b700, actual 281e0ac6b700 ok the chain head is signed by the key the manifest names :: ed25519 ok every record states whether it was a simulation ok NOTE: 1 of 5 records are shadow decisions and did not affect any response VERIFIED — 21 checks passed. # exit 0 $ sed -i 's/AC-77310/AC-99120/' example-export-ed25519/records.jsonl $ python3 b5verify.py ./example-export-ed25519 FAIL every record hashes to its stated digest :: [(2, 'ev-01J8ZA', 'stated 5a7c1ab486cd, computed 581ebbefff4f')] VERIFICATION FAILED — 1 of 21 checks did not pass. # exit 1
Two example exports ship, and the reason is not convenience. One is signed with HMAC and carries its secret in the manifest so it verifies with the standard library alone — which makes it demonstrably forgeable. The other carries an ed25519 public key only, which is what production looks like. Shipping just the convenient one while claiming signatures protect the chain would be a claim the artefact itself contradicts. When the signing library is absent the tool reports the signature check as SKIPPED, never as passed.
The format specification was attacked before it was published. Nine attempts — flipping a denial to a permit, deleting a record mid-chain, reordering two, re-chaining after a tamper, forging the head signature, stripping the shadow flag — and one of them worked on the first draft, which is how the digest came to bind the chain linkage as well as the body. A format that has not been attacked is a draft.