> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/administration-guide/governance/sod/sod-triage-remediation-and-evidence.md).

# Work an SoD violation to closure

Triage an SoD violation to its authoritative source, govern exemptions and mitigating controls, read SoD context in a certification review, and produce evidence an auditor will accept.

## What this is, and when you need it

Detection produces a list. A list is not a control outcome. This page is for the two people who have to turn one into the other: the **triager**, who opens a violation, works out which entitlement arrived from where, and picks an outcome; and the **evidence producer**, who has to hand an auditor something showing that the conflict was found, decided, actioned and re-checked, with dates.

You need this the moment the first detection run finishes, and then continuously. The failure mode is not that nobody looks at the list — it is that somebody closes items on it without changing or governing any risk: revoking a child entitlement that a business role puts straight back, granting an exemption with no owner and no review date, or linking a "mitigating control" that names no procedure and no evidence. All three make the list shorter and the organisation no safer, and all three are visible to an auditor who reads the rows.

## At a glance

|                          |                                                                                                                                                                                                                                  |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **You will end up with** | One violation resolved at its authoritative source, or formally accepted with a recorded exemption or mitigating control, and absent from the **next** detection run                                                             |
| **Where**                | **Access Control → Segregation of Duties**, on the **Violations**, **Mitigating Controls** and **Reports** tabs (`/webconsole/segregation-of-duties`); one user's detail is `/webconsole/user-sod-policy-violation?id=<USER_ID>` |
| **You need first**       | A completed detection run; the process or application owner available to decide which duty the user gives up; the authoritative grant path identified                                                                            |
| **Takes**                | 15 minutes per violation to triage; days to weeks for remediation to reach the target and re-detect clean                                                                                                                        |
| **Reversible**           | **No** — revoking access changes the user's entitlements and dispatches provisioning. An exemption row can be deleted, but the access it permitted was live meanwhile                                                            |

## Before you begin

The **Violations** tab renders a screen headed **Impacted users** — same thing, two labels, which is worth knowing before you go looking for a screen called "Violations". Getting violations to exist in the first place is [SoD detection and violations](/administration-guide/governance/sod/sod-detection-and-violations.md); defining the policies is [SoD policies and rule sets](/administration-guide/governance/sod/sod-policies-and-rule-sets.md). This page assumes both.

Read the **Is direct violation** column before you touch anything: a direct violation is the grant itself and can be removed where you are standing, while an indirect one is inherited through a parent role or group, and removing the child entitlement by hand fixes nothing.

## Remediate the authoritative source

**Delete selected** removes the entitlement from the user. It does not remove whatever put it there. A business role whose content includes that entitlement, a business rule that recalculates membership from an attribute, or a synchronization that carries the grant inbound will all restore it — sometimes within minutes, always without anybody noticing that the violation you closed has quietly reopened.

{% stepper %}
{% step %}

### Decide which duty the user gives up

With the process or application owner, not on your own. Removing the wrong side of a conflict breaks somebody's job and the violation survives.
{% endstep %}

{% step %}

### Find the authoritative path

Direct administration, an access request, a business role, a business rule, a synchronization or import, or a nested entitlement. The user's access detail shows where a membership came from — see [Grant and revoke access](/administration-guide/identities/grant-and-revoke-access.md).
{% endstep %}

{% step %}

### Change the source, not the child

Remove or end-date the source relationship: drop the business role membership, correct the rule, fix the mapping in the inbound feed, or unnest the entitlement. Use **Delete selected** on the Violations tab only when the grant really is direct.

**Delete selected** and **Allow selected** are the same operation with opposite intent — one user, one policy, the entitlements you ticked, and your comment — and the audit action follows which button you pressed: `DELETE_SOD_VIOLATIONS` or `ALLOW_SOD_VIOLATIONS`. There is no separate exemption screen.
{% endstep %}

{% step %}

### Follow it to the target, then re-detect

Let provisioning complete, or work the manual fulfilment task. Then re-run detection for that user or policy and confirm both that the violation is gone and that the compliant negative case is still clean. A violation that clears in OpenIAM while the account still holds the access in the managed system is not resolved; it is unreconciled.
{% endstep %}
{% endstepper %}

Deleting the OpenIAM representation of an entitlement so that the alert goes away is not remediation. It is the destruction of evidence, and the access is still there.

