A policy is a rule NHI Security holds your estate to. An evaluation applies every runnable policy to everything a connector has reported and writes the findings. Risk is derived from the findings that are still open. Nothing in this chain is a score the product invents: every number traces to a finding, and every finding traces to evidence a connector recorded.

The policy catalogue

The catalogue is fixed in the product. You can switch a policy off and retune its parameters; you cannot write a new one, and you cannot delete one. Twenty-six policies ship. All are enabled by default except agent_invocation_rate_anomalous.

Identity and credential policies

Activity policies

These need activity_events, which no connector collects. See Activity and exposure policies.

Agent policies

Twelve further policies — unowned_agent, agent_autonomy_undeclared, unsupervised_agent_mutates, agent_tool_reaches_high_impact, agent_tool_effect_unknown, agent_credential_shared, agent_acted_outside_its_tools, shadow_agent_unprofiled, agent_delegated_authority_unowned, agent_delegates_to_agent, agent_lineage_unknown and agent_invocation_rate_anomalous — hold AI agents to rules about ownership, declared autonomy, the tools they may use and who they act for.
No connector discovers AI agents, so on an estate filled only by connectors these twelve policies have no subject. Those needing agent_inventory report as unavailable; the rest raise nothing. agent_lineage_unknown is unavailable on every estate, because no adapter produces the lineage edge it needs. shadow_agent_unprofiled cannot raise a finding at all: its only outcomes are pass and not assessable. See Limitations.

Reading and tuning a policy

GET /api/v1/policies returns the whole catalogue with your organization’s overrides and each policy’s availability; GET /api/v1/policies/{policyKey} returns one. Both need policy:read, which every role holds. PUT /api/v1/policies/{policyKey} enables, disables or retunes one. It needs policy:manage — inside TRUSTIVAN, an Organization Admin. A parameter outside its range is refused with 422 and a per-parameter problem (unknown_parameter, not_a_number, not_an_integer, below_minimum, above_maximum); the rejected value is not echoed back. An unknown policy key is 404. Every policy can be switched off. None is mandatory.

Availability: what a policy needs before it can run

Each policy declares the facts it requires, drawn from a fixed list: identity inventory, identity ownership, identity usage, credential inventory, permission grants, resource classification, resource reachability, activity events, credential exposure, agent inventory, agent tool grants, agent autonomy, agent delegation and agent lineage. When no connected environment supplies a required fact, the policy is unavailable and names what is missing. It is not reported as zero findings.
An unavailable policy is skipped entirely. Findings it raised on an earlier run are not resolved, because nothing looked at them. If you disconnect the environment a policy depended on, its findings stay open until the facts come back and an evaluation clears them, or you close them by hand.
Availability is about the whole organization. A single subject the policy could not assess is reported separately as not assessable, with one of a fixed set of reasons and a plain-English explanation of what was missing. Those tallies appear on the evaluation run, not in the findings queue.

Evaluation runs

An evaluation opens a run, applies every runnable policy in batches, writes the findings, captures risk snapshots, and closes the run. GET /api/v1/policies/evaluations lists runs newest first, with policy:read.

What triggers one

  • A person, through POST /api/v1/findings/evaluate or Govern → Policies → Run evaluation. This needs policy:manage, so inside TRUSTIVAN only an Organization Admin can start one — a Security Analyst can triage findings but cannot run the evaluator.
  • A synchronization that collected something, automatically, straight afterwards. A run that collected nothing triggers nothing.
Evaluation is synchronous: the request returns when the run finishes. There is no queue and no evaluation scheduler, so a large estate can exhaust an HTTP timeout. Unattended evaluation happens only as a consequence of scheduled discovery, which is itself off unless the deployment enables it. See Discovery and synchronization.
Two refusals: 409 when a run is already in progress for your organization — enforced by a database constraint, not by a check that could race — and 422 when there is no identity inventory or no runnable policy. If evaluation throws, the run is recorded as failed, audited, and the error is returned to the caller.

Findings

A finding is one policy’s conclusion about one subject, with the facts that produced it. It is identified by the policy and the subject together, so re-running evaluation updates the same finding rather than creating a second one. Findings are never deleted.

Status

PATCH /api/v1/findings/{findingId}/status needs finding:manage — an Organization Admin or a Security Analyst. Setting resolved is refused with 422: that status is the evaluator’s reading of evidence, not an opinion. Setting the status it already has is 409. There is no route that creates a finding.