## Verification

| What you did                                   | Evidence                                                                                                                                                                                           |
| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Revoked conflicting access                     | `DELETE_SOD_VIOLATIONS` (target `USER`); the user leaves the Violations tab after the next detection                                                                                               |
| Granted an exemption                           | `ALLOW_SOD_VIOLATIONS` (target `USER`); a `SOD_EXEMPTION` row with your `CREATED_BY` and `COMMENT_TEXT`                                                                                            |
| Created or changed a mitigating control        | `CREATE_SOD_MITIGATING_CONTROL` / `UPDATE_SOD_MITIGATING_CONTROL` / `DELETE_SOD_MITIGATING_CONTROL`, target `SOD_MITIGATING_CONTROL`                                                               |
| Generated a report                             | `GENERATE_SOD_REPORT`; a `.csv` in `org.openiam.sod.reports.directory` with no `.processing` sibling left behind                                                                                   |
| A user's last conflict cleared                 | `SOD_VIOLATION_RESOLVED` mail; the document deleted from the `user-violated-sod-policy` index                                                                                                      |
| Remediated at the source rather than the child | The membership or rule that granted the entitlement is changed, the target account reflects it, and the violation is absent from the **next** detection run — not only from the screen you were on |
| Linked a mitigating control to a policy        | A `SOD_POLICY_MC` row; `mitigatingControlIds` on the user's violation index entry; the control named in a generated report                                                                         |
| Produced audit evidence for one conflict       | All four timestamps retained: dataset generated, conflict recorded, review decision and its fulfilment, current target state                                                                       |

## When it goes wrong

| Symptom                                                       | Cause                                                                                                                                                                                 | Fix                                                                                                                                                                               |
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Access came back after you removed it                         | A business role, a business rule or a synchronization restored the entitlement, or another inherited path still grants it                                                             | Remediate the authoritative source, not the child grant, then re-detect                                                                                                           |
| **Allow selected** refused                                    | `SOD_POLICY.EXCEPTIONS_ALLOWED = 'N'`; the screen answers `Exemptions are not allowed for this policy`                                                                                | Attach a mitigating control instead, or reclassify the rule — enforcing a set forces this off for `SOD_RISK_CRITICAL` policies                                                    |
| A user is still in violation after an exemption               | `SOD_EXEMPTION` is per entitlement; the user holds another entitlement on the same segment                                                                                            | Exempt each entitlement, or revoke                                                                                                                                                |
| An expired mitigating control still reads as mitigating       | `EXPIRATION_DATE` is recorded, not enforced; `REVIEW_FREQUENCY` fires no reminder                                                                                                     | Review controls on your own schedule; include `USER_IS_MC_MANAGER` and `USER_IS_MC_OWNER` in the report                                                                           |
| A mitigating control will not delete                          | A `SOD_POLICY_MC` row still links it to a policy                                                                                                                                      | Unlink it from every policy first — and prefer end-dating to deleting, since the control is the recorded justification for every violation accepted on its strength               |
| Report never appears in the list                              | A `.processing` file remains — generation failed before the atomic move, or the per-name lock skipped a duplicate request                                                             | Check the ESB log for `SOD report '<name>' generation started` and the failure after it                                                                                           |
| Report is missing columns you expected                        | Only the fields you selected are computed; an unselected field is absent, not blank                                                                                                   | Re-select from the twenty fields in [SoD rule and policy reference](/administration-guide/reference/sod-rules-and-rule-sets.md#the-twenty-violation-report-fields) and regenerate |
| Report rows have far more segment columns than a policy needs | The header is sized by the widest policy in the system, not by the policies in the report                                                                                             | Expected; use the **Policy** filter in **Create SoD Report** to narrow the set                                                                                                    |
| A report seems to ignore a later certification decision       | The CSV is a point-in-time artifact, and campaign SoD context is snapshotted at build time                                                                                            | Compare the report's generation time with the decision and fulfilment times, read the current target access, then re-run detection and regenerate                                 |
| A review item shows no SoD context                            | The policy was inactive, or nothing had detected the conflict, when the campaign was built — `ACCESS_REVIEW_ITEM_SOD_VIOLATION` is written at build time and not refreshed afterwards | Confirm the policy is active and detection has run, then build a new campaign; an existing one will not acquire the context retrospectively                                       |
| An exemption has no review date and nobody remembers why      | `SOD_EXEMPTION` has no expiry column and nothing reminds anybody                                                                                                                      | Put the rationale and the review date in `COMMENT_TEXT`, and put the review itself in a certification campaign                                                                    |

## The violation lifecycle

A violation is not a workflow object with states — it is the presence of a (user, policy) pair in the index. It comes into existence, and it leaves. Four things end it.

| Stage                      | What happens                                                                                                                                                                                                                                                                         | Evidence                                                                                                                                        |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **Detected**               | Inline on save, or by a sweep. The user's document in the `user-violated-sod-policy` index gains a `sodPolicies` entry                                                                                                                                                               | `SOFT_` / `HARD_SOD_POLICY_VIOLATION_DETECTION` audit action; the user appears on the Violations tab                                            |
| **Notified**               | `SOD_VIOLATION_SOFT` or `SOD_VIOLATION_HARD` to the manager group, subject to the suppression rule on [SoD detection and violations](/administration-guide/governance/sod/sod-detection-and-violations.md#the-mail-templates) — a soft conflict notifies once, a hard one every time | The mail, and the audit entry's `SOFT_SOD_POLICY_VIOLATION` / `HARD_SOD_POLICY_VIOLATION` attribute, which carries the violation detail as text |
| **Triaged**                | Someone opens `/webconsole/user-sod-policy-violation?id=<USER_ID>`, reads which entitlements on which side, and picks an outcome                                                                                                                                                     | The **Is direct violation** column                                                                                                              |
| **Resolved by revocation** | **Delete selected** removes the conflicting entitlements                                                                                                                                                                                                                             | `DELETE_SOD_VIOLATIONS` audit action, target `USER`                                                                                             |
| **Resolved by exemption**  | **Allow selected** records a `SOD_EXEMPTION` for that user, policy and entitlement                                                                                                                                                                                                   | `ALLOW_SOD_VIOLATIONS` audit action, target `USER`                                                                                              |
| **Resolved by mitigation** | A `SOD_MITIGATING_CONTROL` is attached to the policy; the violation still exists but is documented as compensated                                                                                                                                                                    | `mitigatingControlIds` on the index entry; `SOD_POLICY_MC` row                                                                                  |
| **Cleared**                | The next detection finds no conflict; the entry is dropped, and the whole document deleted when no policies remain                                                                                                                                                                   | `SOD_VIOLATION_RESOLVED` mail to each formerly violated policy's manager group                                                                  |

Every stage above is reachable from the **Violations** tab: **Detect users** triggers a sweep, the tab itself lists the violating users, and clicking one opens that user's violations at `/webconsole/user-sod-policy-violation?id=<USER_ID>`, where the list can be narrowed to a single policy.

## Exemptions

An exemption is one row in `SOD_EXEMPTION`, scoped to a **single entitlement**, not to the policy as a whole — its columns are in [SoD rule and policy reference](/administration-guide/reference/sod-rules-and-rule-sets.md#the-tables).

Two constraints govern them. First, `SOD_POLICY.EXCEPTIONS_ALLOWED` must be `Y` — otherwise the screen answers `Exemptions are not allowed for this policy`. Second, that flag is not yours to keep: enforcing a rule set sets `EXCEPTIONS_ALLOWED = N` on every policy whose risk tag is `SOD_RISK_CRITICAL`. So a Critical conflict has **no per-user exemption path** by design — mitigate it or remove the access.

There is no expiry column. An exemption granted today is permanent until someone deletes the row, and nothing reminds anybody. Put the review date in `COMMENT_TEXT` and put the review itself in a certification campaign, because the product will not chase it.

## Mitigating controls

**Mitigating Controls** tab; edit at `/webconsole/mitigaring-control-edit?id=<SOD_MC_ID>` (the route is misspelled in the product — `mitigaring` — and the misspelling is what works).

A control records what the compensating measure is, who operates it (`MANAGER_TYPE` and `MANAGER_ID`, either a `USER` or a `GROUP`), who is accountable for it (`OWNER_TYPE` and `OWNER_ID`), how often it should be reviewed (`REVIEW_FREQUENCY`: `ANNUALLY`, `SEMI_ANNUALLY`, `QUARTERLY` or `MONTHLY`), and the window in which it applies (`EFFECTIVE_DATE`, `EXPIRATION_DATE`). It ships `ACTIVE = 'N'`.

The review frequency is a recorded attribute, not a scheduler — nothing in the product fires a reminder when a quarterly review is due, and `EXPIRATION_DATE` passing does not deactivate the control. Both are evidence for an auditor and inputs to your own calendar.

Link controls to policies through `SOD_POLICY_MC`. A linked control surfaces on the violation index entry as `mitigatingControlIds`, and the report can render the control plus whether the violating user is its manager or owner — which is the check that catches a "compensating control" operated by the person it is supposed to compensate for.

A control that a policy still links **cannot be deleted**. Remove the `SOD_POLICY_MC` row first, and only with the control owner's agreement, because the control is the recorded justification for every violation that was accepted on the strength of it — delete it and you have deleted the reason. For a control you no longer operate, set `EXPIRATION_DATE` and clear `ACTIVE`, then unlink it. Do not delete it to tidy the list.

## SoD in certification reviews

A certification campaign is the third way a conflict reaches a human, and the only one that reaches the person accountable for the access rather than the person administering it. When a campaign item is built, active SoD policies are evaluated against it and each conflict is written to `ACCESS_REVIEW_ITEM_SOD_VIOLATION` — the policy id and name, the severity, the risk name, the conflicting entitlement with its type, the policy threshold, the segment and its threshold, whether the violation is direct, and a resolved flag. The reviewer therefore sees the conflict **at the moment of decision**, which is the entire value of the integration.

Teach reviewers what their two buttons mean here, because it is not self-evident.

* **Approving** a conflicting item is a decision to **retain** the conflict. That is a legitimate answer only where a mitigating control is in place or an exemption has been approved. Otherwise the reviewer has just attested that a toxic combination is fine.
* **Revoking** starts remediation; it does not finish it. The decision still has to be fulfilled at the target and the user re-evaluated before the conflict is actually gone.

Prove on a test campaign that the expected SoD context appears on the item before you rely on certification as your response workflow.

### The reviewer's resolution preview

Opening a conflicting item gives the reviewer a **Resolve SoD Violation** dialog — *Review and remove entitlements to resolve this segregation of duties violation* — which is a live what-if rather than a list. Each segment is shown as **Triggered**, **Cleared** or **Inactive** against its own threshold, and as the reviewer ticks entitlements for removal the panel recalculates: the triggered-segment count moves from its current value to a projected one, the heading changes from **Select Entitlements to Remove** to **Policy Will Be Resolved** or **Violation Still Active**, and the confirm button reads **Confirm Removal (n) — Will Resolve** only when the projection actually drops below the policy threshold. Nothing is submitted until they confirm.

The alternative is **Skip this policy — delegate to next approver**, and reviewers should be told what it costs before they meet it: skipping approves *every* entitlement in the policy — *By skipping this policy, you are approving all n entitlements listed below without resolving the violation* — and hands the policy to the next approver in the workflow. Entitlements approved that way are locked for later reviewers, who see **Approved (Skipped)** and cannot revoke them at their step. A skip is therefore a decision to retain the conflict for the whole review, not a way to defer one.

### The campaign snapshot boundary

A campaign is **not** a live query. Certification stores denormalized user and access data captured during preview and launch, and `ACCESS_REVIEW_ITEM_SOD_VIOLATION` is snapshotted at build time. Some open, untouched risk fields can be refreshed, and revoking an item can re-evaluate and auto-resolve the related campaign SoD record, but none of that makes every displayed field a current view of the target system.

This matters most when a SoD report was generated and a review decision changed the access afterwards. Do not read the original report row as the current state, as a pending revocation, or as the latest decision. For every audit decision, retain four timestamps and the state at each:

| # | Retain                                                                                 | Why it is not one of the others                                          |
| - | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| 1 | When the SoD dataset or campaign preview was **generated**                             | Fixes the population, the policies and the mappings the finding rests on |
| 2 | The access and the conflict **recorded** at that point                                 | The finding itself, which must never be overwritten by a later state     |
| 3 | The later review **decision** and its fulfilment state                                 | Approve or revoke, and whether the target actually changed               |
| 4 | The **current** target and effective-access state after provisioning and re-evaluation | Closure — and the only one of the four that goes stale                   |

Report those as separate columns rather than overwriting history. Before declaring a conflict open or closed, re-run detection or the report, read the current access-review item, and check the target account. If the deployed version does not show active review actions beside the original SoD row, that is a product boundary, not evidence that no remediation is under way.

## The violation report

**Reports** tab → **Generate New Report**, which opens **Create SoD Report** (audit action `GENERATE_SOD_REPORT`). Set **Report Name**, optionally narrow with **Policy**, **Severity** (`SOFT` or `HARD`) and **Risk** under *Filters (optional)*, and choose the **Report Fields** in the order you want the columns. At least one field is required — the dialog answers *"At least one report field must be selected"* — and **Generate** confirms with `SoD report generation started`. The tab then lists every generated file by **Name** and **Last Modified Date** for download. The twenty selectable fields and how the segment columns are built are in [SoD rule and policy reference](/administration-guide/reference/sod-rules-and-rule-sets.md#the-twenty-violation-report-fields).

The output is **CSV**, with every field quoted, written to the directory named by `org.openiam.sod.reports.directory`, which ships as `${confpath}/upload/sod/reports/`. That is a deployment property rather than a `SYS_PROP` row, so you will not find it under **Administration → System Configuration** and cannot read its live value from the Webconsole; the report list on the screen is the observable proof that OpenIAM can write there. Generation is guarded by a cluster-wide lock per report name, so a duplicate request is skipped with a warning rather than producing two files. The file is built as `<name>_MM_dd_yyyy_HH_mm_ss.csv.processing` and atomically moved into place on success, so a half-written report never appears in the list. Violations are paged 500 at a time.

### Reporting views by audience

One CSV does not serve four readers. Choose the fields for the audience, and reconcile the row count against the Violations tab for the same detection state before you send anything to anybody.

| Audience                 | Include at minimum                                                                                                                                                                                 |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Operations**           | User or identity, the policy, the conflicting segment entitlements, the authoritative source of each grant, the assigned owner, current status and a due date                                      |
| **Process owner**        | The business risk and the conflicting business tasks in their own vocabulary, the user's job context, and the proposed removal or control — not entitlement ids                                    |
| **SAP security**         | The SAP system and client, the account, the direct and composite role paths, the transactions involved, and the result of validating the relevant authorization objects                            |
| **Audit and compliance** | Rule set, policy and version; detection and report timestamps; severity and risk; the decision and its approver; fulfilment; proof at the target; the exemption or mitigating control; and closure |

The audit row is the demanding one, and three of the twenty fields exist for it specifically: the mitigating control, and whether the violating user manages or owns it. The SAP row is the one the product cannot fill on its own — authorization-object values are not modelled in OpenIAM, so that column is a human answer from the SAP security owner. See [SAP role and SoD analysis](/administration-guide/governance/sod/sap-sod-analysis.md).

Two habits keep these reports defensible. Name reports after the control and the period, not after the day you ran them, so the same control produces a comparable artifact every cycle. And never overwrite a previous row: report the original conflict, the decision, the fulfilment and the current state as separate columns, because an auditor's question is almost always about the gap between two of them.

## Related

* [SoD detection and violations](/administration-guide/governance/sod/sod-detection-and-violations.md) — the inline check, the population sweep, the schedule and the digest that puts this list in front of you
* [SoD policies and rule sets](/administration-guide/governance/sod/sod-policies-and-rule-sets.md) — policies, segments, thresholds, the enforcement ladder and the severity override
* [SAP role and SoD analysis](/administration-guide/governance/sod/sap-sod-analysis.md) — what the SAP security owner has to validate that OpenIAM cannot
* [Operate a live campaign](/administration-guide/governance/certification/operate-a-live-campaign.md) — working a live campaign, and why a revocation is end-dated rather than deleted
* [SoD rule and policy reference](/administration-guide/reference/sod-rules-and-rule-sets.md) — the twenty report fields, the exemption and mitigating-control columns
* [Audit actions and retention](/administration-guide/reference/audit-actions-and-retention.md) — every audit action named on this page, and what is pruned

*Applies to OpenIAM 2026.8.1. Last reviewed 7 August 2026.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/administration-guide/governance/sod/sod-triage-remediation-and-evidence.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