What an evaluation does to an existing finding

  • Still matches, and it was suppressed (risk_accepted, false_positive) — left alone.
  • Still matches, and it was resolved — reopened to open.
  • No longer matches — resolved, unless it is false_positive, which stays.
Every status change writes a history row with the previous status, the new one and who made the change. GET /api/v1/findings/{findingId}/history returns it, and /evidence returns the observations behind the finding.

Reading the queue

GET /api/v1/findings lists findings, sorted by severity, with finding:read. GET /api/v1/findings/summary gives the counts plus whether this organization has ever evaluated — so an empty queue on a never-evaluated organization does not read as a clean estate.
exposureId, resourceId and subjectKind are accepted by the list endpoint and currently have no effect on the results. Filter by identityId, credentialId, status, severity, policy, kind, provider, unownedOnly or actionableOnly instead.

Risk

Per identity

An identity’s severity is the highest severity among its open findings — not a band derived from its score. Its score is the sum of its open findings’ severity points, clamped to 0–100: Risk is computed when you read it, from the findings as they stand, so it cannot disagree with the findings page. Each contributing finding is shown with the score. GET /api/v1/findings/risk returns risk by identity; /risk/identity/{identityId}/comparison compares the live score with the most recent earlier snapshot.

Snapshots, history and posture

Every evaluation run captures a snapshot per identity that has at least one open finding — its score, severity and the findings behind it — and one organization-wide posture snapshot holding the findings by severity, the identities by risk band, how many subjects were not assessable and how many policies were unavailable. An identity with nothing open is omitted rather than written as a zero. GET /api/v1/findings/risk/posture returns the trend, up to 30 points by default and 180 at most. /risk/identity/{identityId}/history returns one identity’s snapshots, newest first. A trend point is improving, worsening, unchanged or no_comparison — band first, score as the tiebreak. A posture comparison is marked not comparable when the later run assessed less than the earlier one: if more subjects were skipped or more policies were unavailable, a lower finding count is a coverage change, not an improvement, and NHI Security says so rather than drawing an encouraging line.

Policy exceptions

An exception records that your organization has deliberately exempted a subject from a policy, with a justification, an owner and an end date. Request it with POST /api/v1/policy-exceptions (policy:exception:request — Organization Admin or Security Analyst); decide it with POST /api/v1/policy-exceptions/{id}/decision (policy:exception:approve — Organization Admin).
  • Exactly one scope: an identity, a credential, a resource or a team. There is no “everything”.
  • Duration is 1 to 90 whole days, and expiresAt is always set — no exception is permanent. Renewal is a new request, never an extension.
  • The approver must be a different person from the requester. The attempt is refused with 403 and recorded in the audit trail as a failure.
  • Withdrawing is the requester’s act; revoking is an approver’s, and needs a reason.
An approved, in-force exception is a governance record. It does not suppress the finding today: the finding still appears in the queue, still counts as open, and still contributes its points to the identity’s risk score. Nothing past the exception’s end date changes its stored state either — it simply stops being in force. See Limitations.

Remediation

A remediation action is a proposed fix, optionally linked to the finding that prompted it: revoke_credential, rotate_credential, disable_identity, remove_permission, quarantine_identity, decommission_identity, assign_owner, create_ticket or notify_owner.
  • Propose with POST /api/v1/remediation (remediation:propose — Organization Admin or Security Analyst).
  • Every action that would change something at the provider needs an approval, and the approver must not be the proposer.
  • The three irreversible kinds — revoking a credential, decommissioning an identity, removing a permission — need a dry run first.
  • Execution is additionally gated by a deployment setting and by having an executor for that provider. The summary reports whether execution is enabled at all.
  • A succeeded action of a reversible kind can be rolled back once.

Activity and exposure policies

Five activity policies and credential_exposed depend on facts no connector collects: what identities actually did, and where credential material has turned up. NHI Security does not pretend to have them — the policies report as unavailable and name the missing fact. Both facts arrive through ingestion endpoints instead, for a pipeline you run: Both permissions belong to the Organization Admin role inside TRUSTIVAN. Records that cannot be matched to the inventory are reported back as rejections with a reason rather than silently dropped, and each submission is recorded as an ingestion run you can list.
NHI Security has no API keys of its own. Every request is authenticated by your TRUSTIVAN session, except the runtime gate, which uses its own bearer credentials. A pipeline that ingests activity has to carry a session, which makes this an integration to plan rather than a header to set. See Limitations.