Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 193 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Product Docs

Loading...

Introduction

Loading...

Loading...

Loading...

Concepts

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Installation

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Configuration

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Welcome

CISO Assistant

CISO Assistant — Product Documentation

CISO Assistant is an open-source GRC (Governance, Risk and Compliance) platform — a different take on cybersecurity posture management, built on a few load-bearing ideas:

  • Explicitly decoupling compliance from security-operations implementation.

  • Providing simplified tools for decision-making.

  • Assessing a program, product, or whole organisation against standard frameworks.

  • Letting you bring your own framework via a simplified DSL.

  • Acting as a one-stop shop for the Governance, Risk, and Compliance layers.

  • Introduction — design philosophy and vocabulary.

  • Concepts — the central objects you work with: domains, perimeters, applied controls, assets, assessments, risks.

  • Installation — getting CISO Assistant running.

  • — recorded demos and walkthroughs.

  • — subscription tiers and what's included.

  • — feature-by-feature comparison.

Configuration — organisation setup, IAM, SSO, and customisation.
  • Features — a catalogue of shipped capabilities.

  • Guides — task-oriented walkthroughs, both onboarding and ongoing operations.

  • AI and Integrations — the REST API, the MCP server, and third-party integrations.

  • Contributing — how to extend CISO Assistant and improve this documentation.

  • — partner programme for integrators and resellers.
  • — release notes and product news.

  • What's inside

    More from intuitem

    Replays
    Pricing
    Community vs PRO
    One hub for governance, risk, and compliance
    Partnership
    Blog

    Philosophy

    CISO Assistant is built around a small set of design principles. A lot of object boundaries, naming choices, and workflow shapes only make sense once you have these in mind.

    Applied controls at the centre

    The applied control is the unifying object in CISO Assistant. Everything the organisation does to manage risk and prove compliance is captured as an applied control — a technical safeguard, an organisational process, a documented policy, a tested recovery plan. Once that's in place, the rest of the platform connects to it:

    • An audit assesses requirements; each requirement assessment links to the applied controls that satisfy it.

    • A risk scenario lowers its current and residual levels by attaching the applied controls in place and planned.

    • A task records that an applied control was actually exercised on a given date and produces the evidence to prove it.

    • Evidence lives on an applied control — and through it, substantiates every requirement and scenario the control supports.

    • An incident response invokes applied controls; a vulnerability is mitigated by them; a policy is one.

    Authoring an applied control once and reusing it across all the places it applies — instead of redoing the same work per audit, per risk study, per framework — is the productivity gain that justifies the whole architecture.

    The corollary of putting applied controls at the centre is that everything around them must be decoupled, so that one applied control can serve many consumers without being rewritten for each:

    • Security controls are decoupled from compliance requirements — a single applied control can satisfy many requirements across many frameworks.

    • Risk assessments are decoupled from frameworks — the same risk scenario can inform multiple compliance audits.

    • Assets are decoupled from threat scenarios — assets exist independently of any specific risk study and can be reused across them.

    The payoff is reuse, end-to-end. One applied control answers many requirements. One assessment covers many frameworks. One asset participates in many scenarios. One evidence file substantiates everything the underlying control supports.

    Decoupling principle

    Community vs PRO

    How the Community and PRO editions differ, how contributor seats are counted, and where each edition can run

    CISO Assistant ships in two editions:

    • Community — the open-source edition, free to use, with the platform's core GRC capabilities. Self-hosted only.

    • PRO — the commercial edition, built on top of Community, adding enterprise features (sub-domains, focus mode, advanced insights, custom roles, validation flows, and more) plus official support.

    A full feature-by-feature comparison lives on the — we keep the matrix there so it stays in sync with pricing and release cycles. This page is here to explain the commercial concepts that intersect with the platform itself: contributor seats and where PRO runs.

    PRO is licensed by contributor seats — the number of users in your instance who can actually make changes.

    A user counts as a contributor as soon as they have any create / edit / delete permission anywhere in the platform — that is, any role that grants add_…, change_…, or delete_… rights. Concretely, the typical contributor is someone with the Analyst, Domain Manager, or Administrator role (or a custom role that confers similar write rights). Read-only users — anyone whose role only grants view_… permissions — do not consume a seat.

    Two narrow categories of users are explicitly excluded from the seat count, even though they may perform meaningful work in the platform:

    • Pure approvers — a user whose only write capability is signing off on a . In practice this is the built-in Approver role: its single write permission, change_validationflow, is registered as a non-seat permission. If the same user also holds any other write right (e.g. they're an Analyst who happens to be an approver too), the seat is still counted — being an approver doesn't subtract from the count, it just doesn't add one on its own.

    • External third-party representatives — vendor-side users who log into the to fill in entity assessments. They are flagged as external (is_third_party) and are systematically excluded from the count regardless of which write permissions their role grants.

    The intent behind the two exceptions is narrow: the seat count tracks internal contributors authoring and maintaining your GRC content, while sparing two patterns where counting would feel punitive — pure sign-off workflows, and external vendors who don't belong to your organisation in the first place.

    The instance compares the number of contributors against the seat allowance carried by your license. The current count is visible from About CISO Assistant, opened via the three-dot menu next to your name in the sidebar footer — so you can see at any time how many seats are used and how many are available.

    PRO is available on both deployment models, and the feature set is identical between them:

    • On-premises — you host the platform on your own infrastructure (Linux VM, Kubernetes via the , or any of the deployment methods documented under ). Your data stays in your network. This is the right model when sovereignty, air-gapping, or strict residency requirements rule out a managed service.

    • SaaS — intuitem hosts and operates a managed instance for you. No infrastructure to run, automatic upgrades, backups handled. The right model when you'd rather focus on the GRC programme than on running a Django application.

    You can move between the two models — there's no architectural difference, and the data formats (domain exports, library YAML, audit exports) are stable across deployments.

    For organisations that don't want to track individual seats — typically large enterprises, MSSPs, public-sector deployments, or any environment where contributor headcount fluctuates often — both the on-premises and SaaS editions are available with an unlimited plan. Under an unlimited plan, the platform doesn't enforce a seat count and you don't need to manage role assignments around license limits.

    A SecNumCloud version is also available, with dedicated hosting under the highest available cloud-security qualification. It is offered in unlimited mode. See the for details.

    • — current plan tiers and what each includes.

    • — the full feature comparison.

    • — the governance object whose approvers don't consume a seat.

    — the auditee surface used by external representatives, who also don't consume a seat.

    Contributor seats

    Exceptions — who doesn't count

    Internal users helping fill in an audit do consume a seat. This includes anyone in your own organisation who is assigned to answer requirements via the feature — most typically users carrying the built-in Respondent role, but also any internal teammate whose role grants write access to requirement assessments and evidences. The third-party exception above applies only to vendor representatives reaching the platform through the external auditee surface.

    How the count is enforced

    Where PRO runs

    Unlimited plans

    SecNumCloud

    Related

    Community vs PRO page on the intuitem website
    validation flow
    third-party auditee surface
    Helm chart
    Installation
    pricing page
    Pricing
    Community vs PRO
    Validation flows
    Third-party risk
    Assignment/Respondent mode

    Domains

    A domain is a top-level container in CISO Assistant. It represents an organisational scope — a business unit, a subsidiary, or any boundary you want to manage access and reporting around.

    Domains are the platform's primary mechanism for access control and reporting boundaries: a user's roles are granted on a domain, and most reports, dashboards, and audit roll-ups can be filtered by domain.

    Building a hierarchy

    A domain can have a parent domain (parent_folder internally) — that's how you build a tree of sub-domains beneath a top-level one. The hierarchy lets you mirror the shape of your organisation in the platform: a "Group" domain on top, "Region" or "Subsidiary" domains beneath, "Business unit" or "Programme" domains beneath those, and so on.

    When a parent-child relationship is in place, two things follow:

    • Permissions can flow downward. A user with a role on a parent domain can be configured to see and act on objects in its sub-domains, without re-assigning them at every level.

    • Reporting can roll up. Dashboards and analytics aggregate across a domain and its descendants, so leadership-level views work the same way the org chart does.

    The root is reserved for global, cross-organisation objects (built-in catalogues, the global library) — your own domains always live one level under it, even when no other hierarchy is in place.

    Not every domain needs to be an IAM boundary. Sometimes you want a domain purely as an organisational container — a folder in the tree to group related work — without the platform spinning up the per-role user groups that come with a "real" scoping domain.

    The Create IAM groups checkbox on the domain form controls this:

    • On (default for new domains) — the platform auto-provisions one user group per role for the domain. Anyone who needs access to objects in this domain gets placed into one of those groups; the domain is a true IAM scope.

    • Off — no user groups are created. The domain exists in the tree, can be picked from selectors, and can host objects, but it carries no scoping machinery of its own. Access flows from whatever parent domain it sits under.

    Turn the flag off when you want sub-domains that are just structure — for example, breaking a "Subsidiary" domain into a "2025 audits" / "2026 audits" tree purely for organisation, without giving each year its own IAM surface. The setting is shown by the on-form help text: "IAM groups are used to assign roles to users."

    The flag is not a one-way choice. You can flip it on a domain at any time — turning it on later provisions the per-role user groups, turning it off later removes them. So a domain you initially created as a pure folder can later become a real IAM scope (or vice versa) without recreating it or moving its content.

    The hierarchy is not frozen at creation. Editing a domain lets you change its Parent domain (PRO), which moves the whole sub-tree — the domain itself and every domain beneath it — under the new parent. Use this to:

    • Reorganise as your business changes (a programme becomes a subsidiary, two business units merge).

    • Promote a sub-domain to top-level by setting its parent back to the root.

    • Re-parent for IAM reasons (giving a parent role-holder access to a sub-tree that wasn't previously under them).

    The platform prevents cycles — you can't move a domain under one of its own descendants — but everything else is reachable.

    Almost every operational object in CISO Assistant is bound to a domain: assessments and audits, applied controls, evidences, risk scenarios, assets, tasks, policies, findings, incidents, exceptions, contracts, entities, and so on. The domain a record lives in is what drives who can see it and how it rolls up in reports.

    Because reorganisations happen, the domain assignment is not permanent:

    • One at a time — edit any object and pick a different Domain in the form. The platform re-evaluates IAM scoping on save, so the object disappears from one domain's views and appears in the other's.

    • In bulk — for models that opt in to bulk operations, the toolbar exposes a Change folder action: select multiple rows in the table, choose the destination domain, and the move is applied across the selection in one go. Useful when reorganising a subsidiary into its own sub-tree, or pulling a programme's controls into a dedicated domain.

    A handful of objects whose domain is forced by a parent (e.g. risk scenarios always inherit their risk assessment's domain) intentionally don't expose the batch Change folder action — moving the parent moves the children.

    • — how users, teams, and entities get scoped to a domain

    Sub-domains are an Enterprise (PRO) feature. The community edition ships with a flat structure — every domain you create sits directly at the root. The Parent domain field on the domain form is only exposed in the Enterprise edition, where you can nest domains to whatever depth you need to mirror your organisation.

    Organisational-only domains — the "Create IAM groups" flag

    Restructuring the tree

    Objects move between domains

    Related

    batch actions
    Perimeters
    Actors and teams

    Vocabulary

    A glossary of the terms used in CISO Assistant. Where a user-facing term differs from the internal model name, both are given.

    A

    • Accreditation — Formal authorisation that a system, environment, or product has met security and compliance requirements. Captured as an object in project-management workflows, often required for go-live.

    • Actor — The unifying handle for anyone who can own or be assigned work in CISO Assistant. An actor wraps exactly one of three underlying objects: a User, a Team, or an Entity. Auto-created when its underlying object is created — not managed directly. See Actors and teams.

    • Applied control — The main building block of the action plan: a concrete action your team has implemented or will implement. It can be technical, organisational, a process, a policy, a piece of documentation — anything that materially changes risk or compliance posture. Applied controls are always defined by the organisation and can be attached to the global domain or to a specific domain. They may derive from a reference control for consistency, or be created independently.

    • Asset — Anything of value worth protecting. Primary assets are core resources directly contributing to the organisation's main objectives (business processes, data, intellectual property). Supporting assets indirectly aid primary functions (IT systems, services, locations, people).

    • Asset assessment — A per-asset row inside a business impact analysis, capturing recovery posture (documented, tested, targets met), associated controls, evidence, and the escalation thresholds that describe how impact grows over time.

    • Assessment — Umbrella term covering audits (compliance work), risk assessments, business impact analyses, and entity assessments.

    • Attack path — In EBIOS RM, the route an attacker may take from a starting point — through stakeholders or supporting assets — to reach a target objective.

    • Audit — The evaluation of a perimeter against a framework, producing a per-requirement view of status, score, and evidence. Internally a ComplianceAssessment.

    • Audit log — Append-only record of significant actions taken in the platform (creations, edits, permission changes, logins). PRO feature.

    • Auditee mode — A read-only UX mode aimed at external assessors who need to inspect an audit without being granted full access to the platform. Gated by the auditee_mode feature flag.

    • Business impact analysis (BIA) — A structured assessment of the operational, financial, and reputational impact of disruption to specific assets or business processes. Outputs feed into resilience planning.

    • Campaign — An orchestration object for running many audits in parallel — for example, one audit per perimeter against the same framework. PRO feature.

    • Catalog object — A reusable building block of CISO Assistant: framework, threat, risk matrix, reference control, mapping, security advisory, CWE. Catalog objects are packaged into libraries.

    • Compliance assessment — Internal model name for an audit. See Audit.

    • Dashboard — A configurable view of metrics and progress indicators, scoped to a perimeter or a domain.

    • Data breach — In a privacy register, an incident affecting personal data, with notification status and response actions.

    • Data contractor — A third party involved in a processing as data processor, sub-processor, or joint controller. Distinct from a generic supplier entity — captures the privacy-specific role.

    • EBIOS RM — The French ANSSI risk-management method, supported natively in the platform as its own object graph (studies, feared events, stakeholders, strategic and operational scenarios, kill chains).

    • Elementary action — In EBIOS RM, an atomic step an attacker can perform. Composed into operating modes.

    • Entity — Scope of an external review — typically a vendor or third party.

    • Feared event — In EBIOS RM, the undesirable outcome to be avoided on a primary asset — for example, a confidentiality breach of customer data.

    • Filtering label — A free-form tag that can be attached to most objects for categorisation, filtering, and reporting.

    • Findings assessment — A formal record tracking issues raised by an audit, a security review, or an external assessor, used to drive remediation through to closure.

    • Generic collection — A flexible grouping object in project-management workflows: a "bag" of related items that doesn't fit a more specific schema.

    • Incident — A security or operational event being investigated or tracked. Distinct from a risk (potential) or a vulnerability (weakness).

    • Inherent risk — The natural risk level of a scenario without any applied controls. The top tier of CISO Assistant's three-tier model — useful for ranking scenarios by their underlying severity, independently of the mitigation already in place. Surfaced in the UI when the inherent_risk feature flag is on.

    • Journey — An instance of a applied to a domain. Carries the scaffolded objects created at apply time and a step list with per-step statuses, notes, and completion timestamps. See .

    • Journey step — One row of work inside a journey: a title, description, optional pointer to a target object or internal route, and a status (not started, in progress, done, skipped).

    • Kill chain — In EBIOS RM, an ordered sequence of attacker steps culminating in the target objective.

    • Library — Container object bundling one or more catalog objects (frameworks, matrices, threats, reference controls, mappings, security advisories).

    • Managed document — A document tracked through a controlled lifecycle (draft, in-review, validated, published, deprecated) and pinned to a parent object such as a policy. Each iteration is a .

    • Mapping — Based on the . Allows moving an assessment from framework A to framework B while reusing existing requirement assessments.

    • Metric definition — A reusable specification for a measurable indicator (formula, target, unit, scope). Defined once, instantiated per perimeter.

    • Operating mode — In EBIOS RM, a specific way an attacker can carry out an operational scenario, composed of elementary actions.

    • Operational scenario — In EBIOS RM, the detailed "how" of a strategic scenario — the assets touched, the steps taken, and the techniques used.

    • Organisational issue — A documented context element describing an internal or external problem affecting the organisation.

    • Perimeter — A scoped subset of a domain that an audit or risk assessment applies to. Unlike a domain, a perimeter does not enforce role-based access control. Perimeters were previously called "Projects".

    • Personal access token (PAT) — A long-lived authentication token a user can issue from their profile to authenticate API calls. Alternative to session-based login; used by scripts, integrations, the CLI, and the MCP server.

    • Personal data — In a privacy register, any data referring to an identified or identifiable individual.

    • Quantitative risk hypothesis — A parameter set (loss-event frequency, magnitude distribution) feeding a quantitative risk scenario.

    • Quantitative risk scenario — A scenario inside a quantitative risk study, evaluated via Monte-Carlo simulation over loss distributions.

    • Quantitative risk study — A risk study using quantitative methods rather than a risk matrix. Sibling to qualitative risk assessment and EBIOS RM.

    • Recap — The roll-up view of a business impact analysis, aggregating asset assessments and their escalation thresholds into a single readout.

    • Recovery target — A documented commitment for restoring an asset after disruption, typically a Recovery Time Objective (RTO) or Recovery Point Objective (RPO). Tracked on an asset assessment as "documented", "tested", and "targets met" flags.

    • Reference control — A template for an applied control. Provided by frameworks via libraries, or defined locally. Optional but recommended for keeping applied controls consistent across the organisation.

    • Security advisory — A catalogued security warning published by a vendor or CERT (e.g. CVE entries). Linked to vulnerabilities and affected assets.

    • Security exception — A documented, time-bound deviation from a control or policy, approved through a workflow and tracked for review.

    • Severity — The shared ordinal scale used to qualify vulnerabilities, incidents, and findings: undefined / info / low / medium / high / critical. Drives SLA escalation and visual emphasis in dashboards.

    • Task definition — A reusable specification of a task: default assignee, owner, recurrence rule, expected evidence. Defining a task creates one or more task occurrences over time. Internally a TaskTemplate.

    • Task node — Internal model name for a task occurrence. See Task occurrence.

    • Task occurrence

    • URN — Uniform Resource Name. A unique identifier used to link to catalog objects across libraries.

    • User — A person with an account on the platform.

    • User group — A combination of a role and a domain, on which you place users. Auto-created when a domain is created.

    • Validation flow — A configurable approval workflow that mirrors an organisation's internal review or management-approval process — peer-review, sign-off by a security lead, formal acceptance by a steering committee. Attached to objects whose state changes warrant such review (e.g. risk acceptance, audit close-out), it captures the human approval step inside the platform rather than enforcing it as a hard technical gate.

    • Vulnerability — A weakness in a system or process that could be exploited by a threat. Tracked with severity, status, and linked applied controls.

    • Webhook endpoint — A registered URL CISO Assistant calls when configured events happen (e.g. an audit closed, an applied control updated). Used to notify external systems and trigger downstream automation.

    Contract — A third-party agreement attached to a supplier entity or solution, with terms, dates, and renewal information.

  • Control — Generic term. Disambiguate against applied control (concrete instance) and reference control (template).

  • Current risk — The risk level given the applied controls already in place — the state of risk today. The middle tier of CISO Assistant's three-tier model: inherent (no controls) → current (existing controls) → residual (existing + planned controls).

  • Custom field (also custom attribute) — An organisation-defined attribute that can be attached to platform objects (projects, risks, assets, suppliers, contracts, and more) to capture typed, filterable, searchable metadata beyond the built-in fields.

  • CWE — Common Weakness Enumeration. A catalogued category of software weakness, used to tag vulnerabilities and security advisories.

  • Data recipient — A party (internal team, external service, public body) that personal data is disclosed to as part of a processing.

  • Data subject — The category of individuals whose personal data is processed (customers, employees, prospects, etc.). Surfaces in the privacy register and right-request workflows.

  • Data transfer — A record of cross-border or cross-entity movement of personal data, with destination, legal basis, and safeguards.

  • Document revision — A single revision of a Managed document. Carries a version number and a lifecycle status (draft → in review → change requested → validated → published → deprecated).

  • Domain — The top-level container in CISO Assistant: a business unit, subsidiary, project, or any boundary used for organising work and isolating permissions via role-based access control. Sub-domains nest underneath. Internally a Folder. Demo and Starter are reserved for internal features.

  • Entity assessment — The actual review of an entity. Can trigger or be linked to an audit.

  • Escalation threshold — A point-in-time / impact pair attached to an asset assessment inside a BIA: "after 4 hours of outage, impact is high". Lets a BIA model how disruption escalates rather than recording a single worst-case impact.

  • Evidence — A document, screenshot, configuration sample, or any other artifact attached to an applied control or requirement assessment to substantiate compliance.

  • Evidence revision — A single versioned iteration of an evidence object. Replacing an attachment creates a new revision rather than overwriting the previous one; revisions carry a version number, an SHA-256 integrity hash, optional observation, and a link to the task occurrence that produced them when applicable.

  • Focus mode — A workspace mode that filters the entire UI to a single domain, hiding objects belonging to other domains. PRO feature.

  • Folder — Internal model name for a domain. See Domain.

  • Framework — A set of requirements covering patterns and expectations needed to comply with a regulation, prepare a certification, or establish a foundation. Shipped as a YAML library.

  • Metric instance — A concrete sample of a metric definition for a given scope at a given point in time.

    Organisational objective — A documented strategic or operational goal of the organisation.

    Policy — A specific type of applied control: a document describing what is expected from some part of your stakeholders. Lives in CISO Assistant so its lifecycle can be managed alongside the rest of your controls.

  • Preset — A reusable template describing a guided workflow: a set of starter objects to scaffold (audit, risk assessment, etc.) plus an ordered list of steps to follow. Library-backed or authored locally; applied to a domain to produce a Journey.

  • Processing — In a privacy register, an activity that operates on personal data (collection, storage, transfer, deletion). Captures purpose, lawful basis, recipients, and retention.

  • Processing nature — A catalogued type of processing operation (collection, storage, transfer, disclosure, deletion, …) used to characterise a processing.

  • Project — In the project-management module, a planned initiative with deliverables and milestones. Distinct from the legacy meaning of "project" in older CISO Assistant documentation — see Perimeter.

  • Purpose — In a privacy register, the lawful reason for which personal data is processed.

  • Representative — The person responsible for answering the questionnaire or requirements of an entity assessment.

  • Requirement — A single normative statement inside a framework.

  • Requirement assessment — The evaluation of one requirement inside an audit (status, score, evidence, applied controls).

  • Requirement mapping set — Internal model name for the catalog object backing a mapping library. See Mapping.

  • Residual risk — The risk level expected once all planned applied controls have been implemented — the target state of the action plan. The bottom tier of CISO Assistant's three-tier model (inherent → current → residual), and the figure used as input to risk-acceptance decisions.

  • Responsibility matrix — An assignment of actors to activities, used in project workflows and accreditation processes. Supports RACI, RASCI, and RAPID conventions.

  • Responsibility role — The role attached to an actor on an activity inside a responsibility matrix (e.g. R/A/C/I in RACI, or R/A/S/C/I in RASCI). Defined per matrix.

  • Right request — In a privacy register, a data-subject request under GDPR or equivalent (access, rectification, deletion, portability).

  • Risk acceptance — Formal record of an organisation's decision to tolerate a residual risk without further treatment. Carries an approval workflow; approval requires the Approver role.

  • Risk assessment (also risk study) — A scenario-based evaluation of risk over a perimeter.

  • Risk matrix — A configurable lookup table that derives risk level from probability and impact. Imported from a library. The matrix is fixed per risk assessment once the assessment is created.

  • Risk scenario — A building block of a risk assessment: combines threats, assets, and existing controls into a story whose probability and impact can be evaluated.

  • Role — A bundle of permissions. Four built-in roles ship with the platform; PRO editions also support custom roles.

    • Domain Manager — can set up and access everything on a domain.

    • Analyst — can input and read data, but cannot change a domain's settings.

    • Reader — read-only on the domain's items.

    • Approver — can validate workflows on objects for a domain (e.g. risk acceptance).

  • Role assignment — The attachment of a user (or user group) to a role within a domain. The unit of access control.

  • RO/TO couple — In EBIOS RM, the pairing of a Risk Origin (who attacks) with a Target Objective (what they want). The seed for strategic and operational scenarios.

  • Solution — A product or service provided by an entity.

  • Stakeholder — In EBIOS RM, an internal or external party with a relationship to the studied system. Evaluated for trust level and dependency.

  • Strategic scenario — In EBIOS RM, the high-level "what" of an attack: a Risk Origin, a Target Objective, a path through stakeholders, and an outcome.

  • — A scheduled instance of a task definition, with a due date, a status (pending → in progress → completed/cancelled), and the evidence collected when the task ran. Internally a
    TaskNode
    .
  • Task template — Internal model name for a task definition. See Task definition.

  • Team — A named grouping of users used for collaborative ownership of objects, with a leader, optional deputies, members, and an optional team email for notification routing. Distinct from a User group (which is role-scoped to a domain — see the disambiguation in Actors and teams).

  • Terminology — An organisation's overrides to the platform's default labels, used to align the UI with internal vocabulary.

  • Threat — A catalogued source of harm — reusable across scenarios. Optional: assessments can be performed without referencing threats explicitly.

  • B

    C

    D

    E

    F

    G

    I

    J

    K

    L

    M

    O

    P

    Q

    R

    S

    T

    U

    V

    W

    Preset
    Journeys
    Document revision
    OLIR initiative

    Foundations

    Perimeters

    A perimeter is an optional scope refinement an assessment or risk study can be attached to, inside a domain. Where a domain defines who owns the work and what they can see, a perimeter narrows the assessment to exactly what is being assessed — a product, a system, a process, a contract.

    Perimeters are optional everywhere they appear: an assessment without a perimeter is scoped to its domain only. Use them when you need to track several distinct scopes inside the same domain, or to roll up assessments by scope rather than by domain.

    When to use a domain vs a perimeter

    The two concepts solve different problems — and the choice matters because it shapes both who can see what and how reports roll up.

    • Use a domain (or a sub-domain) when the boundary needs to enforce IAM scoping or anchor reporting. Domains are where roles are granted, where permissions stop, and where dashboards aggregate. Pick a domain when different teams must have different levels of access, or when leadership wants to see one number per business unit / subsidiary / regulated entity.

    • Use a perimeter when the boundary is purely logical, inside an already-scoped domain. Perimeters split the work into distinct named scopes — a product, a system, a process, a contract — so you can run separate audits or risk studies against each without spinning up extra IAM machinery. Everyone with access to the domain sees every perimeter inside it; there's no per-perimeter access control.

    A useful mental check: "Do these two scopes need different people seeing them?" — if yes, they're domains (or sub-domains). "Do these two scopes need separate assessments but the same audience?" — they're perimeters.

    Related

    Domains
    Audits
    Risk assessments

    Catalog

    Actors and teams

    How CISO Assistant represents people, groups, and external parties for assignment and responsibility

    Almost every object in CISO Assistant has an assignee — the applied control someone is responsible for, the audit a team is running, the contract a supplier signs. The platform represents all these counterparties through a single abstraction: the actor.

    Mental model

    The actor is a one-to-one wrapper that always points at exactly one of three concrete records — a user, a team, or an entity (the three dashed edges are exclusive: a database check constraint enforces XOR). Every Assigned to / authorship / approver field on the platform (applied control assignee, audit author, task assignee, contract counterparty…) holds an actor, so a single code path resolves notifications and access regardless of the underlying type. Teams aggregate users via leader, deputies, and members — assigning to a team fans out to every user in it.

    User-facing
    Internal
    Notes

    An actor is the unifying handle for anyone who can be assigned to work in CISO Assistant. Every actor wraps exactly one of three concrete underlying objects:

    • A user — a person with a platform account.

    • A team — a named grouping of users for collaborative responsibility.

    • An entity — an external party from the third-party register (typical for contracts and entity assessments).

    The actor abstraction means the same Assigned to field on an applied control can hold a user, a team, or a supplier without the consuming code caring which it is. Notifications, emails, assignments, and reporting all go through the actor — they fan out to the right addresses regardless of the underlying type.

    Actors are created automatically when their underlying object is created. You don't manage actors directly; you manage users, teams, and entities, and the actor records follow.

    A team is a named grouping of users used for collaborative assignment — when the responsibility for something belongs to a working group rather than an individual.

    A team has:

    • A leader — a single user accountable for the team.

    • Deputies — users who can act in the leader's place.

    • Members — the broader group.

    Teams are first-class targets for assignments and notification routing. When work is assigned to a team, anyone with the appropriate role in the team's domain can act on it.

    These two are easy to confuse:

    • A team is a collaborative group with members, a leader, and deputies. It's about who works together. Teams are voluntary, organisational, and can span any domain.

    • A user group is a (role, domain) pair on which users get placed. It's about what permissions someone has where. User groups are auto-created when a domain is created — one per role per domain.

    You join a team for collaboration. You're placed in a user group for access. Both can carry users; they answer different questions.

    • Applied controls are assigned to one or more actors.

    • Requirement assessments can be assigned to an actor for completion.

    • Tasks are assigned to actors and notify them when due.

    Because all of these use the same actor handle, an audit log that says "assignee changed from team A to user B" is unambiguous, and the platform can resolve notifications the same way everywhere.

    • — where role-based access control happens

    An optional team email — used as the default notification address; if not set, emails fan out to the leader, deputies, and members individually.
    Risk scenarios are assigned to one or more actors.
  • Entity assessments have a representative (an actor of type user, tied to an entity).

  • Validation flows route approvals through actors.

  • Actor

    Actor

    XOR(User / Team / Entity); auto-created with its target

    User

    iam.User

    Platform account

    Team

    Team

    Leader + deputies + members

    Entity

    Actors

    Teams

    Teams vs user groups

    How actors are used across the platform

    Related

    Domains
    Vocabulary → Actor, Team, User, User group
    Add and manage users

    IAM and scoping

    How IAM, the domain hierarchy, publication, and cross-domain visibility shape what each user sees

    This page is the mental model for how access and visibility work in CISO Assistant. The full configuration-side deep-dive (SAML / OIDC / MFA / PATs / accounting) lives in ; this page focuses on the three things every user needs internalised before they can predict what they will and won't see on screen:

    1. Almost everything is bound to a domain.

    2. Permissions are inherited down the domain tree.

    Frameworks

    A framework is a normative body of requirements that audits are measured against — an industry standard (ISO/IEC 27001, NIST CSF, SOC 2), a regulation (NIS2, DORA, GDPR), a custom internal standard, or any other structured set of requirements.

    In CISO Assistant, frameworks are shipped as YAML libraries and are the foundation of every audit.

    A framework lives inside a loaded library and is read-only. It comprises a tree of requirement nodes — some assessable, some structural — linked parent-to-child via the self-loop. Creating an audit instantiates the framework: each assessable node becomes a requirement assessment inside the audit. Requirements can optionally suggest reference controls (templates for the applied controls that satisfy them), and a framework can be mapped to other frameworks for cross-walks.

    User-facing
    Internal

    tprm.Entity

    Third-party party

    User groups
    Teams

    Some objects are published — visible across the tree — and assessments are not.

    The combination of these three is what produces the most common "why am I seeing items from another domain here?" moment, which the last two sections explain and resolve.

    The platform's primary scoping unit is the domain (see Domains). Almost every operational object you create carries a domain — that's what drives who can see it and how it rolls up in reports.

    The list is long on purpose — to make the model concrete:

    • Compliance: audits / compliance assessments, requirement assessments, evidences.

    • Risk: risk assessments, risk scenarios, quantitative risk studies, EBIOS RM studies, business impact analyses, security exceptions.

    • Operations: applied controls, policies, tasks, incidents, findings, findings assessments.

    • Assets: assets, contracts, entities, solutions, representatives.

    • Privacy: processings, personal-data inventories, right requests, data breaches.

    • Project management: projects, accreditations, responsibility matrices.

    A small number of objects don't carry a domain because they're either system-wide (the user catalogue, the role catalogue, instance settings) or imported from a library catalogue. Everything else lives inside a domain.

    The domain hierarchy is not just for organising the UI — it actively shapes access. A role granted on a domain applies to every domain beneath it. Give a user the Analyst role on a parent domain, and they get analyst-level access to every sub-domain underneath, without re-assigning them at each level.

    This is why the tree shape matters as much as the names: putting "France" and "Germany" under a "EMEA" parent isn't decorative — it's the lever that lets EMEA-level managers see across both without granting them individual roles per country.

    Permissions only flow downward: a role on a sub-domain does not grant any access to the parent. If you need a role-holder to see across siblings, the role goes on the shared ancestor.

    The same inheritance also drives reporting: most dashboards and analytics roll up across a domain and its descendants, so a leadership-level view on the parent domain is automatically the consolidated view across its sub-tree.

    Some objects exist to be shared. Frameworks, threats, risk matrices, reference controls, and other catalogue-style items wouldn't be useful if they were trapped in a single domain — every team needs to be able to pull from the same shared library.

    CISO Assistant models this through a built-in flag — is_published — that any object can carry. An object marked as published is visible inside every sub-domain of its own domain, as if it had been attached to each one. Publication is a visibility mechanism only; it does not let users in other domains create, update, or delete the object.

    By default:

    • Catalogue-style objects (frameworks, threats, matrices, reference controls, libraries, terminologies, …) are published — they live "above" individual domains and are intended to be reused.

    • Assessments (audits, risk assessments, BIAs, entity assessments) are not published — they belong to a specific domain and stay there.

    The most common surprise this creates is when a user opens the platform and sees a library of frameworks or threats they "shouldn't" have access to. They aren't seeing them through a permissions hole — they're seeing them because the catalogue is published from a domain that sits above theirs.

    If you want to keep a specific object out of the published view, the simplest trick is to attach it to a leaf sub-domain (a domain with no children) — nothing inherits from a leaf.

    Assessments routinely compose objects across the tree. Risk assessments reference applied controls, threats, and assets; audits reference applied controls and evidences; findings assessments reference applied controls and the requirement assessments they remediate.

    When you're working inside one assessment, the platform's selectors and pickers don't just show you what's in the assessment's own domain — they show you everything you have access to. So a risk scenario authored inside the France domain can pull in:

    • A shared applied control attached to the EMEA parent domain (you can see it because of inheritance).

    • A threat from the global library (you can see it because it's published).

    • An asset attached to a sibling Germany domain (if your role gives you access there).

    This is by design — composing across the organisation is the whole point of a centralised GRC platform — but it can be disorienting on day one. The rule is consistent: you see what you have access to, regardless of which domain you started on.

    When you have access to many domains and you only want to think about one at a time, the platform exposes Focus mode (PRO, default off). Focus mode scopes the entire application — every list, dashboard, count, and search — to a single domain and its sub-tree, hiding everything else for the rest of your session.

    It does not grant or revoke permissions; it just filters the view. Use it when:

    • You operate across many client domains and want to work on one at a time.

    • Your organisation is large enough that the "all domains" view is overwhelming for day-to-day work.

    • You're running a demo or an onboarding and want the rest of the workspace out of the way.

    When focus is engaged, all the cross-domain composition described above is suppressed — you'll only see assets, controls, and assessments from the focused sub-tree. Clearing the focus restores the full cross-domain view.

    • Domains — domain hierarchy, IAM groups, restructuring, moving objects.

    • Actors and teams — who gets assigned what.

    • Understanding the IAM model — full configuration-side deep dive (SSO, MFA, PATs, accounting).

    • — the PRO tool for scoping back the view.

    • — how role assignments are actually stored and managed.

    Understanding the IAM model

    Everything is bound to a domain

    Inheritance — roles flow down the tree

    Publication — why catalogues appear across all domains

    Why you sometimes see items from other domains

    Managing the noise — focus mode (PRO)

    Related

    Notes

    Framework

    Framework

    Read-only catalog object

    Requirement

    RequirementNode

    Tree node (assessable or section)

    Library

    LoadedLibrary

    Active library bundle

    Audit

    A framework is a tree of requirement nodes. Most nodes are assessable — concrete requirements you evaluate one by one — while others act as section or chapter headings that organise the tree. Each assessable node becomes a requirement assessment inside an audit, carrying its own status, score, and evidence.

    Frameworks can define a default scoring scale with a minimum score, a maximum score, and optional level descriptions. For example, a CMMI-style framework may use 0..5, while another framework may use 1..4 or 0..100.

    An individual requirement node can override that default scale with its own min_score, max_score, and scores_definition_ref. These overrides are useful when a standard mixes different scoring shapes in the same tree: for example, a mostly maturity-based framework that also contains binary pass/fail requirements.

    The override is resolved independently for each field:

    • If a requirement defines min_score, that value is used; otherwise the audit-level minimum is used.

    • If a requirement defines max_score, that value is used; otherwise the audit-level maximum is used.

    • If a requirement defines scores_definition_ref, those labels (resolved from the framework's alternatives registry) are used; otherwise the audit-level labels are used when they fit the requirement's effective range.

    Per-requirement label overrides go through a named alternatives registry declared on the framework alongside its default scale. Each requirement references an entry by name, keeping shared scales DRY and avoiding duplication on the node:

    One-off scales that only apply to a single requirement are added as a new entry in the framework's alternatives registry and referenced by name, just like shared scales. The node always carries a reference, never inlined labels.

    The audit copies the framework's scores_definition (default scale + alternatives) at creation, so per-requirement references resolve against the audit's own copy. This keeps the audit self-contained: customising the audit's scale later doesn't break references on its requirements.

    Roll-ups keep mixed scales comparable. Average-based aggregation normalises each requirement score against its effective range before computing the parent or global score, then displays the result on the audit scale. Sum-based aggregation remains a raw weighted sum, so each requirement contributes its own effective maximum.

    CISO Assistant ships with 100+ built-in frameworks covering most international standards and regulations. When none of them fits your needs, you can build your own — see Designing your own libraries and Getting your custom framework.

    A mapping (or crosswalk) is a directed graph linking the requirements of one framework to those of another, using the NIST OLIR convention. Once a mapping is loaded, an existing audit can be projected onto the target framework — reusing requirement assessments where the mapping is strong, surfacing gaps where it isn't.

    • Audits

    • Libraries

    • Mappings feature

    Mental model

    framework:
      scores_definition:
        scale:                # default scale, inherited by requirements that don't override
          - score: 0
            name: "N/A"
          - score: 1
            name: "Initial"
          - score: 5
            name: "Optimised"
        alternatives:
          binary:             # named alternative shared by several requirements
            - score: 0
              name: "No"
            - score: 1
              name: "Yes"
      requirement_nodes:
        - urn: ...:r1
          min_score: 0
          max_score: 1
          scores_definition_ref: binary       # reference by name, DRY
        - urn: ...:r2
          min_score: 0
          max_score: 1
          scores_definition_ref: binary       # same reference, same scale

    Structure

    Scoring scales

    Alternative scales registry

    Aggregation across mixed scales

    Built-in vs custom

    Mappings between frameworks

    Related

    Focus mode
    User groups

    ComplianceAssessment

    One per (framework × domain × optional perimeter)

    Reference control

    ReferenceControl

    Template for an applied control

    Vocabulary → Framework / Requirement / Mapping

    Libraries

    A library is a bundled set of catalog objects — frameworks, threats, risk matrices, reference controls, mappings, security advisories, CWE entries — distributed as a YAML file.

    Libraries are how content gets into CISO Assistant. They make the platform extensible: anything from a regulator's framework to a vendor's threat feed to your organisation's internal control catalogue is just another library.

    Mental model

    A library starts life as a stored record — its YAML is parsed and registered but contents stay inactive. Loading it materialises whatever catalog objects the YAML declares — any subset of framework, risk matrix, threats, reference controls, or mapping set (all dashed, all optional). A loaded library can also declare dependencies on other loaded libraries — for example, a framework library that ships its companion reference-control catalogue as a separate dependency.

    User-facing
    Internal
    Notes

    A library can be in one of two states:

    • Stored — the library is known to the instance but its content hasn't been activated yet. It's visible in the libraries store, ready to be loaded on demand.

    • Loaded — the library is active. Its catalog objects show up across the platform: a loaded framework becomes available when creating an audit; a loaded threat appears in the threats list; loaded reference controls power autosuggestion.

    A library typically contains a single primary object (for example, one framework) but may bundle related ones — a framework alongside its companion reference-control catalogue and its mapping to a sibling framework.

    Library content is referenced by URN (Uniform Resource Name), an immutable identifier that survives renames and re-imports.

    • Built-in libraries ship with the platform — over 100 frameworks plus the standard threat, matrix, and reference-control catalogues.

    • Community libraries are contributed by the open-source community; see .

    • Custom libraries can be built locally and loaded without sharing them, useful for internal frameworks or control sets.

    See for the format.

    Libraries are versioned. When a newer version is available, you can upgrade in place — your existing audits keep using the version they were created with until you migrate them explicitly. See and .

    Stored library

    StoredLibrary

    Inventory entry, contents inactive

    Loaded library

    LoadedLibrary

    Activated; contents visible across the platform

    Mapping set

    RequirementMappingSet

    Crosswalk between two frameworks

    Stored vs loaded

    What's in a library

    Built-in, community, and custom

    Lifecycle

    Related

    Contributing a framework or library
    Designing your own libraries
    Library upgrade
    Library clean-up
    Frameworks
    Threats
    Vocabulary → Library / Catalog object / URN

    Mappings

    Directed graphs linking the requirements of one framework to those of another

    A mapping (also called a crosswalk) describes how the requirements of one framework relate to those of another. Once a mapping is loaded, an audit performed against the source framework can be projected onto the target framework — reusing the existing requirement assessments where the mapping is strong, surfacing gaps where it isn't.

    Mappings are catalog objects: defined once as a YAML library, loaded into the platform, and applied on demand.

    Mental model

    A mapping set is the unit shipped by a library — it pins exactly one source framework and one target framework. Inside the set, each individual mapping connects one source requirement node to one target requirement node and carries a relationship type (equal / subset / superset / intersect / not_related). Applying the set to an audit projects the existing requirement assessments onto the target framework: full-coverage relationships (equal, superset) copy directly; partial-coverage (intersect, subset) require manual review.

    User-facing
    Internal
    Notes

    Most organisations have to demonstrate compliance against multiple frameworks at once — ISO 27001 plus SOC 2 plus a sector-specific regulation, for instance. Without mappings, you re-assess the same control posture against every framework's requirement list, which is busywork. With mappings, you assess once and project.

    A mapping is a directed graph linking assessable nodes of a source (SRC) framework to assessable nodes of a target (TGT) framework, using the convention from project.

    Each relationship between a SRC node and a TGT node has a type, which is easiest to read as a set relation between what each requirement covers:

    • No relationship — the two requirements are disjoint; nothing carries over.

    • Equal — the two requirements are equivalent in scope and intent.

    • Subset — the SRC requirement is contained within (narrower than) the TGT requirement.

    The directionality matters: a mapping from A → B does not automatically imply B → A. Reverse mappings can be generated, but the relationship type usually inverts (a SRC subset becomes a TGT superset).

    Once a mapping library is loaded, it can be applied to an existing audit:

    1. Open the source audit.

    2. Click Apply mapping and pick the target framework.

    3. The platform creates a new audit on the target framework and copies over the requirement assessments where the mapping is strong (typically equal), leaving the rest to be assessed.

    The apply-mapping feature can also clone an audit onto the same framework — useful for creating a new revision while keeping the previous one for history.

    You don't need a direct mapping between every pair of frameworks. If the platform holds a mapping from A → B and another from B → C, it can chain them automatically to project an A audit onto C, using B as a pivot — even though no one ever authored an A → C crosswalk.

    The mapping engine treats the loaded mapping sets as a directed graph of frameworks and searches for a path between your audit's framework and the target you pick. When you open an audit and choose Apply mapping, the list of available targets already includes every framework reachable through the graph — both directly mapped ones and those reachable only through one or more pivots. You select the destination; the chaining happens behind the scenes.

    How the chain behaves:

    • Coverage degrades to the weakest hop. Full-coverage relationships (equal, superset) chain cleanly. If any hop in the path is partial (subset, intersect), the projected result is marked partial and flagged for manual review — a chain is only as strong as its loosest link.

    • The best path wins. When several pivots connect A to C, the engine keeps the path that successfully maps the most requirements, and records which intermediate framework(s) it went through so the projection is auditable.

    This is what makes a modest set of crosswalks go a long way: a hub framework such as ISO 27001 or NIST CSF that is mapped to many others effectively becomes a translation pivot between all of them.

    Many cross-walks ship as built-in or community libraries (ISO 27001 ↔ NIST CSF, SOC 2 ↔ ISO 27002, and so on). When none of them fits, you can author your own — see and the prepare_mapping_v2.py tool that scaffolds a mapping skeleton between two loaded frameworks.

    Requirement

    RequirementNode

    Read-only catalog entry from a framework

    Superset — the SRC requirement contains (is broader than) the TGT requirement.
  • Intersect — the two overlap in part but neither contains the other.

  • Depth is bounded. Chaining is limited by the Mapping max depth setting in General settings (default 3 nodes — i.e. up to one pivot, A → B → C). Raise it (up to 5) to allow longer chains (A → B → C → D…), at the cost of progressively weaker, more indirect inferences and slower computation.

    — the UI flow for applying a mapping
  • Mapping explorer — visualising a mapping graph

  • Vocabulary → Mapping / Requirement mapping set

  • Mapping set

    RequirementMappingSet

    One per (source, target) library entry

    Mapping

    RequirementMapping

    Single SRC → TGT pair, typed

    Why they matter

    Structure

    Applying a mapping

    Transitive inference (pivot mappings)

    Loading vs authoring

    Related

    NIST's OLIR
    Designing your own libraries
    Frameworks
    Audits
    Libraries
    Mapping relationship types as set relations between source and target requirements
    Mappings feature

    Threats

    A threat is a catalogued source of potential harm — a phenomenon, agent, or event that could compromise an asset, a business process, or a regulatory obligation.

    Threats are reusable building blocks: a single threat (say, "Phishing") may appear in many risk scenarios, EBIOS RM operational scenarios, and applied control rationales without being duplicated.

    When threats appear

    • Risk scenarios — most qualitative risk scenarios name the threat that drives them.

    • EBIOS RM operational scenarios — threats are mapped to attacker techniques in the kill chain.

    • Vulnerability tracking — threats can be linked to vulnerabilities to express what could exploit this weakness.

    • Applied controls — controls can declare which threats they address.

    CISO Assistant ships with curated threat libraries based on common sources — MITRE ATT&CK, ENISA, the ISO 27005 illustrative threat catalogue, sector-specific catalogues. You can also create your own threats inside a domain, or contribute a custom threat library.

    A risk assessment can be done without referencing threats — the platform doesn't force it. Naming the threat behind a scenario makes the analysis sharper, more reusable, and easier to map back to threat-intelligence feeds.

    Where threats come from

    Optional, but useful

    Related

    Risk assessments
    Libraries
    Vocabulary → Threat

    Risk matrices

    The lookup tables that derive a risk level from probability and impact

    A risk matrix is a configurable lookup table that maps a (probability, impact) pair to a resulting risk level. It's what turns "likely × severe" into "critical" — the encoded judgement that lets a risk assessment be more than a free-form narrative.

    Risk matrices are catalog objects: defined once, packaged into libraries, loaded into the platform, and reused across many risk assessments.

    Mental model

    A risk matrix is a JSON definition (probability axis, impact axis, risk levels, and the grid linking them) bundled in a library. Once a risk assessment is created against a matrix the binding is permanent — the FK uses on_delete=PROTECT — because switching matrices mid-assessment would silently change every risk level, which is what auditors don't want. Each risk scenario in the assessment reads its inherent, current, and residual risk levels from the same matrix's grid using the (probability, impact) pair the assessor sets at each tier.

    User-facing
    Internal
    Notes

    A matrix has four pieces:

    • Probability levels — the ordered scale used for likelihood (e.g. negligible, low, medium, high, very high).

    • Impact levels — the ordered scale used for severity (financial, reputational, operational, or whatever scale the organisation uses).

    • Risk levels — the resulting categories (e.g. low / medium / high / critical), usually colour-coded.

    The grid is the substance of the matrix; the visual rendering (orientation, colours, layout) is handled by the UI based on the loaded matrix definition.

    When a risk assessment is created, its risk matrix is captured and stays fixed for the lifetime of that assessment. Re-evaluating the same scenarios against a different matrix would silently change the risk levels under your feet, which is exactly what auditors don't want.

    If you change matrices mid-programme, you create a new risk assessment against the new matrix and migrate the scenarios. The old assessment keeps its history; the new one starts clean against the new scale.

    Each scenario in a risk assessment is evaluated three times against the chosen matrix:

    • Inherent risk — what the risk would be with no controls.

    • Current risk — what it is today given existing applied controls.

    • Residual risk — what it will be once planned applied controls are implemented.

    The matrix is the same for all three tiers; what changes is the (probability, impact) pair the assessor sets at each tier. See for how the three tiers are used.

    Matrices ship as YAML libraries — the same format as frameworks, with _meta and _content sheets defining the probability/impact/risk axes and the grid. They are typically authored in Excel using the templates under tools/excel/matrix/ and converted to YAML.

    Designing a matrix correctly — particularly the grid — is non-trivial. Start from one of the existing examples and adapt the levels and grid logic rather than building from scratch. See .

    The grid — the lookup from each (probability × impact) cell to a risk level.

    Risk matrix

    RiskMatrix

    json_definition with probability / impact / risk / grid

    Risk assessment

    RiskAssessment

    risk_matrix FK is fixed at creation (PROTECT)

    Anatomy

    Why a matrix is fixed per risk assessment

    Three-tier evaluation

    Authoring a matrix

    Related

    Risk assessments
    Designing your own libraries
    Risk assessments
    Libraries
    Vocabulary → Risk matrix
    Designing your own libraries

    Journeys

    Guided, step-by-step workflows that bootstrap a domain along a recognised path

    A journey is a guided, step-by-step workflow that walks a domain through a recognised process — getting an organisation ready for ISO 27001 certification, running a DORA readiness assessment, building out a privacy register, and so on.

    Journeys remove the "what do I do first?" problem. Instead of staring at an empty domain and assembling the right libraries, assessments, and tasks by hand, you pick a journey, apply it to a domain, and start working through the prescribed steps.

    Preset vs journey

    Journeys come in two flavours of object that mirror the Framework → Audit pattern elsewhere in the platform:

    • A preset is the template. It bundles a set of starter objects (typically an audit, a risk assessment, sometimes additional scaffolds) plus an ordered list of steps with descriptions and links into the platform. Presets are versioned and shipped via libraries; they can also be authored locally.

    • A journey is an instance of a preset, materialised in a specific domain. Applying a preset creates the scaffolded objects in the chosen domain and copies the step list onto the journey so that step statuses can be tracked independently from any other journey.

    The same preset can be applied to multiple domains and yields a distinct journey each time.

    1. Browse the catalogue. The presets page lists everything available on the instance — library-backed presets shipped with CISO Assistant (ISO 27001 starter, DORA readiness, NIS2, sector-specific bundles, etc.) and any presets authored locally. Filter by region tag to narrow the list.

    2. Apply to a domain. Pick a target domain (or create one on the fly). Optionally let the journey create the scaffolded objects for you and apply any feature flags the preset suggests.

    3. Work the steps. Each step has a title, description, and either a target object (e.g. "open the SOA review for the ISO audit") or a target URL inside the platform. Mark steps as

    • Scaffolded objects — the assessments and supporting records that get created when the preset is applied. Typical scaffolds include compliance assessments (with framework + implementation-group selection), risk assessments (with a chosen matrix), and occasionally task templates, perimeters, or entities.

    • Steps — an ordered list of actions to perform. Each step can point at a scaffolded object (via a named reference resolved at apply time) or at a generic internal route such as the SOA results page. Steps carry translations so the workflow speaks the user's language.

    • Feature flags — some presets enable optional features when applied (reports, sec-intel feeds, etc.), letting the journey come with a fully-configured environment.

    Applying a preset requires permission to load libraries on the target domain. Viewing journeys and updating their step statuses follows the standard domain-scoped permission model — see .

    in progress
    ,
    done
    , or
    skipped
    as you advance, and add notes.
  • Track progress. The recently-active journeys panel shows a progress ring per journey; the underlying step counts feed dashboards.

  • Upgrade when a newer preset ships. When a library-backed preset is updated, journeys derived from it flag an upgrade. Upgrading re-applies the newer template while preserving user-state (statuses and notes) on steps that survived the new version.

  • Dependencies — required libraries (frameworks, matrices) that must be loaded for the preset to apply cleanly.

  • Lifecycle

    What's inside a preset

    Permissions

    Related

    Understanding the IAM model
    Vocabulary → Preset
    Libraries
    Audits
    Risk assessments

    Threat intelligence

    Catalogued vulnerabilities, weaknesses, and the feeds that enrich them

    The threat intelligence layer holds the catalogued knowledge CISO Assistant uses to prioritise vulnerabilities, qualify incidents, and connect operational findings to the wider security ecosystem. Today it covers security advisories, weakness catalogues, and a small set of public enrichment feeds; the surface is expected to grow significantly in upcoming releases.

    Security advisories

    A security advisory is a catalogued security warning published by a vendor, CERT, or standards body. CISO Assistant supports four sources today:

    • CVE — the MITRE/NIST CVE Program identifiers (CVE-YYYY-NNNN).

    • EUVD — the EU Vulnerability Database (post-NIS2 European equivalent).

    • GHSA — GitHub Security Advisories.

    • Other — for sources that don't fit the above.

    Each advisory carries the usual identifying metadata (reference ID, published date, references) plus the bits that drive prioritisation:

    • CVSS base score and CVSS vector — severity per the standard scoring system.

    • EPSS score and EPSS percentile — probabilistic exploitation likelihood from FIRST.

    • Active exploitation flag and the KEV date when the advisory landed on CISA's Known Exploited Vulnerabilities list.

    Advisories are catalog objects: library-backed, root-folder-published, referenced from vulnerabilities and assets rather than re-created per scope.

    The Common Weakness Enumeration is MITRE's catalogue of software-weakness categories — buffer overflows, missing authentication, improper input validation, and so on. Where a security advisory is "this specific vulnerability in this specific product", a CWE is "this class of flaw". CWEs are catalogued separately and tagged onto advisories and vulnerabilities to enable categorical analysis ("how many of our open vulns are credential-handling bugs?").

    CWEs ship as their own catalog library; loading the CWE library makes the entries available across the platform.

    A vulnerability in CISO Assistant is the organisation-specific record — "we have this exposed in our environment, here's the SLA". It links to:

    • One or more security advisories — the upstream finding(s) it corresponds to.

    • One or more CWEs — the weakness categories it belongs to.

    This linkage is what lets enrichment feeds work end-to-end: advisories get scores from EPSS, exploitation status from KEV, and category mappings from NVD; vulnerabilities inherit that context via their advisory links and surface it in dashboards and SLA prioritisation. See .

    Three public feeds enrich the catalogue when enabled — they keep the threat-intel layer current without manual data entry. Configuration is under :

    • KEV feed — CISA's Known Exploited Vulnerabilities; flags advisories under active exploitation.

    • EPSS feed — FIRST's Exploit Prediction Scoring System; attaches a probabilistic exploitation score.

    • NVD enrichment — pulls extra metadata from the NIST National Vulnerability Database (CWE mappings, affected configurations, references).

    Each feed is a separate flag and can be toggled independently. The platform stores feed status, network timeout, and last-update timestamps centrally.

    The threat-intelligence surface is being expanded to cover full STIX-style threat intelligence — threat actors, attack patterns, indicators of compromise, campaigns, sightings — along with STIX 2.1 / TAXII / MISP / OpenCTI interop and DORA cyber-threat notification workflows. The objects on this page remain the entry point; new SDOs will sit alongside them.

    Aliases — cross-references to other identifiers when an advisory exists under multiple IDs.

    CWEs

    How they connect to vulnerabilities

    Enrichment feeds

    Where this is going

    Related

    Vulnerabilities
    Security intelligence feeds
    Vulnerabilities
    Incidents
    Security intelligence feeds
    Vocabulary → Security advisory / CWE

    Metrics

    Expected outcome

    • define your metrics or import their definition

    • instantiate them on your domains

    • feed data to your metric instances

    • create dashboards with builtin and custom metrics

    A metric definition is the catalog template — qualitative (level) or quantitative (number with unit) — and can be shipped via a library. Each instance scopes one definition to a domain and carries the operational fields: assignee, target value, collection frequency (auto-stale logic kicks in when the latest sample exceeds the cadence + grace period). Samples are timestamped data points against an instance. Dashboards are independent of the metrology pipeline: they comprise widgets, and each widget either reads a custom metric instance, pulls from a builtin sample (a system-computed daily snapshot attached generically to any tracked object — assets, audits, projects, incidents, etc.), or just displays free text.

    User-facing
    Internal
    Notes

    Consider metric definition as a template of your metric. It serves as the guideline of the actual metric instance that you will track accross your domains.

    You will learn how to import off-the-shelf metrics definitions on CISO Assistant.

    Click "Metric definitions".

    Click here to proceed to the next menu.

    You can also preview the content before importing it.

    Click "Metric definitions" to revisit the main metrics page.

    Click "Search..." to begin finding specific metrics.

    You can now instantiate this metric as you see fit for your domains.

    You can now instantiate this metric as needed across your domains. Keep in mind that you can also create your own metric definition directly without going through the library.

    Metrics can be quantitative (number with unit) or qualitative (choices):

    You can add your options during declaration or afterward:

    The "higher is better" setting is used to indicate if the trend is a good thing or not.


    The metric instance is the projection of the definition to a specific domain and it's what you'll be tracking.

    Parameters:

    • Metric definition (it will inherit its settings)

    • Domain: the scope of this metric

    • Status: lifecycle of the metric. The stale is specially interesting as the application will auto-toggle it according to the data freshness

    This is the actual data of the metric instance on a given timestamp.

    Keep in mind that you can add the data manually or through all the supported integrations (API, n8n, etc.). Note that data cannot be in the future.

    Dashboards are the visual representation of the metrics and support:

    • custom metrics instance (multiple charts)

    • built-in metrics (multiple charts)

    • markdown text widget

    In edit mode, you can add different widgets, place and resize them as you see fit:

    Once done, you can go back to view mode to see the result:

    In addition to the custom metrics for your internal KPI and KRI, you can also include some of the built-in metrics tracked by the platform:

    Those are updated on each change of your data and tracked as daily metrics.

    Sample

    CustomMetricSample

    Timestamped data point on an instance

    Builtin sample

    BuiltinMetricSample

    System-computed; daily; ContentType GFK to any object

    Dashboard

    Dashboard

    Container

    Widget

    DashboardWidget

    KPI / donut / pie / bar / line / area / gauge / sparkline / table / text

    Collection frequency: expected collection frequency, on which we add a grace period before toggling the metric to stale status
  • Target value: expected target of this metric for this specific domain. This is handy as you can have different targets of the same metric definition according to the domain.

  • Assigned to: actor responsible for the metric instance and its updates.

  • Metric definition

    MetricDefinition

    Catalog template; optional library FK

    Metric instance

    MetricInstance

    One definition × one domain

    Mental model

    Metric definitions

    Importing definitions

    1. Introduction

    2. Open Metric Definitions

    3. Click import

    4. Import the library matching your criteria

    5. Return to Metric Definitions

    6. Look for the metric definition you want

    7. Select The Specific Metric

    Creating a definition

    Metric instance

    Metric sample

    Dashboards

    Introduction
    Open Metric Definitions
    Click import
    Import the library matching your criteria
    Return to Metric Definitions
    Look for the metric definition you want
    Select The Specific Metric
    Quantitative metric
    Qualitative metric

    Assets and resilience

    Operations

    Asset classes

    A shared taxonomy for classifying assets, extensible per organisation

    An asset class answers "what kind of thing is this?" for an asset — a server, a business process, a set of personal data. Classes form a tree, so a class can be a refinement of a broader one, and an asset points at most one class.

    CISO Assistant ships with a taxonomy derived from the CIS asset categories (Devices, Software, Data, Users, Network, Facilities, Documentation, Business Process, and their sub-classes). You can extend that tree with your own classes, and hide the shipped ones you don't use.

    Why it exists

    The class is deliberately separate from the domain an asset lives in and from its primary/supporting type. Those three answer different questions:

    Question
    Field

    Keeping them apart means you can classify a supporting asset in one domain and a primary asset in another under the same class, and then read your whole estate by class regardless of who owns it.

    A class refines a parent class, forming the taxonomy tree. An asset is classified by at most one class — the link is optional, so an unclassified asset is valid and stays fully usable. The domain still scopes the asset; classes are organisation-wide and carry no access control of their own.

    User-facing
    Internal
    Notes

    The shipped classes are marked Builtin. They are re-created every time the platform starts, which is why they behave differently from classes you create:

    • They cannot be renamed or deleted — a rename would be undone and a deletion would silently reappear on the next restart. The edit form states this: "Built-in classes are provided with the product: they can be hidden, but not renamed or deleted."

    • They can be hidden. Clearing Visible removes a class from the picker used when classifying an asset, without touching any asset already classified under it. The form notes: "Hidden classes stay listed here but are no longer offered when classifying an asset."

    Classes you create are yours entirely — rename, re-parent, hide, or delete them (see ). Creating a class under a built-in one is the intended way to extend the shipped taxonomy: the child is your own class, and the built-in parent stays untouched.

    Hiding a class that still has visible sub-classes does not orphan them. The class remains in the picker as a non-selectable grouping row so its descendants keep a readable path.

    In the sidebar under Extra → Asset classes.

    The table lists Name, Parent class, Description, Translations, Visible and Builtin. Filters let you narrow to visible or built-in classes.

    Use the add button on the Asset classes page. The form asks for:

    • Name — free text.

    • Description — optional.

    • Parent class — optional. Leave it empty to create a top-level class. The picker is a tree, and it excludes the class you are editing along with everything beneath it, so a class can never become its own ancestor.

    To add a child directly under an existing class, open that class and use the add button on its children table: the Parent class is filled in for you.

    Built-in class names are translated by the interface itself and follow the language you are using. Classes you create are free text, so they need their own translations.

    The Translations editor on the class form takes a Name and a Description per language. When you are using a language that has no entry, the class falls back to the name you typed when you created it. That fallback is why a class can look "untranslated": it means no entry exists for your current language, not that translation is unavailable.

    Deleting a class also deletes every class beneath it. The confirmation dialog lists exactly what will go, so check it before confirming.

    Assets classified under a deleted class are never deleted — they simply become unclassified. They keep every other property, and you can re-classify them afterwards.

    On the asset form, the Class field is a searchable tree. Only visible classes are offered. Type to search across the whole taxonomy, or expand the tree to browse it; the selected class shows its full path so you can tell two same-named classes apart.

    The Assets by class page turns the taxonomy into a way to navigate your estate. Reach it from the Assets page using the tree icon.

    Each class shows a count of the assets beneath it, rolled up through the tree, so a parent class with no assets of its own still shows what its children hold. Expanding a class lists the assets classified directly in it; classes with no assets at all are hidden unless you clear Hide empty classes.

    Assets with no class appear in a separate Unclassified group at the bottom — a useful starting point when you are working through a backlog of unclassified assets.

    Only assets you are allowed to see are counted or listed, so the totals on this page are yours, not the whole database's.

    Asset exports include an asset_class column holding the class's full path, with each level separated by / — for example assetClassDevices/assetClassEnterpriseAssets/assetClassServers.

    The path is used rather than a display name because it is unambiguous (two classes may share a name under different parents) and stable across instances and languages. Imports accept the same format in an asset_class column, and also accept a bare class name when only one class in the tree carries it.

    If an import names a class that does not exist, the asset is still imported — it simply arrives unclassified, and the row is reported as a warning.

    Domain exports carry asset classes the same way. When you import a domain into another instance, any of your own classes that the target does not have are re-created, while built-in classes bind to the ones already there.

    • — a different organisation-defined override

    • — confidentiality labelling, not typology

    Built-in

    builtin

    Shipped with the product

    Visible

    is_visible

    Controls whether the class is offered when classifying

    Translations — see below.
  • Visible — on by default.

  • Who owns and can see it?

    Domain

    Does it deliver value directly, or support something that does?

    Type (primary / supporting)

    What kind of thing is it?

    Class

    Asset class

    AssetClass

    Self-referencing tree via parent

    Class (on an asset)

    Asset.asset_class

    Optional; a single class per asset

    Mental model

    Built-in versus your own classes

    Managing classes

    Creating, editing and deleting asset classes requires administrator rights. Other roles can see the taxonomy and use it to classify assets, but not change it.

    Creating a class

    Translating class names

    Deleting a class

    Classifying an asset

    Browsing assets by class

    Assets load in batches as you expand a class, with a Load more control on large groups. The page is built to stay responsive on estates with tens of thousands of assets.

    Classes in import and export

    Related

    Deleting a class
    Assets
    Terminology
    Object classifications

    Assets

    An asset is anything of value worth protecting. Assets are first-class objects in CISO Assistant, decoupled from any specific risk study or audit, so the same asset can participate in many analyses without being duplicated.

    Assets are always defined by the organisation and can be attached to the global domain or to a specific domain.

    Mental model

    The asset is a hub other surfaces point at: risk scenarios impact it, vulnerabilities affect it, incidents affect it, and a Business Impact Analysis assesses it (through an intermediate AssetAssessment row, one per asset in the BIA). The supports self-loop captures the primary/support hierarchy — a support asset is recorded as a child of its primary parent through parent_assets.

    User-facing
    Internal
    Notes
    • Primary assets are core resources directly contributing to the organisation's main objectives — business processes, data, intellectual property.

    • Supporting assets indirectly aid primary functions — IT systems, services, locations, people.

    The distinction matters for risk work: scenarios typically express what can happen to a primary asset via which supporting assets are involved.

    First-class

    Incident

    Incident

    First-class

    BIA

    BusinessImpactAnalysis

    Bridges to assets via AssetAssessment

    Asset

    Asset

    First-class; primary vs support via type

    Domain

    Folder

    Required; drives IAM scoping

    Risk scenario

    RiskScenario

    Lives inside a RiskAssessment

    Vulnerability

    Primary vs supporting assets

    Related

    Asset classes
    Risk assessments
    Vocabulary → Asset

    Vulnerability

    Applied controls

    An applied control is the main building block of the action plan: the actual action your team has implemented or will implement to address a security need. It can be technical, organisational, a process, a policy, a piece of documentation — anything that materially changes risk or compliance posture.

    A single applied control can satisfy any number of requirements across any number of frameworks — it's where what the framework asks meets what the organisation actually does.

    Mental model

    The applied control sits at the centre — anything that asks for action points to it; everything that proves the action took place hangs off it. Compliance work (requirement assessments), risk work (scenarios), follow-up work (findings), and operational maintenance (tasks — periodic reviews, evidence refresh, assignee rotation) all reference the same control, while evidences and protected assets accumulate on the other side. This is the decoupling principle made concrete: one applied control, many demand-side users.

    User-facing
    Internal
    Notes

    Applied controls are fundamental for both compliance and remediation. They can derive from a reference control for consistency, or be created independently. They are always defined by the organisation and can be attached to the global domain or to a specific domain.

    The status field is what turns an applied control from a static catalogue entry into a live, trackable piece of work. It's the single signal that drives roll-ups across audits, dashboards, action plans, and reporting — so it's worth understanding how it moves.

    The target state of an applied control is Active, not Done. This is deliberate. A control is never finished in the way a project task is finished: a backup policy that's been written and approved still has to keep being followed, a firewall rule that's been deployed still has to keep being enforced, an access review that's been run still has to be run again next cycle. Reaching Active doesn't end the work — it starts the maintenance phase. The work shifts to keeping the control in Active, through periodic reviews, evidence refresh, and the that "maintain" it.

    This is why the lifecycle has Active, Degraded, and Deprecated rather than Done. A control that's failing partially moves to Degraded (signal to act); a control that's no longer needed moves to Deprecated (retire with history intact). There's no terminal "done" state on purpose — the whole point of cybersecurity controls is that they're a continuous effort to stay in Active, not a checkbox you tick once.

    The lifecycle runs through seven states:

    Status
    Meaning
    Counts as "in place"?

    Why the lifecycle matters across the platform:

    • Risk model — Current risk uses controls in active (and partly degraded); residual risk also factors in controls in to_do / in_progress (the planned ones). Moving a control from to_do to active is what closes the gap between residual and current.

    The transitions aren't enforced as a strict state machine — you can move a control between any two statuses — but staying within the lifecycle above makes audit trails and analytics meaningful.

    Applied controls carry a structured cost field, so the financial weight of your security programme isn't a separate spreadsheet — it's attached to the controls themselves and rolled up wherever they appear (most notably on every ).

    The platform models the build vs run distinction that controls actually carry in practice:

    Cost type
    Meaning
    How it's counted

    Each side accepts two inputs:

    • Fixed cost — a money amount (hardware purchase, licence fee, contractor invoice).

    • People days — a measure of internal effort. The platform converts this to money using the daily rate configured in General settings, so internal time is comparable with external spend.

    From these inputs, the platform computes an annual cost for every control:

    Symbol
    Meaning

    That single number is what feeds every roll-up — the action plan's budget overview, the per-assignee and per-domain breakdowns, the by-status / by-priority / by-CSF-function totals. Controls without a cost set contribute zero, so partial adoption of the financial tracking still works — you fill in numbers where you have them and the totals reflect what's known.

    The annualised view matters because cybersecurity controls are continuous (see above). A capex-style "we paid €40k once" view doesn't compare well across controls; an "annual cost in steady state" view lets you put a single line per control on the budget and compare them like-for-like.

    A reference control is a template for an applied control. Reference controls facilitate the creation of applied controls and help keep them consistent across the organisation.

    They can be provided by security frameworks imported from a library, or you can create your own — in the global domain or in a specific domain. Reference controls are optional but recommended.

    A policy is a specific type of applied control: a document describing what is expected from some part of your stakeholders. Putting your cybersecurity policies in CISO Assistant makes them readily available for audits, and lets you manage their lifecycle alongside the rest of your controls.

    M2M; one evidence can prove several controls

    In progress

    Being implemented

    No

    On hold

    Started then paused — blocked, deprioritised, or waiting on a dependency

    No

    Active

    Implemented and operating as intended

    Yes

    Degraded

    Was active, now partially failing — gap detected at audit or in operations

    Partial

    Deprecated

    Retired or superseded — no longer in scope

    No

    Action plan — the Kanban view and the Control Plan grid both swimlane by status. A control sitting in on_hold for too long is the signal to escalate.
  • ETA enforcement — when ETA passes and the status isn't active, the control is flagged overdue. Reaching active is what stops the clock.

  • Framework / audit roll-ups — compliance percentages and analytics treat active as "in place" and degraded as a partial signal that wants follow-up. Other statuses don't contribute coverage.

  • Deprecation — preferred over deletion. A deprecated control keeps its history, evidence, and links to the requirements it once satisfied — useful for past-audit traceability — without polluting current views.

  • T

    Amortisation period, in years

  • Vocabulary → Applied control / Reference control / Evidence

  • Applied control

    AppliedControl

    The action you take

    Reference control

    ReferenceControl

    Optional library template; an applied control can also be created from scratch

    Task

    TaskTemplate (definition) / TaskNode (occurrence)

    A task definition lists which controls it keeps alive; occurrences are the recurring instances

    Evidence

    Undefined

    Default — status not yet set

    No

    To do

    Planned but not started

    No

    Build

    One-shot setup cost — buying hardware, integrating a tool, drafting and approving a policy, running a project to roll out the control

    Amortised over the configured amortisation period (in years)

    Run

    Ongoing operational cost — licence renewals, the time spent every quarter on access reviews, the hours of the team that operates the control

    Counted as an annual cost — applied every year for as long as the control runs

    annual cost=Bfixed+Bdays⋅rT+Rfixed+Rdays⋅r\text{annual cost} = \frac{B_{\text{fixed}} + B_{\text{days}} \cdot r}{T} + R_{\text{fixed}} + R_{\text{days}} \cdot rannual cost=TBfixed​+Bdays​⋅r​+Rfixed​+Rdays​⋅r

    Bfixed, Bdays

    Build fixed cost and people-days

    Rfixed, Rdays

    Run fixed cost and people-days

    r

    Configured daily rate (from General settings)

    Applied control

    Status lifecycle

    Why "Active" — and why no "Done"

    Financial tracking

    Reference control

    Policy

    Related

    tasks
    action plan
    Why "Active" — and why no "Done"
    Policies
    Audits
    Findings assessments

    Evidence

    Philosophy → Decoupling principle

    Incidents

    Security and operational events tracked from detection through resolution

    An incident is a security or operational event being investigated or responded to. CISO Assistant treats incidents as first-class objects so that detection, response, evidence, and the controls that should prevent recurrence all live in one place.

    Incidents are deliberately distinct from related concepts:

    • A risk scenario is a potential adverse event — the possibility.

    • A vulnerability is a weakness that could be exploited — the gap.

    • An incident is something that has actually happened and is being handled.

    An incident lives in a domain and aggregates everything about the event: the assets it affected, the threats it's attributed to, the actors handling it, the applied controls invoked during response, and any task templates set up for follow-up work (post-mortem, control review). Timeline entries are the append-only log of what happened and when — detection, mitigation, observation, severity / status changes.

    User-facing
    Internal
    Notes
    • Identifiers and classification — a name, an optional reference ID, the severity (critical / major / moderate / minor / low / unknown), and the status through its lifecycle.

    • Timing — when it occurred, when it was reported, when it was resolved.

    • Detection — internal vs external, optionally with a link to the source signal.

    Incidents follow a five-state lifecycle:

    new → ongoing → resolved → closed (or dismissed at any point if the event turns out not to be a real incident)

    State transitions are recorded in the incident timeline, an append-only log of significant moments: detection, mitigation, free-form observation, severity changes, status changes. The timeline is what an auditor or a post-mortem author will read to reconstruct what happened.

    For regulated tenants, CISO Assistant ships a DORA incident report — a structured form aligned with the Digital Operational Resilience Act notification requirements (initial, intermediate, and final reports). It draws from the underlying incident but adds the regulatory fields and timing that DORA prescribes.

    Actor

    Actor

    XOR(User / Team / Entity)

    Task template

    TaskTemplate

    Spawns occurrences

    Timeline entry

    TimelineEntry

    Append-only response log

    Scope — the affected assets, the threats believed to be in play, the entities (third parties) involved.

  • Assignees — the actors handling the response.

  • Response and qualifications — qualifying terminology, BCP-activation flag, resolution notes.

  • Linked controls and tasks — the applied controls invoked during response, plus the task definitions that should run as follow-up (e.g. a post-mortem, a control review).

  • Vocabulary → Incident / Severity

  • Incident

    Incident

    First-class operational event

    Threat

    Threat

    Library catalog object

    Mental model

    What an incident captures

    Lifecycle

    DORA incident reports

    Related

    Risk assessments
    Vulnerabilities
    Applied controls
    Tasks

    Tasks

    Recurring and one-off operational work tracked against assignees, schedules, and evidence

    Tasks are how CISO Assistant tracks the operational work that keeps controls effective: the weekly access review, the monthly backup test, the quarterly policy refresh, the one-off offboarding checklist. They are deliberately separate from applied controls — a control says what is done; a task says that someone has actually done it on a given date.

    The task template is the definition — assignee, recurrence rule, expected evidence — and the task occurrence is the actual unit of work scheduled from it. The schedule is a JSON field describing the cadence (DAILY / WEEKLY / MONTHLY / YEARLY with the usual iCalendar refinements). Templates can be wired to many other objects — applied controls being the canonical one (the "maintains" semantics: this work keeps that control healthy) — and when an occurrence is completed, the evidence revision it produces is back-linked through task_node so the audit trail closes the loop.

    User-facing
    Internal
    Notes

    Task definition / template

    TaskTemplate

    One spec, one schedule

    Task occurrence

    TaskNode

    One scheduled run

    Schedule

    schedule JSON field on the template

    iCal-style recurrence rule

    Tasks come in two layers, mirroring the template → instance pattern used elsewhere in the platform:

    • A task definition is the reusable spec — the title, description, assignee, expected evidence, and the recurrence rule (every Monday, the 1st of each month, every 90 days). It says what should happen and how often. Internally a TaskTemplate.

    • A task occurrence is a single scheduled run produced from a definition — the actual row with a due date, a status (pending → in progress → completed / cancelled), and the evidence collected when the work was done. Internally a TaskNode.

    A one-off task is just a definition that produces a single occurrence.

    1. Define. Create a task definition with the assignee, the cadence, and what's expected when the task runs.

    2. Schedule. Occurrences are materialised from the recurrence rule. The platform creates them as their due dates come into view, so the list of upcoming work is always visible.

    3. Work the occurrence. When a due date arrives, the assignee opens the occurrence, records what they did, attaches evidence, and marks it completed.

    4. Iterate. Edit the definition to adjust the cadence, assignee, or expected evidence — existing occurrences keep their state; future occurrences pick up the change.

    The point of tracking tasks inside the platform — rather than in a calendar or ticketing system — is so that the evidence of execution lives next to the rest of your compliance record. An auditor asking "show me proof of monthly backup testing" can be answered by pointing at the task and walking through the completed occurrences with their attached evidence.

    • Applied controls

    • Evidence

    • Vocabulary → Task definition / Task occurrence

    Mental model

    Definition vs occurrence

    Lifecycle

    Why tasks (and not just calendar reminders)

    Related

    Business impact analyses

    A business impact analysis (BIA) measures the operational, financial, and reputational consequences of disrupting specific assets or business processes — the input to any serious resilience plan.

    Where a risk assessment asks "what could go wrong?", a BIA asks "if it does, how bad is it, and how quickly does it become unacceptable?".

    Mental model

    A BIA is an assessment scoped to a perimeter. For each asset in scope, the platform captures:

    • Asset assessment — the impact of disruption along one or more dimensions (financial, operational, regulatory, reputational).

    • Escalation thresholds — the durations after which disruption becomes severe, critical, or unacceptable — often expressed as RTO (Recovery Time Objective) levels.

    The output is a prioritised view of which assets your continuity plan must protect first.

    • BIAs read from the asset inventory — assets are first-class objects, not BIA-private records.

    • The criticality output can drive risk scenario prioritisation for the same assets.

    • For organisations subject to DORA, BIA results feed into incident-reporting workflows.

    How it ties into the rest of the platform

    Related

    Assets
    Risk assessments
    Vocabulary → Business impact analysis

    Governance

    Policies

    A policy is a specific type of applied control: a document describing what is expected from some part of your stakeholders — an acceptable-use policy, a password policy, a data-classification policy, an incident-response procedure, anything that defines how things should be done.

    Because policies are applied controls under the hood, they inherit the full applied-control machinery: they live in a domain, have an assignee and a status, link to the requirements they satisfy, and carry evidence.

    Why give policies their own page

    Policies are central to most compliance frameworks — almost every requirement expects a documented policy as part of the substantiating artifacts. Pulling policies onto a dedicated page lets you:

    • Maintain the catalogue of published documents independently of the broader action plan.

    • Track policy review and approval cycles separately from operational controls.

    • Surface policies by domain when responding to audit requests or external reviews.

    The Policies page in the platform is a filtered view of applied controls where the type is policy; everything you can do to an applied control, you can do to a policy.

    Policies can come from either side of the divide:

    • Author in CISO Assistant. Each policy can carry one or more managed documents — versioned documents tracked in-platform through a draft → in-review → validated → published → deprecated lifecycle. Useful when you want the policy text to live where the rest of the GRC programme lives, with revision history and approval workflow attached.

    • Bring an existing document. If a policy already exists as a file, or lives in Confluence, SharePoint, or a DMS, its managed document can be uploaded (the file itself) or linked (a pointer to where it lives) — the same lifecycle, versioning, and links apply, without duplicating the source of truth.

    Both paths are first-class — you can mix them across an organisation, or even across policies in the same domain. The applied-control machinery (assignee, status, linked requirements, evidence) is the same either way.

    For policies authored in CISO Assistant, every change produces a new revision of the managed document rather than overwriting the previous text. Each revision carries:

    • A monotonically increasing version number (v1, v2, …).

    • A revision status (draft / in review / change requested / validated / published / deprecated).

    • A timestamp, the actor who edited it, and the content at that point in time.

    The full revision list is reachable from the version history sidebar on the document page — you can switch between revisions to read any past version exactly as it was published.

    Two diff views help reviewers and approvers see what actually changed:

    • Diff between two revisions — pick a "from" revision and a "to" revision in the history sidebar and the platform renders the textual differences between them. Useful for periodic reviews ("what changed between v3 and v6?") and for the approval workflow ("show me the delta the requester is asking me to validate").

    • Edit diff (within a revision) — while a draft is being worked on, the platform also tracks the diff between the last loaded state and the current edits in the editor. This lets the author see exactly what they're about to commit before they save the increment.

    The diff is computed on the document content itself — it's not a binary file diff, so it works well for the plain-text or Markdown policies typically authored in-platform. For policies attached as external files (PDF, DOCX, etc.), version history is preserved through evidence revisions, but the inline diff view is not available.

    Policies have their own lifecycle — drafting, review, approval, publication, periodic review, retirement. The platform tracks these states through the standard applied-control status field and the supporting evidence on each policy entry. When authoring in-platform, the managed-document revision states (draft, in review, validated, published, deprecated) provide a finer-grained workflow on top.

  • Authoring options

    Versioning, history, and diff

    Diff between revisions

    Lifecycle

    Related

    Documents
    Applied controls
    Audits
    Evidence
    Vocabulary → Policy

    Findings assessments

    A findings assessment — called Follow-up in the UI — tracks the issues raised by a review and drives their remediation through to closure. Findings can come from a CISO Assistant audit, an internal security review, a penetration test, an external assessor's report, or any other source.

    It's the place where the action plan meets reality: each non-compliance, observation, or recommendation gets an assignee, a due date, and a status, and is followed all the way to "fixed".

    Mental model

    A findings assessment is an assessment scoped to a perimeter, in the same family as audits, risk assessments, and business impact analyses. Inside it sit individual findings, each with:

    • A severity, often aligned with the assessor's severity scale.

    • An assignee and a due date.

    • A status from open → in progress → remediated → closed.

    • One or more linked applied controls that address it.

    The same findings model serves several sources:

    • Audit findings — non-compliances or partial compliances raised during an audit, especially when extended results are enabled (minor / major nonconformity, observation, opportunity for improvement, good practice).

    • External assessments — penetration-test reports, third-party security reviews, regulator inspections.

    • Internal reviews — self-imposed checks outside the formal audit cycle.

    Because the model is uniform, dashboards aggregate across sources: you can see all open findings due this quarter, across all reviews, without preselecting which kind of review they came from.

    Findings link to applied controls — closing a finding usually means standing up or updating one or more controls. The link is many-to-many: a single control can close several findings, and a single finding can require several controls.

    Where findings come from

    Driving remediation

    Related

    Audits
    Applied controls
    Vocabulary → Findings assessment

    Documents

    Document management lets you author, version, and publish documents — policies, procedures, charters, records, meeting minutes — directly inside CISO Assistant, so the text of your governance programme lives where the rest of your GRC data lives, with revision history and an approval workflow attached.

    Documents can be authored in-platform (a Markdown editor with a draft → published lifecycle), uploaded (an existing PDF or file carried through the same lifecycle), or linked (a pointer to a document that lives in another system). Whatever the source, a document can be classified, linked to the objects it governs, and referenced by other documents.

    Document management is controlled by the document_management (on by default). The Documents reading catalogue, the document list, and templates all live behind it.

    Mental model

    A document container is the language-independent identity of a document: it holds the document's type, its domain, its classification, and its links. Under it sit one managed document per language, and each managed document is a chain of document revisions — one per saved increment. A new document can be seeded from a template, classified with a level, reference other containers, and be linked to the objects it governs. Solid edges are always present; dashed edges are optional.

    In the UI
    Internally

    Every document has a Document type, used to group the reading catalogue and to scope the template picker. The built-in types are Policy, Procedure, Charter, Record, Meeting minutes, and Other.

    A document's content comes from one of three sources, chosen when you create it:

    • Authored — written in the in-platform Markdown editor (formatting toolbar, live preview, insert links to other documents). The published version is rendered to a PDF snapshot.

    • Uploaded — an existing file (e.g. a signed PDF) attached to the document. It runs through the same lifecycle and version history, but is served as-is rather than rendered from Markdown.

    • Linked — a pointer to a document that lives in another system (Confluence, SharePoint, a DMS, …). The document carries the URL through the same lifecycle; readers open it in place rather than reading content inside CISO Assistant.

    All three share the same versioning, lifecycle, languages, classification, and links — they differ only in where the content lives.

    Each language version moves through its own lifecycle — Draft → In review → Change requested → Validated → Published → Deprecated — and every saved change produces a new revision (v1, v2, …) rather than overwriting the previous text. The Version history sidebar lets you read any past revision and diff two of them.

    The lifecycle, revision history, and diff mechanics are shared with policy documents and are described in detail under .

    A single document can carry a version per language. One language is the default (used for the catalogue title and status); the others are translations. Each language version has its own lifecycle, so a French translation can still be in draft while the English original is published.

    When you link one document to another from inside the editor (Link to document), CISO Assistant records the edge automatically. Each document then shows:

    • References — the documents this one points to.

    • Referenced by — the documents that point at this one.

    These are computed from the content — there is no separate list to maintain, and they stay accurate as the text changes.

    A document can be linked to one or more Policies, Applied controls, Task definitions, or Processings. The link is associative — it never changes the document's domain or publication state — and it is bi-directional: the linked object shows a Documents panel listing the documents attached to it.

    This is how a policy or a control points at the document that describes it without duplicating the text. See .

    A document can carry a Classification — a level from an scheme such as TLP. Once set, the level shows as a coloured badge on the reading catalogue, in the reader, and in the documents table, and it is stamped on every page of the document's exported PDF (for example TLP:AMBER). Classification is optional and independent of the document's type, domain, and lifecycle.

    New authored documents can start from a document template — a reusable Markdown body, chosen in the editor's template picker. The picker only offers templates matching the document's type and language. See the .

    The Documents page is a read-oriented catalogue: published documents shown as tiles, grouped by type, with search and type filters. It is the place to browse and read the published corpus, separate from the authoring workflow.

    Risk

    DocumentTemplate

    Document

    DocumentContainer

    Language version

    ManagedDocument

    Revision

    DocumentRevision

    Document types

    Content sources

    Lifecycle and versioning

    Multiple languages

    References

    Links to governed objects

    Classification

    Templates

    Reading catalogue

    Related

    Policies → Versioning, history, and diff
    Policies → Authoring options
    object classification
    Document templates guide
    Authoring documents
    Document templates
    Policies
    feature flag

    Document template

    Feature flags

    Risk assessments

    A risk assessment (also called a risk study) is a scenario-based evaluation of risk over a perimeter. CISO Assistant supports qualitative approaches (configurable risk matrices), quantitative approaches (Monte Carlo over loss distributions), and the structured EBIOS RM methodology.

    The platform follows the ISO 27005 risk-management workflow.

    ISO 27005 risk management workflow

    Mental model

    A risk assessment always lives inside a domain (the mandatory IAM scope) and is bound to one risk matrix that supplies the probability × impact scale (the matrix can be swapped later; existing scores are clamped to the new scale). A perimeter can optionally narrow the assessment to a specific service or process inside the domain. The assessment is composed of risk scenarios; each scenario links to the assets it impacts, the threats it materialises, and the applied controls that mitigate it (split between existing and planned to drive the three-tier risk model below).

    User-facing
    Internal
    Notes

    A risk assessment encompasses three steps:

    • Risk identification — defining the risk scenarios.

    • Risk analysis — assessing probability, impact, and strength of knowledge for each scenario.

    • Risk evaluation — done automatically based on the selected risk matrix.

    In CISO Assistant, risk treatment is combined with the risk assessment rather than tracked as a separate phase.

    Scenarios can be defined directly from the risk-assessment view or separately via the scenarios view. The same scenario can be reused across multiple studies.

    CISO Assistant tracks three risk levels for each scenario, reflecting where the organisation stands along the treatment journey:

    • Inherent risk — the natural level of the scenario without any controls in place. The starting point. Surfaced in the UI when the inherent_risk feature flag is on.

    • Current risk — the level given the applied controls already in place. The state of risk today.

    • Residual risk — the level expected once all planned

    Each level has its own probability, impact, and overall level fields. The assessment's consistency check flags a scenario whose residual risk exceeds its current risk (on level, probability, or impact), and also flags a residual lowered below current when no applied control justifies the reduction.

    Risk acceptance is when an organisation or individual decides to tolerate a certain level of risk without taking further action to reduce it. CISO Assistant provides a workflow to capture formal approval of risk acceptances by management — the approver must hold the Approver role.

    For the formal definition, see .

    Risk levels are calculated as a function of the probability and impact of a scenario, using a configurable risk matrix. Matrices are imported from libraries — pick one of the built-in matrices or define your own via a custom library.

    Most organisations define an official matrix to be used for all risk assessments, but CISO Assistant lets you choose a different matrix per assessment when needed. The matrix can be changed after the assessment has been created. When you do, each scenario's existing probability and impact values are clamped to the new scale's bounds — a score that falls outside the new range is clipped to the nearest valid value, and unrated scenarios stay unrated. There is no proportional rescaling, so review the scenarios afterwards and correct any score that no longer reflects your intent.

    RiskMatrix

    Can be changed; existing scenario scores are clamped to the new scale's bounds

    Domain

    Folder

    Required; drives IAM scoping

    Threat

    Threat

    Catalog entry from a library

    applied controls have been implemented. The target state, and the figure used in risk-acceptance decisions.

    Risk assessment

    RiskAssessment

    Also called "Risk study" in the UI

    Risk scenario

    RiskScenario

    A row inside the assessment

    Risk assessment

    Risk scenario

    Risk levels: inherent, current, residual

    Risk acceptance

    Risk matrix

    Related

    ISO 31073:2022, term 3.3.32 — risk acceptance
    Assets
    Applied controls
    Vocabulary → Threat / Risk assessment

    Risk matrix

    Quantitative risk studies

    A quantitative risk study evaluates risk in monetary terms — the expected annualised loss from each scenario — using probabilistic methods rather than a qualitative matrix.

    It's the sibling of qualitative risk assessment and EBIOS RM: same problem (what could go wrong, how bad would it be), different lens (statistics rather than categories).

    Mental model

    A study is the container for one quantitative analysis. It comprises scenarios — each one a discrete risk being modelled — and each scenario comprises one or more hypotheses, typically one per risk stage (inherent / current / residual). The hypothesis carries the probability and impact distributions plus the applied controls it assumes are in place — split into existing / added / removed sets so the delta between stages is explicit. Scenarios reference the assets they impact and the vulnerabilities they exploit, mirroring the qualitative side of the platform.

    User-facing
    Internal
    Notes

    Each scenario in the study is parametrised by one or more hypotheses:

    • A loss-event frequency distribution — how often the bad thing happens per year, expressed as a distribution rather than a point estimate.

    • A loss magnitude distribution — how much it costs when it happens, also as a distribution.

    The platform runs Monte-Carlo simulation over those distributions and derives the loss exceedance curve (LEC) plus aggregate metrics: expected loss, value-at-risk, tail loss.

    • You need to compare risk against budget — "should we spend €X on control Y?" becomes tractable when both sides are in euros.

    • You need to talk to the board or finance about risk in the language they speak.

    • You have enough data — or enough informed judgement — to bound the loss distributions.

    Qualitative methods stay useful for everything else.

    • — click walkthrough for running a study.

    — the math behind the LEC, VaR, expected shortfall, ROSI, and tolerance overlay.
  • Study

    QuantitativeRiskStudy

    Container; carries risk tolerance + loss threshold

    Scenario

    QuantitativeRiskScenario

    One row of risk

    Hypothesis

    QuantitativeRiskHypothesis

    Parameter set + Monte-Carlo simulation cache

    How it works

    When to use it

    Related

    Risk assessments
    EBIOS RM
    Guide → Cyber risk quantification
    Guide → Cyber risk quantification methodology
    Vocabulary → Quantitative risk study / scenario / hypothesis

    EBIOS RM

    EBIOS RM (Expression des Besoins et Identification des Objectifs de Sécurité — Risk Manager) is the structured risk-management method published by the French national cybersecurity agency, ANSSI.

    CISO Assistant supports EBIOS RM natively, with a dedicated object graph rather than forcing the method into a generic risk-assessment shape.

    The five workshops

    EBIOS RM organises a study around five workshops:

    1. Scope and security baseline — define the studied system, its mission, and the regulations it must comply with.

    2. Risk origins and target objectives — identify who might attack and what they want (the RO/TO couples).

    3. Strategic scenarios — model attack paths through stakeholders to reach target objectives.

    4. Operational scenarios — drop into technical detail: kill chains, attacker techniques, supporting assets touched.

    5. Risk treatment — score residual risk and plan the action plan.

    An EBIOS RM study lives in a domain (no perimeter — the study itself is the scope envelope). It unfolds through five workshops that produce, in order: feared events (undesirable outcomes on primary assets) and stakeholders in workshop 1; RO/TO couples (Risk Origin × Target Objective) in workshop 2; strategic scenarios showing high-level attack paths through stakeholders in workshop 3; and operational scenarios drilling into kill chains, operating modes, and elementary actions in workshop 4. Workshop 5 reuses the platform's standard objects — applied controls, evidence, residual risk — to treat both strategic and operational scenarios.

    User-facing
    Internal
    Notes

    EBIOS RM scenarios sit alongside qualitative risk scenarios in the same risk register: both contribute to the residual-risk picture for a perimeter, and both can be treated with the same applied controls.

    Stakeholder

    Stakeholder

    Workshop 1 — internal/external party with trust + dependency scores

    RO/TO couple

    RoTo

    Workshop 2 — Risk Origin × Target Objective

    Strategic scenario

    StrategicScenario

    Workshop 3 — uses an attack path through stakeholders

    Operational scenario

    OperationalScenario

    Workshop 4 — composed of kill chains, operating modes, elementary actions

    Applied control

    AppliedControl

    Shared with the rest of the platform; used at workshop 5

    EBIOS RM study

    EbiosRMStudy

    Container for the five workshops

    Feared event

    FearedEvent

    Workshop 1 outcome on a primary asset

    Mental model

    Mapping to qualitative risk

    Related

    Risk assessments
    Quantitative risk studies
    Guide → EBIOS RM study
    Vocabulary → EBIOS RM and related terms

    Vulnerabilities

    Catalogued weaknesses tracked through detection, triage, and remediation

    A vulnerability is a weakness in a system, process, or product that could be exploited to compromise confidentiality, integrity, or availability. CISO Assistant tracks vulnerabilities as first-class objects, separately from the incidents they may cause and the risk scenarios they feed into.

    The vulnerability surface answers two operational questions: what's exposed and are we treating it fast enough?

    Mental model

    A vulnerability sits inside a domain and points outward at what it affects (assets) and what's treating it (applied controls). Threat-intel feeds enrich it asynchronously — KEV/NVD/EUVD feeds attach security advisories, NVD enrichment tags it with CWEs. The vulnerability SLA policy is a single platform-wide setting that maps severity to a deadline: when severity changes and no explicit due date has been set, the platform recomputes the due date from the policy.

    User-facing
    Internal
    Notes
    • Identification — a name, an optional reference ID (typically a CVE), a description.

    • Severity — the shared scale (undefined / info / low / medium / high / critical).

    • Status — undefined, potential, exploitable, mitigated, fixed, not exploitable, unaffected.

    Vulnerabilities are unusual in that the platform sets a due date automatically based on severity, via the . The flow:

    1. A vulnerability is created (or its severity changes).

    2. If no explicit due date is set, the SLA policy is applied — high severity gets a tighter deadline than medium, and so on.

    3. The bulk "refresh due dates" action re-applies the policy across existing rows when the SLA configuration changes.

    Explicit due dates the user (or an import) sets are preserved — the policy only fills in the blank.

    Vulnerabilities don't live in isolation. CISO Assistant can pull from external feeds to enrich them automatically — see :

    • KEV feed flags vulnerabilities confirmed exploited in the wild.

    • EPSS feed attaches a probabilistic exploitation score.

    • NVD enrichment pulls CWE mappings, affected configurations, and references.

    These enrichments link a vulnerability to its security advisory and CWE entries, making severity triage less guesswork.

    The status field captures where each vulnerability sits in that flow; the linked applied controls and security exceptions explain how it's being treated.

    Severity → days mapping

    Affected scope — the assets exposed, and the entities (third parties) involved when relevant.
  • Treatment — linked applied controls (the remediations), security exceptions (formal deviations), CWE entries, and one or more security advisories.

  • Timing — detection date, publication date, ETA, and the SLA due date computed from the severity-driven policy.

  • Security intelligence feeds

  • Vocabulary → Vulnerability / Security advisory / CWE / Severity

  • Vulnerability

    Vulnerability

    First-class object

    Security advisory

    sec_intel.SecurityAdvisory

    Ingested from KEV / NVD / EUVD

    CWE

    sec_intel.CWE

    Common Weakness Enumeration

    SLA policy

    What a vulnerability captures

    SLA-driven due dates

    Threat-intelligence enrichment

    Lifecycle

    Related

    Vulnerability SLA policy
    Security intelligence feeds
    Applied controls
    Incidents
    Risk assessments

    GlobalSettings("vulnerability-sla")

    Vulnerability SLA policy
    detected → triaged → treated (mitigated / fixed / exception / accepted) → closed

    Audits

    An audit is the evaluation of a perimeter against a framework. It produces a per-requirement view of status, score, evidence, and the applied controls that substantiate each requirement.

    Because applied controls are decoupled from compliance requirements, a single set of controls can be evaluated against many frameworks in parallel without re-doing the work.

    An audit always lives inside a domain (the mandatory IAM scope) and is assessed against one framework. A perimeter can optionally narrow the audit further — e.g. to a specific service or process inside the domain. On creation the platform spawns one requirement assessment per requirement in the framework — those rows are where status, score, and the supporting applied controls and evidences live.

    User-facing
    Internal
    Notes

    Audit

    ComplianceAssessment

    One audit = one framework × one domain (× optional perimeter)

    Requirement assessment

    RequirementAssessment

    Per-requirement row inside the audit

    Requirement

    RequirementNode

    Read-only catalog entry from the framework library

    Domain

    The fundamental input to an audit is a framework — a published standard such as ISO/IEC 27001:2022 or NIST CSF. Frameworks ship as YAML libraries. If you can't find one that fits your needs, you can build your own and import it.

    An audit assesses compliance against the chosen framework. The evaluation of a single requirement inside an audit is called a requirement assessment.

    A requirement assessment is not a single value — it captures several dimensions at once, separating the compliance result from how the work got done and from the depth of the implementation. The point is that the same row tracks the auditor's view, the analyst's progress, and the maturity of the underlying implementation without conflating them.

    Every audit in the audit tables (and on dashboards and campaigns) shows a Progress percentage. It answers a single question: how much of the audit has been assessed?

    What counts as assessed depends on which fields the audit exposes to the auditor. A single rule drives every surface (audit tables, the audit page, journeys, and My assignments), so the number never diverges between views:

    • Status mode — the default, and active whenever the workflow status field is visible to the auditor. A requirement counts as assessed only once its status is Done. Nothing else moves the needle: a requirement can already be Compliant or scored and still not count until it is explicitly marked Done. This makes progress the analyst's own "I'm finished with this one" signal.

    • Content mode — active when the status field is hidden. A requirement counts as assessed when:

      • for questionnaire requirements, the questionnaire is fully answered (every question answered), or it already carries a result or a score;

      • otherwise, when the result is visible, as soon as it leaves the default Not assessed state (Compliant, Partially compliant, Non compliant, or Not applicable);

      • otherwise, for scoring-only audits, when the score is strictly above the applicable minimum of the scale.

    Enabling scoring pre-fills every requirement at the scale minimum, so a bare minimum score is treated as "not touched yet" and does not count. Only a score genuinely moved above the minimum counts as assessed, which stops empty maturity- or scoring-only audits from showing 100%.

    In other words, progress is an auditing-activity signal, not a compliance signal. An audit can be 100% in progress and still be largely non-compliant — the column tells you the team has gone through every requirement and reached a verdict, not that the verdicts are good. The actual compliance picture lives in the donut and score read-outs computed from the compliance result below.

    Only assessable requirements count toward the denominator — section titles and headings from the framework are skipped. When the audit is scoped to specific implementation groups, only the requirements inside those groups count, so progress reflects the work you actually committed to rather than the framework's full catalogue.

    Several frameworks ship with their requirements pre-tagged into implementation groups (IG) — labels that act as filters over the requirement catalogue. They serve two recurring purposes, depending on how the framework's authors used them:

    • Maturity tiers — basic / intermediate / advanced (CIS Controls' IG1 / IG2 / IG3, CyFun's Basic / Important / Essential, FedRAMP's Low / Moderate / High). Picking IG1 narrows the audit to the minimum baseline; IG2 adds the next tier; IG3 expands to the full catalogue. This is the "how mature do we want to be?" axis.

    • Scope or applicability — slices like physical security, SaaS, cloud, or framework-specific selectors like ISO 27001's SoA group. Picking these narrows the audit to the requirements that actually apply to your context, regardless of maturity.

    The two patterns are not exclusive — a single framework can mix them, and several IGs can be combined on the same audit. If no IG is selected the audit covers the full catalogue, and you can change the selection later (adding or removing IGs) without losing the work already done on requirements that stay in scope.

    Where IGs show up in the platform:

    • Audit scope — selected at creation, editable afterwards. Anything outside the selection isn't dropped, it's simply hidden from the audit's assessable count.

    • Progress, score, donut, and analytics — all roll-ups respect the IG selection. The Implementation Groups Breakdown widget in audit analytics shows progress per IG when you want to compare tiers.

    • Framework report — the report filter lets you re-slice the audit by IG after the fact, so the same audit can produce an IG1-only view and a full-catalogue view without re-running the assessment.

    See Multi-level support for the mechanic of selecting IGs at audit creation, and the framework library's own documentation for which IG taxonomy a given standard ships with.

    The headline dimension — the actual answer to "does this requirement hold?". Each requirement carries one of:

    • Compliant

    • Partially compliant

    • Non compliant

    • Not applicable

    This is the field that feeds the framework's compliance percentages, the report, and the cross-framework roll-ups.

    For questionnaire-driven frameworks (whether authored in the library builder or imported from an Excel source — same vocabulary on both paths), the result is computed from the compute_result tag carried by each question choice and aggregated worst-wins across the requirement's questions, with not_applicable neutral.

    If you maintain a tenant whose audits were produced under the older boolean-collapse logic, see Special cases — Recompute assessment results for the realignment procedure.

    Independently of the compliance result, each requirement assessment captures who is working on it and where they are in their process:

    • An assignee (an actor — user, team, or entity) — who is responsible for assessing this requirement.

    • A workflow status — To do / In progress / In review / Done. This is the analyst's status, not the auditor's verdict.

    The two layers exist because the same requirement can be Compliant but still In review (the analyst has reached a conclusion, but a peer hasn't validated it yet) — and an In progress requirement obviously doesn't have a final compliance result yet. Splitting analyst progress from compliance result lets dashboards and the campaign view show meaningful "still to do" counts without polluting the compliance percentage.

    When you enable extended results on the audit, each non-compliant or partially-compliant requirement can carry an additional qualification on a specific scale:

    • Major nonconformity

    • Minor nonconformity

    • Observation

    • Opportunity for improvement

    • Good practice

    This is the auditor's grading language, useful when the framework requires distinguishing major from minor non-conformities (ISO certification audits being the canonical case). It's an extra layer attached to the result — not a replacement for it.

    Beyond the binary compliance result, each requirement assessment can carry a score on the framework's scale. Scoring captures how mature or deep an implementation is, not just whether it exists. There are two ways to score, depending on what the audit needs:

    • Maturity score (single layer) — one score per requirement, typically used for CMMI-style or NIST-CSF-style maturity assessments.

    • Implementation + Documentation scores (two layers) — toggle on documentation score to split scoring into is this implemented? and is the implementation documented?. The platform computes the maturity score as the average of the enabled layers.

    Each requirement assessment uses an effective scoring scale. At audit runtime the fallback is the audit's own scoring scale (ComplianceAssessment), which is usually initialised from the framework when the audit is created. A requirement can override that audit-level scale with its own min_score, max_score, and level labels. The scoring UI, documentation score, exports, and tree views use that effective scale for the requirement.

    When an audit contains mixed scales, average-based roll-ups normalise each requirement against its effective range before aggregating, then display the result on the audit scale. Sum-based roll-ups stay raw: they add score x weight, and their maximum is the sum of each requirement's effective maximum times its weight.

    If anchor N/A to target is enabled, not-applicable requirements contribute the audit target projected onto their own effective range. If no target is configured, they contribute their effective maximum.

    Together with the compliance result, the analyst dimension, the extended results, and the scoring layers, a single requirement assessment can record: what's the compliance state, who is working on it and where they are, how severe any non-conformity is, and how mature the implementation is — all without conflating them.

    Each requirement assessment can carry a thread of comments — short, dated, author-attributed notes used for in-context conversation during the audit. They sit alongside the formal fields and don't change the compliance result or the score; they're where the back-and-forth between the analyst, the reviewer, and the auditee happens (clarifications, follow-up questions, agreed-upon next steps).

    Each comment has a body, an author, a creation timestamp, and an active / processed toggle so resolved threads can be filtered out of the default view without losing the history. Comments can be edited (the platform records the edited state), preserving who said what and when. The panel is collapsed by default and shows the comment count, so it stays out of the way until you open it.

    Comments are not exclusive to requirement assessments — the same thread is available on risk scenarios, applied controls, and findings.

    On audits, Comments is governed by two controls: the comments feature flag (the platform-wide master switch, default on) and the per-audit field-visibility editor, which lets you make the thread visible to respondents, auditor-only, or hidden. So you can keep comments enabled everywhere while still hiding the discussion from third-party respondents on a sensitive audit. Authors are also masked for third-party participants who can't see other users.

    See Comments for the full feature reference — processed state, edit history, permissions, and author privacy.

    Evidence justifies the status of a compliance requirement or proves that an applied control has been implemented. It can be a description, a link, or an uploaded file, and it can be attached to any number of applied controls or requirement assessments.

    • Applied controls

    • Findings assessments

    • Perimeters

    Mental model

    Framework

    Audit

    Progress column

    Implementation groups

    Compliance result

    Analyst dimension (assignee + workflow status)

    Extended results (severity of non-conformities)

    Scoring layers

    Comments

    Evidence

    Related

    Folder

    Required; drives IAM scoping

    Framework

    Framework

    Read-only library import

    Vocabulary → Audit / Requirement / Evidence

    Validation flows

    Formal sign-off workflow that routes assessments, policies, evidence, and other artefacts through one or more approvers

    A validation flow (labelled Validations in the sidebar) is the platform's structured sign-off workflow. It takes one or more objects — an audit, a risk assessment, a policy, a security exception, a contract, an accreditation — bundles them into a single request, and routes that request to a designated approver for a formal decision. The decision and its context are preserved as an audit trail.

    It's the answer to "who approved this, when, and on what evidence?" — the question that comes up in every certification audit, every internal review, and every regulator visit.

    Mental model

    A requester submits a validation flow for one or more objects in their domain. The flow carries optional request notes, a validation deadline, and is routed to a designated approver. The approver moves the flow through a status machine ending in one of: Accepted, Rejected, Change requested, Revoked, Expired, or Dropped. The original objects remain unchanged — what's recorded is the validation flow itself, with the link back to whatever was up for approval.

    User-facing
    Internal
    Notes

    There are two ways to start a flow, and they cover slightly different objects:

    • From the Validations list — click +, then expand the More section to attach objects. The picker offers Audits, Risk assessments, Business impact analyses, Findings assessments (follow-ups), Security exceptions, Processings (privacy), Accreditations, and Contracts (third-party). You can mix several types in one flow when they belong to the same approval decision (e.g. "approve this audit and the related exceptions").

    • From an object's own page — objects that carry a validation section let you submit the open object directly. This is the only way to route a Policy through a flow, and it's also available on audits, risk assessments, BIAs, follow-ups, exceptions, processings, accreditations, and contracts.

    So the full set of objects that can go through a validation flow is: audits, risk assessments, business impact analyses, follow-ups, policies, security exceptions, processings, accreditations, and contracts.

    The flow moves through a small state machine:

    Status
    Meaning

    The status is the audit-trail field that gets cited in evidence reports — "policy v3 was Accepted by Jane Doe on 2026-03-12" is what makes the decision provable later.

    Most ownership/assignment fields across the platform hold an actor (which can resolve to a user, a team, or an entity). The validation-flow approver is the deliberate exception: it's a foreign key to a User directly. Approval is a personal accountability act — "a named individual signed off" — and a team can't approve in the same way it can co-own work.

    When the page surfaces validation flows, it wraps the user-only approver field so the team-broadening toggle still works: switching to "include team assignments" adds every team member's user ID into the approver filter, giving you a per-team queue without changing the underlying "one named user approves" semantics.

    Each validation flow carries an optional, unique reference ID — useful when you need to cite the approval in external systems (a change-management ticket, a regulator submission, an internal governance record). The platform enforces uniqueness across the instance.

    The pattern fits anywhere a decision needs formal, traceable sign-off:

    • A policy moving from validated to published — the approver records that the document is fit for release.

    • A security exception being granted — naming the risk-owner who accepted the residual risk.

    • An audit's results being signed off before publication to stakeholders.

    It is not the right tool for casual review or peer feedback — for those, use comments, the requirement-assessment review status, or a . Validation flows are explicitly heavy: they exist so that the approval is preserved as evidence.

    • — typical objects routed through validation flows for publication

    • — lighter-weight review/remediation tracking

    • — formal risk acceptance is one of the most common reasons a validation flow is submitted

    Requester

    requester FK to User

    The platform account that submitted the flow

    Approver

    approver FK to User

    Foreign key to a User (not an actor) — approval is always personal accountability, even if assignment elsewhere can fan out to a team

    Request notes

    request_notes

    Free-text explanation of what's being asked for

    Validation deadline

    validation_deadline

    Optional date used for expiry and dashboards

    Rejected

    Declined — decision and rationale recorded

    Revoked

    Approval was rescinded after the fact (e.g. underlying conditions changed)

    Expired

    Validation deadline passed without a decision

    Dropped

    Requester withdrew the flow before a decision was reached

    A risk assessment's residual-risk acceptance — the formal capture required by ISO 27005 and most internal risk frameworks.
  • A third-party contract going through procurement sign-off.

  • My assignments — where approvers see flows queued for them
  • Actors and teams — explains why approver is a user, not an actor

  • Validation flow

    ValidationFlow

    Lives in a domain; carries the request, the bundled objects, the deadline, and the decision

    Validations (sidebar)

    validationFlows i18n key

    The list view label

    Submitted

    Sent to the approver; awaiting decision

    Change requested

    Approver wants edits before deciding; the requester reworks and resubmits

    Accepted

    Approved — decision and timestamp recorded

    What can be validated

    Status lifecycle

    Approver — user, not actor

    Reference ID

    When to use a validation flow

    Related

    My assignments
    findings assessment
    Policies
    Findings assessments
    Risk assessments

    Compliance

    Manage extended result

    Minor nonconformity, Major nonconformity, etc.

    This tutorial guides you through managing minor nonconformities and major audit results within your audits

    Go to your instance

    1. Introduction

    You will learn how to add extra attribute to your audit through extended result.

    Introduction

    2. Open your audit

    Click "ISO 27002 SOA" to access the relevant audit for managing audit results.

    Open ISO 27002 SOA Assessment

    3. Enter Edit Mode

    Click "Edit" to enable modifications on the selected audit.

    Enter Edit Mode

    4. Access More Options

    Click "More" to reveal additional settings and options for the assessment.

    Access More Options

    5. Enable extended result

    Click "on" to activate the desired feature or option within the assessment settings.

    Click "Save" to apply and store the changes made to the audit.

    Click "4.1 - Understanding the organization and its context" to examine specific requirements.

    Select the appropriate category such as major nonconformity, minor nonconformity, observation, opportunity for improvement, or good practice.

    Click the note stating "Major and minor nonconformities are only applicable when result is non-compliant or partially compliant." to understand criteria.

    Click "Save" to store the additional nonconformity or observation details.

    Click "Save" to finalize and save the observation or nonconformity information entered.

    You have successfully managed minor nonconformities and major audit results by editing, documenting, and saving relevant audit details. This ensures accurate tracking and supports effective audit management for your organization.

    7. Save audit Changes

    10. Open a requirement

    11. Choose the value for your extended result

    14. Make sure it's consistent with the audit result

    17. Select the value and save

    21. Use the Observation field for more Information

    Manage Minor Nonconformities And Audit Results Efficiently
    Enable Specific Setting
    Save Assessment Changes
    Open Context Subsection
    Choose Nonconformity Type
    Review Nonconformity Applicability
    Save Additional Entry
    Save Observation Information

    Evidence

    Evidence is anything that substantiates a claim in CISO Assistant — that a control has been implemented, that a requirement is met, or that a process is being followed as described.

    Evidence is the connective tissue between what the audit asks and what the organisation actually does.

    Mental model

    Evidence is the shared substantiation surface — the same record can back an applied control, a requirement assessment, and a finding at the same time, which is why a single proof can satisfy many frameworks at once. Each evidence comprises a chain of revisions; the latest revision holds the current attachment (with its SHA-256 hash) or external link. When a recurring task produces evidence, the corresponding task occurrence is recorded on the revision so the audit trail goes both ways.

    User-facing
    Internal
    Notes
    • An uploaded file — PDF, screenshot, configuration export, signed approval, exported policy.

    • A link to an external system — a Jira ticket, a Confluence page, a Git commit, a monitoring dashboard, a signed agreement.

    • A free-form description, when the proof is the assertion itself (rare but allowed).

    Evidence attaches to two places:

    • Applied controls — proof that the control is in place and working.

    • Requirement assessments — proof that a specific compliance requirement is met.

    Because the same applied control can satisfy many requirements across many frameworks, a single piece of evidence often substantiates compliance against several requirements at once — without duplication.

    Evidence isn't attached once and forgotten. Each piece carries metadata — description, timestamp, expiry, assignee — and a status. Auditors regularly refresh evidence: a yearly penetration-test report needs to be re-uploaded each year; an exported configuration needs to be re-pulled after each significant change.

    Each piece of evidence keeps a versioned history through evidence revisions. Replacing an attachment doesn't overwrite the previous file — it creates a new revision under the same evidence object. Every revision carries:

    • A monotonically increasing version number.

    • The attachment (file) or link for this revision.

    • An SHA-256 hash of the attachment, computed automatically and used for integrity checks.

    The current attachment shown on the evidence page is always the latest revision; older revisions remain accessible for audit. This matters when an assessor asks "what proof did you have on date X?" — the historical revision is still there.

    An observation field for notes about what changed.
  • An optional link to the task occurrence that produced it — when an evidence file is generated by completing a recurring task, the task occurrence is recorded on the revision so the audit trail goes both ways.

  • Evidence

    Evidence

    Logical record (stable identity)

    Evidence revision

    EvidenceRevision

    Versioned payload (file or link)

    Task occurrence

    TaskNode

    Optional producer back-link

    What counts as evidence

    What evidence attaches to

    Lifecycle

    Revisions

    Related

    Applied controls
    Audits
    Tasks
    Evidence preview
    Vocabulary → Evidence

    Specialised modules

    Technical postures

    A technical posture measures a fleet of assets against a technical baseline — a CIS Benchmark, a hardening guide, or any check-shaped framework — and keeps the measurements coming. Where an audit captures a considered, point-in-time evaluation, a technical posture is a living scoreboard: scanners, scripts, and operators keep pushing results, and the platform always shows the latest state of every check on every asset.

    Technical postures are gated by the posture_assessments feature flag. Default off. See .

    Mental model

    A technical posture always lives inside a domain and is measured against one framework, whose assessable requirements act as the check list. It monitors a set of assets, and every ingestion of results — a manual entry session, an API push, a file import — is recorded as a run carrying one check result per (check, asset) it touched. An optional follow-up findings assessment is where remediation of failing checks is tracked.

    User-facing
    Internal
    Notes

    Think of a technical posture as a three-dimensional cube of measurements:

    • Checks — the assessable requirements of the chosen framework. If the framework defines implementation groups (for example Automated vs Manual recommendations in a CIS Benchmark), the Selected implementation groups field narrows the check list to the slice you committed to.

    • Assets — the fleet under measurement. Assets can be enrolled explicitly, or automatically the first time results arrive for them.

    • History — for each (check, asset) cell, the platform keeps the last N results, where N is the

    The cube is sparse on purpose: nothing is created upfront. A cell only exists once something has measured it, and the Measured checks read-out tells you how much of the cube is filled. The current posture — what the overview, the score, and the action plan are computed from — is simply the latest result in each cell.

    Each result carries one of five values: Pass, Fail, Not applicable, Error, or Not checked, along with the observed and expected values and a message when the source provides them. The Pass rate score is computed over Pass and Fail only — errors and unchecked cells don't dilute it.

    Technical postures deliberately do less than :

    Audit
    Technical posture

    The two share the same framework catalogue, so a benchmark imported once can back both a formal audit and a running posture. Use an audit when a human needs to weigh evidence and sign off; use a technical posture when a tool can answer the question and you want it answered often.

    Every way of getting results in produces a run:

    • Manual runs — the "New manual run" flow on the Runs tab, or per-asset editing in the tree view, for checks a human performs.

    • API — scanners push JSON to the assessment's upload-results endpoint; re-using the returned run identifier accumulates or patches the same run. The API tab shows a ready-to-copy example.

    • File import — the "Import results" button on the Runs tab accepts CSV and XLSX files as well as OCSF Compliance Finding JSON. A mapping dialog lets you bind arbitrary scanner CSV columns and result values, choose how colliding rows aggregate, and target one or several of the scoped assets.

    Runs are the ingestion log of the assessment: the Runs tab lists them with their tool, check counts, and pass/fail breakdown, and a run's detail page shows exactly what it recorded per asset. The trend chart on the Overview tab plots the pass rate across runs, which is how posture drift becomes visible.

    The Action plan tab lists every check whose current result is anything other than Pass — failures first, then errors, then unchecked and not-applicable cells — so the operational team can decide what to investigate. From there, each line can be turned into a finding with one click.

    Findings do not live on the technical posture itself. They are created in the follow-up assessment, a regular findings assessment linked to the posture (the creation form offers to create one automatically via Create a related findings assessment). This separation is deliberate:

    • Measurements are ephemeral; remediation is not. A check result is overwritten by the next run and eventually pruned by the history depth. A finding needs a stable life of its own — status, owner, ETA, severity, linked applied controls — that survives every re-measurement. Pinning remediation to a measurement row would lose it on the next scan.

    • Remediation is a shared discipline. Findings assessments are the platform's common remediation ledger — the same object used for pentest reports and internal reviews. Routing posture failures into one means they benefit from the full findings workflow (action plans, applied controls, reporting) instead of a parallel, posture-only mechanism.

    • The posture stays a pure measurement surface.

    The link is kept visible in both directions: the action plan shows the finding attached to each failing check with its status and ETA, and re-measuring a remediated check back to Pass is how the fix is verified — on the next run, not by declaration.

    Assessable requirement from the framework library

    Follow-up assessment

    FindingsAssessment

    Findings assessment with the "Posture follow-up" category

    Domain

    Folder

    Required; drives IAM scoping

    History depth
    of the assessment (10 by default). Older results are pruned as new ones arrive.

    Result

    Compliance result, score, maturity — set by a person

    Pass/fail vocabulary — set by whatever measured it

    Substantiation

    Evidences and applied controls per requirement

    Observed vs expected values from the measurement

    Cadence

    Campaign or review cycle

    Continuous — every scan is a new run

    The cube tells you
    what is true right now
    ; the follow-up assessment tells you
    what you are doing about it
    . Either can be read — or rebuilt — without touching the other.

    Technical posture

    PostureAssessment

    One framework × one domain × a set of assets

    Run

    PostureRun

    One ingestion event; keeps the tool name and start time

    Check result

    PostureResult

    One measurement of one check on one asset

    Check

    Question answered

    "Are we compliant, and can we prove it?"

    "What is passing right now, and what changed?"

    Rows

    One requirement assessment per requirement, created upfront

    Sparse — only measured cells exist

    The measurement cube

    Lightweight by design

    Runs

    Findings and remediation

    audits
    Feature flags

    RequirementNode

    Project management

    The project-management module brings PMBOK-style planning into CISO Assistant: a structured way to organise complex, multi-stakeholder initiatives — go-lives, accreditations, transformation programmes — alongside the compliance and risk work they drive.

    It's the newest concept in the platform, and the object graph will continue to evolve.

    Mental model

    A project sits in a domain and can stack as a portfolio → programme → project hierarchy (the same model with three values of kind). On creation it's auto-paired with a generic collection — the flexible bag where the audits, risk studies, findings, evidences, and policies tied to the project accumulate. A responsibility matrix can be attached to one or more projects, encoding RACI / RASCI / RAPID assignments of actors to activities (each activity in turn references the work objects it covers). An accreditation is the formal authorisation event: it links its decision evidence and its compliance-assessment checklist back to the project's collection.

    User-facing
    Internal
    Notes

    Project objects don't replace — they sit alongside. Use a perimeter to define the scope of assessment; use a project to plan the work needed to bring that scope into compliance or through an accreditation.

    A single project typically references many perimeters, audits, applied controls, and findings assessments — it's the cross-cutting view the security organisation works against day-to-day.

    Every project carries a Budget and an Actual cost field (with a currency that defaults to the instance setting), so leadership has a place to capture the financial envelope an initiative is operating under and what's been consumed against it.

    This is deliberately the high-level view only. The project's budget number is not computed from anywhere — it's the planned envelope a sponsor signed off on, and the actual cost is whatever spend you record against it. Both are decimal money values, not roll-ups.

    The detailed financial picture — line items, build vs run split, amortisation, who's spending — lives where the work actually happens: on the referenced by the audits, risk studies, findings assessments, and other objects sitting in the project's . Each applied control carries its own structured cost; the of every assessment in the collection rolls those costs up into a budget overview.

    The link between the two layers is indirect: applied controls aren't attached to a project directly. They're attached to the work objects inside the project's collection (a control satisfies an audit's requirement, mitigates a risk scenario, remediates a finding), and through that chain they become part of the project's financial picture.

    When the project budget and the rolled-up applied-control costs diverge, that gap is itself a signal — you've either committed more spend than the project envelope foresaw, or your action-plan controls are missing cost data. The platform doesn't flag the gap automatically; the numbers are surfaced on both sides for the project manager to reconcile.

    • — the detailed build / run cost model that drives the bottom-up view.

    • — where the rolled-up cost of an assessment's controls is shown.

    Row of a matrix; many M2Ms to work objects

    Assignment

    ResponsibilityAssignment

    RACI cell — (activity, actor, role) unique

    Accreditation

    Accreditation

    Linked to a Collection; checklist FK to ComplianceAssessment

    Vocabulary → Project / Accreditation / Responsibility matrix / Generic collection

    Project

    Project

    kind enum (Portfolio / Program / Project); self-FK parent_project

    Collection

    GenericCollection

    Polymorphic bag (audits, risk / EBIOS / CRQ studies, findings, evidence, policies, exceptions)

    Responsibility matrix

    ResponsibilityMatrix

    RACI / RASCI / RAPID / Custom; M2M to Project

    Activity

    Where it fits

    Budget — high-level on the project, details on the controls

    Related

    Perimeters
    applied controls
    generic collection
    action plan
    Applied controls — Financial tracking
    Action plans
    Perimeters

    ResponsibilityMatrixActivity

    Third-party risk

    Third-party risk management (TPRM) is the discipline of evaluating the security and compliance posture of the vendors, suppliers, and service providers your organisation depends on.

    CISO Assistant treats third parties as a first-class concern with their own object graph, separate from internal compliance work.

    Mental model

    Four interlocking objects model the third-party landscape:

    • Entity — a vendor, supplier, or service provider. The unit of organisational identity.

    • Solution — a specific product or service provided by an entity. An entity can have many solutions.

    • Contract — the formal agreement covering one or more solutions, with dates, renewal terms, and obligations.

    • Representative — the person on the entity side who answers questionnaires and signs off on assessments.

    The actual review of a third party is an entity assessment. It can:

    • Use a questionnaire — custom, or imported from a library (CAIQ, SIG, …).

    • Trigger an internal audit that lives in the entity's domain, so the third party can fill it in directly.

    • Capture the residual risk you accept by working with this entity.

    CISO Assistant supports two modes for getting the actual answers back from the vendor, depending on whether the third party is allowed to access your instance.

    This is the default workflow. You create a representative on the entity side, the platform issues credentials, and the representative logs into CISO Assistant directly to fill in the questionnaire. Their access is scoped: they only see the entity assessment(s) attached to their entity, and they land in a dedicated third-party / auditee surface — a separate route group with its own auditee dashboard, not the rest of your workspace.

    This surface is gated by the auditee_mode , which has to be on for the third-party login flow to be available.

    Use this mode when:

    • Your instance is reachable from the internet (or from the vendor's network).

    • You want live progress visibility — answers land in the database as they're typed, so the dashboard updates in real time.

    • You want comments, validation flows, and the full audit trail to apply to the vendor's answers automatically.

    Don't confuse this with the feature — that one is for internal users splitting one audit across teammates using the respondent role within your own organisation. The third-party flow described here is for external vendors answering through the auditee surface.

    Many organisations don't want to expose their CISO Assistant instance to third parties — for security, network, or contractual reasons. In that case, the platform supports a fully file-based round trip:

    1. Export the questionnaire from the framework page. On the framework backing the entity assessment, use the Export to Excel action. You get an .xlsx file containing every requirement of the framework, structured so the vendor can fill in the answers, observations, and supporting evidence references in dedicated columns.

    2. Send the file to the vendor. Email, secure file share, sneakernet — whatever channel your procurement and security policies allow. The vendor opens the spreadsheet in any tool that can edit Excel.

    Use this mode when:

    • Your instance can't be (or shouldn't be) exposed to the vendor's environment.

    • The vendor refuses to log into a third-party platform.

    • You want a tangible artefact — the signed-off Excel — as part of the audit record.

    Both modes produce the same internal state at the end: a populated entity assessment with per-requirement answers and observations. You can mix them within an organisation (online for one vendor, offline for another) or switch a single vendor from one mode to the other mid-cycle if the situation changes.

    Treating third parties as a parallel surface — rather than just "another perimeter" — matters because:

    • Permissions differ: third-party representatives need restricted access, not full role-assignment privileges in your domain.

    • Lifecycle differs: contracts have renewal dates, vendors come and go, but your internal frameworks stay stable.

    • Reporting differs: TPRM dashboards aggregate across many entities, not down inside one.

    Receive the filled-in file back.
    The vendor returns the spreadsheet with their answers populated. No platform access was needed at any point.
  • Re-import via the data import wizard. Use the to upload the filled-in spreadsheet. The wizard maps the rows back to the requirement assessments on the existing entity assessment, populating answers, observations, and any other captured columns.

  • Entity assessment

    How the vendor answers the questionnaire

    Online mode — the representative logs in

    Offline mode — Excel exchange via the data wizard

    Why a separate model

    Related

    feature flag
    Assignments / respondent mode
    Domains
    Audits
    Guide → Third-party risk management
    data import wizard
    Vocabulary → Entity / Solution / Contract / Representative / Entity assessment

    Terminology

    Organisation-defined labels that override the platform's defaults

    CISO Assistant ships with a default vocabulary for the values that appear in dropdowns and badges across the UI — risk origin types in EBIOS RM, project status values, qualifications on incidents, accreditation status labels, metric units, and so on. The terminology layer lets each organisation override those defaults to match its own internal vocabulary, without changing the platform's data model.

    Why it exists

    Two organisations can use CISO Assistant against the same framework and the same methodology, but speak entirely different internal languages. One team's "Risk Origin: state-actor" is another team's "Adversary: nation-state". The terminology surface lets you reshape the labels without forking the platform.

    How it works

    A terminology entry binds a label to a field path — the specific UI surface where the label appears. The shipped field paths today cover:

    • ro_to.risk_origin — Risk Origin types on RO/TO couples in EBIOS RM.

    • qualifications — qualification tags on incidents, risk scenarios, and BIA escalation thresholds. The word qualification itself can be swapped for risk category across the interface via .

    • accreditation.status and accreditation.category — labels on accreditation records.

    • entity.relationship — third-party relationship types.

    • metric_definition.unit — units shown alongside metric values.

    • project.status and project.health — workflow labels on projects.

    • processing.nature — the nature of a processing activity (collection, storage, disclosure, erasure, …) in the privacy register.

    • personal_data.category — categories of personal data (name, email, health data, …) in the privacy register.

    For each field path, the platform ships a built-in set of entries (state, organised crime, terrorist, activist, … for risk origins, for example). You can:

    • Hide built-in entries you don't want to surface — the is_visible flag controls dropdown inclusion.

    • Add organisation-specific entries alongside the built-ins.

    • Translate entries through the standard library translation mechanism.

    The platform falls back to the built-in default whenever an entry is missing or hidden — terminology is additive on top of a working set, not a replacement.

    Terminology entries live in the root folder by default, meaning they apply organisation-wide. Built-in entries cannot be deleted; they can only be hidden.

    In the sidebar under Extra → Terminologies. The feature is gated by the terminologies feature flag, which is on by default.

    • — a different kind of organisation-defined override

    Scoping

    Where you find it

    Related

    General settings
    Vocabulary → Terminology
    Custom roles

    Object classifications

    Organisation-defined sensitivity schemes — like TLP — with ordered, coloured levels

    An object classification is a scheme that marks how sensitive an object is — think TLP (Traffic Light Protocol), or a custom scale aligned to a customer's or an authority's own tiers. Each scheme is an ordered set of levels, and any object that supports classification can be tagged with one of them.

    CISO Assistant ships with TLP built in, and lets you tune it or define your own schemes alongside it.

    Why it exists

    Organisations exchange documents with customers, partners, and authorities that each impose their own sensitivity tiers. One party works in TLP; another in a national CONFIDENTIAL / SECRET scale; a customer in its own bespoke levels. Object classifications let you define those schemes once and apply them consistently, with colour coding people already recognise.

    Mental model

    A scheme comprises an ordered set of levels. Each level carries a rank (its position in the order, from least to most sensitive), a colour, an abbreviation, and a translatable name and description. A level can then classify an object — today, a document — which surfaces it as a coloured badge and, on published PDFs, a page marking. The dashed edge is deliberate: classifying an object is always optional.

    A scheme is a thin container with a name and an ID (TLP, for example). Its meaning lives in its levels, which are ordered by rank:

    • Rank sets the order and carries semantic weight — a higher rank is more sensitive. TLP runs CLEAR < GREEN < AMBER < AMBER+STRICT < RED.

    • Colour is the swatch shown wherever the level appears; the platform picks readable text automatically over it.

    • Abbreviation is the short token on the badge (AMBER

    The built-in TLP scheme follows the FIRST TLP 2.0 standard — five levels with their official colours. Its structure is protected: you can hide levels you don't use, but you can't delete or reorder the canonical set.

    Because levels are ranked rather than just listed, the order is data, not decoration — "at least AMBER" is a well-defined comparison. Today a classification is a visual marking; the ordinal rank is the foundation for comparing and, in future, gating access by level.

    Open a scheme to reach its level editor, where you can:

    • Add a custom level with Add level — set its abbreviation, name, and colour; it slots in at the end of the order.

    • Reorder levels with the up/down controls (rank follows the order).

    • Hide a level with its visibility toggle — it stops being offered without being destroyed.

    Built-in levels (and the built-in TLP scheme itself) can only be hidden, never deleted or restructured — so the canonical TLP always stays intact, and a hidden level stays hidden across restarts.

    When you create or edit a document, the Classification field lets you pick a level. Once set, the level shows as a coloured badge on the document catalog, in the reader, and in the documents table, and it is stamped on every page of the document's exported PDF (for example TLP:AMBER, in the level's colour). Deleting a level a document points at simply clears the field — the document is never removed.

    Documents are the first object type to carry a classification; the same mechanism extends to other objects over time.

    Schemes and their levels live in the global (root) folder — they apply organisation-wide. Multiple schemes can coexist, so TLP and a customer-specific scheme are both available at once.

    In the sidebar under Extra → Object classifications. The list shows every scheme; open one to manage its levels. Access is governed by the standard permissions — viewing is available to every role, while creating and editing schemes and levels is reserved for administrators.

    • — the first object type that carries a classification

    • — a related organisation-defined override layer

    ,
    RED
    ).
  • Name and description are translatable, so a level reads in the user's language.

  • Edit or delete custom levels.

    How it works

    Ordering carries meaning

    Classification is currently cosmetic — a badge and a document marking. The rank is designed so that a later access-control layer can treat a clearance as granting every lower level, without reworking the data.

    Customising a scheme

    Applying a classification to a document

    Scoping

    Where you find it

    Related

    Documents
    Terminology

    Overview

    CISO Assistant is delivered as a set of containers — frontend, backend, database, and reverse proxy — that can run locally via Docker, on a VPS, or on Kubernetes via the Helm chart. The diagram below sketches how the pieces fit together.

    This section is being expanded.

    Material to come: prerequisites, local Docker setup, virtualisation and remote deployment, deploying on a VPS, the Helm chart, S3 storage, mailer, custom certificates, secrets management, and instance upgrades.

    System architecture

    Quick start

    Docker Compose or Helm for Kubernetes

    Config Builder

    Customise the local deployment according to your needs:

    Make sure to have Docker 27 or above. If you get an error saying the docker compose command is not recognised, your Docker version is too old.

    Docker Compose

    Make sure Docker and Docker Compose are installed on your system.

    • clone the repo: git clone https://github.com/intuitem/ciso-assistant-community.git

    • run the preparation script and follow the instructions: ./docker-compose.sh

    You can also find other variants for different setups as a starting point for your specific needs:

    Make sure the Helm binary is installed and switch to your cluster context. The chart is published to a GitHub OCI registry — no helm repo add needed.

    1. Pull the default values:

    2. Edit custom.yaml for your environment. At minimum, look at:

      • global.domain — the hostname your instance will serve on.

    See for the full procedure (image tag pinning, values reference, and operational notes).

    Privacy register

    A privacy register is the catalogue of personal-data processing activities the organisation carries out — required by GDPR and equivalent regulations as the foundation of accountable data handling.

    CISO Assistant models the register as a graph of typed objects so it stays queryable, auditable, and reusable across audits.

    • Processing — an activity that operates on personal data (collect, store, transfer, delete). The central object.

    • Purpose — the lawful reason a processing exists. Each processing has at least one purpose.

    global.tls and ingress.tls.* — enable TLS.

  • backend.config.djangoSecretKey — rotate from the default.

  • backend.config.databaseType (sqlite, pgsql, or externalPgsql) and the matching postgresql.* / externalPgsql.* block.

  • Create a namespace: kubectl create ns ciso-assistant

  • Install: helm install ciso-assistant-release oci://ghcr.io/intuitem/helm-charts/ce/ciso-assistant -f custom.yaml -n ciso-assistant

  • helm show values oci://ghcr.io/intuitem/helm-charts/ce/ciso-assistant > custom.yaml

    Helm chart

    This setup assumes Caddy will handle TLS on your behalf. If you experience SSL-related issues, you may need to patch your ingress-nginx-controller to enable the enable-ssl-passthrough flag.

    Remote / Virtualization
    Deploy on a VPS
    Helm Chart
  • Personal data — what is being processed (name, email, location, health record, biometric, …), with categories that map to GDPR sensitivity classes.

  • Data subject — the kind of individual the data refers to (employee, customer, prospect, …).

  • Data recipient — the internal teams or external parties that receive the data.

  • Data contractor — third parties that process data on your behalf — a TPRM entity surfaced here with a privacy-specific lens.

  • Data transfer — flows of data to entities outside the original jurisdiction.

  • Privacy operations also need to record events as they happen:

    • Right requests — data-subject requests under GDPR (access, rectification, erasure, portability) and the organisation's response.

    • Data breaches — incidents affecting personal data, with the notification clock and authority correspondence.

    • A privacy register lives in a domain with its own RBAC scoping — typically a DPO-led folder.

    • Findings from GDPR audits surface in the register as actions on processings.

    • Data contractors cross-reference TPRM entities, so a sub-processor's security review feeds both worlds.

    • A processing's nature and its personal-data categories draw from the layer, so you can align them to your own internal vocabulary.

    • A processing can be exported as a multi-sheet Excel workbook from its detail page and re-imported — through the data import wizard or the CLI — to recreate it with all its sub-objects. See .

    • Domains

    • Third-party risk

    • Terminology — customise processing nature and personal-data category labels

    Mental model

    Personal data entries can be created in batch from a processing's detail page: the Batch create personal data button (layer-group icon on the Personal Data table) opens a picker of categories grouped by theme — drawn from the layer — and applies the same Retention, Deletion Policy, and Is sensitive values to every entry it creates. Categories the processing already records are skipped.

    Event objects

    How it ties into the rest of the platform

    Related

    terminology
    Data import
    Vocabulary → Processing / Personal data / Purpose / Right request / Data breach
    terminology

    Prerequisites

    Prerequisites to Install CISO Assistant On-Premises

    1. Hardware Requirements:

      1. CPU: 4 cores

      2. RAM: Minimum 16 GB

      3. Storage: Minimum 10 GB (consider more for evidences)

    You can start with lower specs of course for testing.

    1. Software Requirements:

      1. Ubuntu/Debian, CentOS, RHEL: LTS versions recommended when applicable*

      2. Docker 27 or up, with Docker compose, or Kubernetes Cluster 1.31 or up

    *most Linux distributions supporting Docker should be compatible but have not been tested. Some distributions are not using the official repositories so make sure to follow the instructions from docker page.

    Postgres 16 or up if you are choosing this variant
  • Any SMTP compatible Mailer

  • Deployment methods

    Docker rootless configuration

    Deployment documentation for rootless containers

    Since V3.16, CISO Assistant now runs as non-root user 1001:1001 by default across all compose templates.

    If you already have a local instance of CISO Assistant, please refer to the migration guide

    Fresh install

    If you are new from Ciso-Assistant, you will automatically be deployed with a rootless Docker configuration by running pre-built images or local image build

    Using pre-built images

    ./docker-compose.sh

    Using image local build

    ./docker-compose-build.sh

    Migration guide

    You already have a self-hosted Ciso Assistant (Community version or On-Premise Pro version) and you want to know all the options you have:

    I want a rootless Docker and I am currently running CISO Assistant with pre-built images

    Then update your docker-compose.yml on the version you want (ex: v3.16) or keep latest tag and then ignore the manual update in your file.

    Your new containers should be root-less!

    If you have any doubt about updating your custom .yml, do not hesitate to contact us on our Discord or Support portal.

    I want a rootless Docker and I am currently running CISO Assistant with local images

    Keep root Docker

    In the case you do not want to have rootless Docker

    Keep the root Docker as it was before

    Then manually update your docker-compose.yml on the images version you want (ex: v3.16). Ignore this step if you use latest image

    That is it! Since you did not update the github repository, the docker-compose.yml keeps the initial form without root less Docker configuration

    Simple rootless check

    If you want to verify if you run a rootless Docker container, do:

    docker exec -it backend id

    It should say :

    uid=1001 gid=1001 groups=1001

    You are using docker-compose.yml to deploy Ciso Assistant

    git pull
    docker compose down
    sudo chown -R 1001:1001 ./db
    docker compose up -d

    You are using a custom .yml to deploy Ciso Assistant

    git pull
    docker compose down
    sudo chown -R 1001:1001 ./db
    docker compose -f docker-compose-build.yml up -d

    In the case you did update the github repository by doing a git pull command, we suggest you to take an older version of the file (like the v3.15.5 docker-compose.yml version)

    docker compose down
    image: ghcr.io/intuitem/ciso-assistant-community/frontend:v3.15.2
    # replace with (for example)
    image: ghcr.io/intuitem/ciso-assistant-community/frontend:v3.16
    docker compose up -d

    Custom certificates

    How to add custom certificates for your remote installation

    You can configure your own Certificate by replacing the line tls internal in the docker-compose.yml by tls <cert_file> <key_file>. Here is Caddy documentation on this https://caddyserver.com/docs/caddyfile/directives/tls

    Before doing this, there is just one step, you need to add the cert_file and the key_file inside caddy container.

    You have basically two ways to do it:

    • Adding the two files inside caddy_data directory, as it is already mounted by default in the volumes, and specify the path to the files:

    • If you don’t have this volume or you want to add another, create a repository at the same level of your docker compose file for example /certs, add the files inside and moun it:

    Local

    Basic setup for local deployment and experimentation

    The recommended pattern for local deployment is to use Docker Compose. Check the Readme file on the CISO Assistant repo for the latest instructions.

    The compose file will manage three containers and set the required variables:

    • Front

    • Back

    • Caddy (proxy)

    • Make sure to have a recent version of Docker installed

      • On a Linux distro with a server flavor, make sure to remove older versions and install the latest one using the proper Docker repos to avoid twisted setups. Check out the instructions at

    • On Windows, Docker Desktop+WSL is recommended

    • On MacOS, Docker Desktop covers the requirements

    Run:

    It will clean up previous images and get the latest stable release.

    Once the images are downloaded and migration triggered, you should see a prompt asking you to set the first superuser. Follow the instructions to set it, and you should be ready.

    In case you are running on an unsupported architecture, you can open a GitHub issue so that we add its support or use the next steps to build the images locally.

    Alternatively, if the previous configuration didn't succeed, run:

    Given that Caddy is using a self-signed certificate, your browser will mention a warning that you can accept and continue.

    caddy:
        container_name: caddy
        image: caddy:2.11.4
        ...
        volumes:
          - ./caddy_data:/data
        command: |
          sh -c 'echo $$CISO_ASSISTANT_URL "{
          reverse_proxy /api/* backend:8000
          reverse_proxy /* frontend:3000
          tls /data/<path>/cert_file /data/<path>/key_file
          }" > Caddyfile && caddy run'

    Using prebuilt images

    Re-building the images locally

    SSL Warning

    https://docs.docker.com/engine/install/ubuntu/
    caddy:
        container_name: caddy
        image: caddy:2.11.4
        ...
        volumes:
          - ./caddy_data:/data
          - ./certs:/certs
        command: |
          sh -c 'echo $$CISO_ASSISTANT_URL "{
          reverse_proxy /api/* backend:8000
          reverse_proxy /* frontend:3000
          tls /certs/cert_file /certs/key_file
          }" > Caddyfile && caddy run'
    ./docker-compose.sh
    ./docker-compose-build.sh

    Deploy on a VPS

    Virtual Private Server - Remote internet-facing VM

    This setup aims to expose CISO Assistant on a VPS while using automated Let's Encrypt for certificates management.

    1. provision your VPS and make sure it has a public reachable IP - make sure to have the Prerequisites mentioned on that page.

    2. Setup your DNS zone to point to the IP of your VPS (A record). Give it sometime to propagate (depends on the registrar). It's better to start with this once you get the IP to give it enough time for propagation.

    3. on the following I'm using ubuntu 24.04. So adjust the packages installation according to your OS

    4. ssh to your server and perform the following commands:

    1. Follow the instructions and make sure to do the following:

    • select VM/Remote

    • Internet facing and ACME ready - yes

    • Provide the FQDN you've set on your registrar

    • Port to use: 443

    It should look like something like this:

    1. Keep track of the URL mentioned at the end of the config generator. You can review the generated yml file and adapt it if needed.

    Wait for the app to initialize and you will get a prompt to enter the first admin user and the password.

    You can go back and update the docker-compose.yml according to your needs or restart the interactive guide to create a new one.

    You can choose Traefik or BunkerWeb instead of Caddy using the config builder. Please note that BunkerWeb deployment is still experimental at the moment.

    • The generated file in the config directory will be named docker-compose-custom.yml For subsequent operations with compose, you'll need to specify it with -f

    • If you're running docker compose without the -f, it could conflict with the default one on the repository root directory.

    • If you're starting a production environment:

  • make sure to disable the debug mode,

  • have your docker-compose-custom renamed and stored out of the repo,

  • have your db folder outside of the repo.

  • #update ubuntu repository and OS
    sudo apt update
    sudo apt upgrade
    
    # install docker
    sudo snap install docker
    
    #install python
    sudo apt install python3-pip python3.14-venv
    
    #clone the repo
    git clone https://github.com/intuitem/ciso-assistant-community.git
    
    #go to the config generator
    cd ciso-assistant-community
    cd config
    
    # setting up the python project and dependencies
    python3 -m venv .venv
    source .venv/bin/activate
    pip install -r requirements.txt
    
    # run the interactive config generator
    python make_config.py
    # switch to sudo. This can be avoided depending on your docker setup
    sudo su
    ./docker-compose.sh
    cd config
    # stop and remove containers
    docker compose -f docker-compose-custom.yml rm -fs
    # delete the db and proxy config
    git clean -fdx .

    Notes

    Clean up

    Post-install setup

    Setting up S3

    How to connect your S3 block storage for your installation

    By default, CISO Assistant stores attachments on the local filesystem. You can configure it to use an S3-compatible object storage (AWS S3, MinIO, etc.).

    Prerequisitories

    • A running S3-compatible storage

    • An existing bucket (must be created before starting CISO Assistant)

    • Valid access credentials (Access Key / Secret Key)

    Set the following environment variables in the backend environment:

    That's it ! You can now launch your backend and your attachments will be sent to your S3 🔥

    You can test S3 support using MinIO:

    Then go on , enter your minio root user/password and create a bucket with the name 'my-ciso-bucket'.

    The backend environment variables will be:

    You can now see your attachments on the MinIO console after importing them in ciso-assistant.

    Configure environment variables

    Example case : local MinIO block storage

    http://localhost:9001
    export USE_S3=True
    export AWS_ACCESS_KEY_ID=<your-access-key>
    export AWS_SECRET_ACCESS_KEY=<your-secret-key>
    export AWS_STORAGE_BUCKET_NAME=<your-bucket-name>
    export AWS_S3_ENDPOINT_URL=<your-s3-endpoint>
    docker run -d \
      --name minio \
      -p 9000:9000 \
      -p 9001:9001 \
      -e MINIO_ROOT_USER=ciso-assistant-admin \
      -e MINIO_ROOT_PASSWORD=not_secure_password \
      -v minio_data:/data \
      minio/minio server /data --console-address ":9001"
    export USE_S3=True
    export AWS_ACCESS_KEY_ID=ciso-assistant-admin
    export AWS_SECRET_ACCESS_KEY=not_secure_password
    export AWS_STORAGE_BUCKET_NAME=my-ciso-bucket
    export AWS_S3_ENDPOINT_URL=http://localhost:9000

    Managing secrets

    This guide covers how to keep sensitive configuration (database credentials, mailer passwords, API keys) out of your docker-compose.yml.

    1. The .env File

    Docker Compose automatically loads variables from a .env file located next to docker-compose.yml. This is the recommended approach for all secrets.

    Create the .env file

    # .env
    
    # ── Postgres ───────────────────────────
    POSTGRES_NAME=ciso_assistant
    POSTGRES_USER=ciso_assistant
    POSTGRES_PASSWORD=change-me-to-something-strong
    
    # ── Django / Backend ───────────────────
    DJANGO_DEBUG=False
    CISO_ASSISTANT_URL=https://localhost:8443
    ALLOWED_HOSTS=backend,localhost
    CISO_SUPERUSER_EMAIL=admin@example.com
    
    # ── Mailer ─────────────────────────────
    EMAIL_HOST=smtp.example.com
    EMAIL_PORT=587
    EMAIL_USE_TLS=True
    EMAIL_HOST_USER=notifications@example.com
    EMAIL_HOST_PASSWORD=smtp-secret-password
    DEFAULT_FROM_EMAIL=ciso-assistant@example.com
    
    # ── Rescue Mailer (optional) ──────────
    # EMAIL_HOST_RESCUE=smtp2.example.com
    # EMAIL_PORT_RESCUE=587
    # EMAIL_HOST_USER_RESCUE=rescue@example.com
    # EMAIL_HOST_PASSWORD_RESCUE=rescue-secret
    # EMAIL_USE_TLS_RESCUE=True
    
    # ── S3 Storage (optional) ─────────────
    # USE_S3=True
    # AWS_ACCESS_KEY_ID=AKIA...
    # AWS_SECRET_ACCESS_KEY=wJal...
    # AWS_STORAGE_BUCKET_NAME=my-bucket
    # AWS_S3_ENDPOINT_URL=https://s3.eu-west-1.amazonaws.com

    Reference variables in docker-compose.yml

    Replace every hardcoded value with a ${VARIABLE} reference:

    services:
      backend:
        container_name: backend
        build:
          context: ./backend
          dockerfile: Dockerfile
        restart: always
        depends_on:
          - postgres
        environment:
          - ALLOWED_HOSTS=${ALLOWED_HOSTS}
          - CISO_ASSISTANT_URL=${CISO_ASSISTANT_URL}
          - DJANGO_DEBUG=${DJANGO_DEBUG}
          - POSTGRES_NAME=${POSTGRES_NAME}
          - POSTGRES_USER=${POSTGRES_USER}
          - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
          - DB_HOST=postgres
          - EMAIL_HOST=${EMAIL_HOST}
          - EMAIL_PORT=${EMAIL_PORT}
          - EMAIL_USE_TLS=${EMAIL_USE_TLS}
          - EMAIL_HOST_USER=${EMAIL_HOST_USER}
          - EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}
          - DEFAULT_FROM_EMAIL=${DEFAULT_FROM_EMAIL}
          - CISO_SUPERUSER_EMAIL=${CISO_SUPERUSER_EMAIL}
        volumes:
          - ./db:/code/db
    
      huey:
        container_name: huey
        build:
          context: ./backend
          dockerfile: Dockerfile
        depends_on:
          - backend
        restart: always
        environment:
          - ALLOWED_HOSTS=${ALLOWED_HOSTS}
          - CISO_ASSISTANT_URL=${CISO_ASSISTANT_URL}
          - DJANGO_DEBUG=False
          - POSTGRES_NAME=${POSTGRES_NAME}
          - POSTGRES_USER=${POSTGRES_USER}
          - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
          - DB_HOST=postgres
        volumes:
          - ./db:/code/db
        entrypoint:
          - /bin/sh
          - -c
          - |
            uv run python manage.py run_huey -w 2 --scheduler-interval 60
    
      frontend:
        container_name: frontend
        environment:
          - PUBLIC_BACKEND_API_URL=http://backend:8000/api
          - PROTOCOL_HEADER=x-forwarded-proto
          - HOST_HEADER=x-forwarded-host
        build:
          context: ./frontend
          dockerfile: Dockerfile
        depends_on:
          - backend
    
      postgres:
        container_name: postgres
        image: postgres:16
        restart: always
        environment:
          POSTGRES_DB: ${POSTGRES_NAME}
          POSTGRES_USER: ${POSTGRES_USER}
          POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
        volumes:
          - ./db/pg:/var/lib/postgresql/data
    
      caddy:
        container_name: caddy
        image: caddy:2.11.4
        restart: unless-stopped
        ports:
          - 8443:8443
        command:
          - caddy
          - reverse-proxy
          - --from
          - https://localhost:8443
          - --to
          - frontend:3000
        volumes:
          - ./db:/data

    Tip — DRY with YAML anchors: Since backend and huey share most variables, you can use extension fields to avoid repetition:

    x-common-env: &common-env
      ALLOWED_HOSTS: ${ALLOWED_HOSTS}
      CISO_ASSISTANT_URL: ${CISO_ASSISTANT_URL}
      POSTGRES_NAME: ${POSTGRES_NAME}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      DB_HOST: postgres
    
    services:
      backend:
        environment:
          <<: *common-env
          DJANGO_DEBUG: ${DJANGO_DEBUG}
          EMAIL_HOST: ${EMAIL_HOST}
          # ... other backend-specific vars
    
      huey:
        environment:
          <<: *common-env
          DJANGO_DEBUG: "False"

    Protect the file

    chmod 600 .env

    Use override files to separate dev and production configurations without touching the base file:

    Each environment can point to its own .env file:

    This lets you commit safe dev defaults while keeping production secrets in a separate file.

    2. Per-Environment Compose Overrides

    docker-compose.yml              # base (references ${VARIABLES}, no secrets)
    docker-compose.override.yml     # local dev defaults  (loaded automatically)
    docker-compose.prod.yml         # production overrides (git-ignored)
    # Dev — override is loaded automatically
    docker compose up
    
    # Production
    docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
    docker compose --env-file .env.prod -f docker-compose.yml -f docker-compose.prod.yml up -d

    Structured logging

    CISO Assistant can emit its operational logs as line-delimited JSON so a SIEM (Microsoft Sentinel, Azure Data Explorer, Splunk, Elastic) can ingest them without custom parsing. This page explains how

    Overview

    The three runtime processes each write their operational logs to standard output, where your container runtime or log shipper collects them:

    • Backend (Django API)

    • Worker (the Huey background task process)

    • Frontend (the SvelteKit server-side process)

    By default the output is a human-readable, colourised format meant for reading in a terminal. That format is convenient locally but awkward to parse in a log pipeline. Setting a single environment variable switches every stream to one JSON object per line (newline-delimited JSON), which SIEMs parse natively.

    Set the following on the backend, worker, and frontend containers:

    The backend and the Huey worker share the same logging configuration, so this one variable covers both. Setting it on the frontend container routes the SvelteKit server process — authentication events, request errors — through the same JSON shape.

    The log level also applies to all three streams and defaults to INFO, which captures request-level events. Adjust it if you need more or less detail:

    A backend request log line (formatted here for readability — on the wire it is a single line):

    A frontend authentication event:

    Field
    Description

    Sensitive OAuth2 query parameters (code, token, id_token, access_token) are redacted from logged request URLs.

    In addition to standard output, the backend can mirror its logs to a file. Set LOG_OUTFILE to the destination path; the file is always written in JSON, regardless of LOG_FORMAT. Leave it empty (the default) to log to stdout only.

    This is useful when a log shipper tails a file rather than the container's stdout.

    Once LOG_FORMAT=json is set, point your collector at each container's stdout (or the file above). Because the lines are newline-delimited JSON, Microsoft Sentinel, Azure Data Explorer, Splunk and Elastic all parse them without a custom grok/regex parser — each JSON key becomes a queryable field. Use request_id to correlate all backend lines belonging to a single request, and logger to separate the frontend stream from the backend stream.

    event

    The log message

    request_id

    Correlation id shared by all backend log lines from one request

    user_id

    Authenticated user id, when the request is authenticated

    ip

    Client IP address

    timestamp

    ISO-8601 UTC timestamp

    level

    debug, info, warning, error, critical

    logger

    Source logger (frontend for the SvelteKit process; a Python module path on the backend)

    This page is about the operational log streams (requests, errors, background-task activity, authentication events). It is distinct from the in-app Audit log, which records who changed which object and is read inside the application.

    Enabling JSON logs

    Set LOG_FORMAT=json on all three containers. If only some are switched, your pipeline receives a mix of JSON and plain-text lines and parsing breaks for the plain ones.

    What the records look like

    Common fields

    Optional: also write the backend log to a file

    Shipping to a SIEM

    LOG_FORMAT=json   # default: plain
    LOG_LEVEL=INFO    # default: INFO. Options: DEBUG, INFO, WARNING, ERROR, CRITICAL
    {
      "request": "GET /api/folders/",
      "code": 200,
      "request_id": "0d6f1c4e-2a8b-4e1f-9c3a-7b2e5f0a1d44",
      "user_id": 1,
      "ip": "10.0.2.15",
      "ciso_assistant_url": "https://ciso.example.com",
      "event": "request_finished",
      "timestamp": "2026-06-12T09:21:33.123456Z",
      "level": "info",
      "logger": "django_structlog.middlewares.request"
    }
    {
      "timestamp": "2026-06-12T09:21:34.001Z",
      "level": "warning",
      "logger": "frontend",
      "event": "Login failed",
      "status": 400
    }
    LOG_OUTFILE=/var/log/ciso-assistant/backend.log

    Helm Chart

    Kubernetes installation with the official Helm chart

    The chart lives at oci://ghcr.io/intuitem/helm-charts/ce/ciso-assistant. Source: in the repo.

    • A Kubernetes cluster you have admin access to.

    • helm 3.8+ (OCI registries require 3.8 or newer).

    kubectl configured for the target cluster.

  • An ingress controller if you want to expose the app externally.

  • A persistent storage class (defaults work on most managed clusters).

    1. Pull the default values into a working file:

      helm show values oci://ghcr.io/intuitem/helm-charts/ce/ciso-assistant > custom.yaml
    2. Customise custom.yaml. The most important settings:

      • global.domain — the hostname your instance will serve on.

      • global.tls — set to true if you're serving over HTTPS.

      • ingress.enabled and ingress.tls.* — enable + configure the ingress.

      • backend.config.djangoSecretKey — rotate from the default changeme.

      • backend.config.databaseType — sqlite (default, single-pod), pgsql (bundled PostgreSQL via Bitnami subchart), or externalPgsql.

      • postgresql.* — when using the bundled PostgreSQL.

      • externalPgsql.* — when pointing at your own PostgreSQL instance.

      • backend.config.smtp.* — outgoing email configuration.

      The chart README in the repository carries the full values table (charts/ciso-assistant-next/README.md) — refer to it for every key with its default and description.

    3. Pin the appVersion to a published release if you want predictable upgrades. Set global.image.tag in custom.yaml to the version you tested against (e.g. v3.18.2). Leaving it empty pins to the chart's appVersion, which moves with the chart.

    4. Create a namespace and install:

    The backend pod runs migrations on startup; allow it ~30s before checking the frontend.

    The in-product AI assistant needs two things wired in the chart: the ENABLE_CHAT flag on the backend and a reachable Qdrant vector database for retrieval-augmented generation. Setting qdrant.enabled: true deploys the official Qdrant chart as a dependency (a StatefulSet with persistent storage and health probes) and injects QDRANT_URL automatically.

    Notes:

    • Any key under qdrant: is passed through to the Qdrant subchart (e.g. qdrant.persistence.size, qdrant.resources). Persistence is on by default; see the subchart values for all options.

    • The Qdrant subchart is bundled inside the published chart, so installing needs no access to the Qdrant Helm repo. Air-gapped clusters still pull the Qdrant image at runtime: mirror it and override qdrant.image.repository (same as for the backend/frontend images).

    • To point at an external Qdrant instead of the bundled one, leave qdrant.enabled: false and set QDRANT_URL through backend.env and backend.huey.env.

    • The LLM provider (Ollama or any OpenAI-compatible endpoint, model, base URL) is configured from the in-app Settings → Chat/AI section, not from the chart. LLM inference is heavy; point it at a GPU-backed endpoint.

    • The Qdrant collection and the indexes are not created automatically. After the pods are up, run the indexing commands once from the backend pod (init_qdrant creates the collection, index_objects indexes your existing risk/control/asset records, index_libraries indexes the framework libraries):

    If your pods need to trust an internal CA (for SMTP, SSO, or any outbound TLS service signed by a private authority), provide just your CA in a secret. Trust is added on top of the default roots, not replaced, so public CAs keep working:

    • Backend and Huey (Python): an init container concatenates the system CA bundle with your CA into a shared bundle, and SSL_CERT_FILE / REQUESTS_CA_BUNDLE point at it.

    • Frontend (Node): NODE_EXTRA_CA_CERTS points at your CA, which Node adds to its built-in roots.

    The backend init container writes the merged bundle to an emptyDir. If you also harden the pod to run as a non-root user (global.securityContext.runAsNonRoot / per-component runAsUser), set an fsGroup so that user can write the volume:

    To restrict pod traffic, enable the bundled NetworkPolicy and pass your own ingress/egress rules. The policy selects all pods of the release by default, so your rules must also allow the internal flows the app relies on: the frontend BFF calls the backend (PUBLIC_BACKEND_API_URL) server-side, and the backend reaches Qdrant. Forgetting these blocks the app even though the ingress controller can reach it.

    Replace ciso-assistant-release below with your Helm release name.

    Chart upgrades are normally additive: new capabilities ship as new values keys, and existing keys are not removed or renamed within a major chart version, so your current custom.yaml keeps working as-is. New features are opt-in and off by default — if you don't set their keys, nothing changes in that area.

    When a breaking change to the values shape is unavoidable, it is released under a new major chart version and the required migration steps are documented in the release notes. Read them before upgrading across a major version.

    The main thing to manage on upgrade is the application version. If you did not pin global.image.tag, the images move to the chart's appVersion on the next helm upgrade. Pin the tag to the version you tested and review the release notes for the range you're crossing. Database migrations run automatically on backend startup, so no manual schema step is needed.

    PostgreSQL persistent volumes are not deleted automatically when using the bundled subchart. Inspect with kubectl get pvc -n ciso-assistant and remove manually if you want a clean slate.

    Note: The old Helm repository (intuitem.github.io/ca-helm-chart) is no longer maintained. The values shape changed substantially between the legacy charts/ciso-assistant/ chart and the current charts/ciso-assistant-next/ chart (frontendOrigin → global.domain, no clientName/clusterDomain shorthand, separate ingress block). New installs should use the OCI registry above.

    Prerequisites

    charts/ciso-assistant-next/
    kubectl get pods -n ciso-assistant
    kubectl get ingress -n ciso-assistant
    backend:
      config:
        chat:
          enabled: true        # sets ENABLE_CHAT on the backend and Huey worker
    qdrant:
      enabled: true            # deploys the Qdrant subchart and injects QDRANT_URL
    kubectl create secret generic my-ca -n ciso-assistant --from-file=ca.crt=./internal-ca.crt
    global:
      extraCerts:
        enabled: true
        secretName: my-ca
        fileName: ca.crt
        mountPath: /etc/ssl/extra-certs
    global:
      securityContext:
        fsGroup: 1001
    networkPolicy:
      enabled: true
      policyTypes:
        - Ingress
      ingress:
        # internal traffic between CISO Assistant pods (frontend -> backend, backend -> qdrant)
        - from:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/instance: ciso-assistant-release
        # the ingress controller reaching the frontend and backend
        - from:
            - namespaceSelector:
                matchLabels:
                  kubernetes.io/metadata.name: ingress-nginx
    helm upgrade ciso-assistant-release oci://ghcr.io/intuitem/helm-charts/ce/ciso-assistant \
      -f custom.yaml \
      -n ciso-assistant
    helm uninstall ciso-assistant-release -n ciso-assistant

    Install

    Verify

    AI assistant (chat / RAG)

    Custom CA certificates

    Network policy

    Upgrade

    Uninstall

    Legacy

    kubectl create ns ciso-assistant
    helm install ciso-assistant-release oci://ghcr.io/intuitem/helm-charts/ce/ciso-assistant \
      -f custom.yaml \
      -n ciso-assistant
    POD="deploy/ciso-assistant-release-backend"
    kubectl exec -n ciso-assistant $POD -c backend -- uv run python manage.py init_qdrant
    kubectl exec -n ciso-assistant $POD -c backend -- uv run python manage.py index_objects
    kubectl exec -n ciso-assistant $POD -c backend -- uv run python manage.py index_libraries --sync

    Remote/Virtualization

    Experimenting CISO Assistant through remote server or hypervisor

    New: Use the config builder at the config folder of the repo for an interactive and reliable experience.

    To get started with the config builder, make sure you have python and docker installed. Here is an example on ubuntu:

    #update ubuntu repository and OS
    sudo apt update
    sudo apt upgrade
    
    # install docker
    sudo snap install docker
    
    #install python
    sudo apt install python3-pip python3.14-venv
    
    #clone the repo
    git clone https://github.com/intuitem/ciso-assistant-community.git
    
    #go to the config generator
    cd ciso-assistant-community
    cd config
    
    # setting up the python project and dependencies
    python3 -m venv .venv
    source .venv/bin/activate
    pip install -r requirements.txt
    
    # run the interactive config generator
    python make_config.py

    You cannot use IP addresses on the configuration and you need to have a FQDN mapped to it.

    1. If you aim to expose the VM to internet, use this dedicated guide: https://github.com/intuitem/ciso-assistant-community/tree/main/product-docs/installation/deploy-on-a-vps.md

    2. If you aim to connect from the VM

    3. If you aim to connect to the VM from your network

    This means that you will be using a browser from within the VM so localhost settings are applicable. You can simply use the default ./docker-compose.sh at the root of the repository or trigger the config builder with the following settings:

    run ./docker-compose.sh and connect from within the VM using https://localhost:8443

    • setup a FQDN for your VM and make sure it's known by the host you are connecting from. This will vary depending on your OS. For instance, for linux/mac, you can add a line to your /etc/hosts file such as:

    192.168.1.87 ca.homelab.local

    in this example, the first part is your VM's ip and the second one will be the FQDN you'll be providing to the config builder and that you will use to connect later on.

    Run the config builder and provide the following settings:

    run ./docker-compose.sh and connect from your host this time using https://ca.homelab.local:8443

    Notes:

    • If you don't want to have a specific port, use the port 443 during the settings, given it's not used by another application on your system.

    • In the remote setup, if you also want to connect from within the VM, you can add your custom FQDN to the /etc/hosts of your VM but mapped to 127.0.0.1

    ---

    Let's say that you want to setup or experiment with CISO Assistant on a Network or Virtualized environment (eg. Hypervisor) on a remote host, for instance, to use with multiple users:

    • Install a recent version of Docker on your remote server

    • Given that we are using TLS with Caddy, we need to have DNS entries and not IPs

    • The workstations need to be able to reach the remote using an FQDN (DNS entry). If not you can add an entry on your /etc/hosts. Keep track of the remote server DNS as you'll put it on the next step, let's say the remote is cool-vm for instance

    • Five lines need to be edited. Save the file and move to the next step

    If you're getting SSL_ERROR_INTERNAL ERROR_ALERT (Can be different on other browsers) blocking you from continuing, make sure that you've made the 5 changes above.

    The tls internal (equivalent to -i in CLI mode) parameter of Caddy can present some security issues and is not recommended for production and internet exposure. You should consider proper certificates for that.

    You're all set, and you can simply run:

    Your CISO Assistant can be reached now from https://cool-vm:8443, and you can skip the SSL warning for the self-signed certificate.

    Clone the repo, but don't run anything yet. Edit the docker-compose.yml file as follows: (red is for deletion and green for addition); your diff should look like:

    ./docker-compose.sh

    From the VM

    From your network / host OS

    Legacy - Kept for reference purposes

    Prometheus metrics

    CISO Assistant exposes a /metrics endpoint in the Prometheus exposition format. This page explains how to enable it and how to access it safely from Prometheus without exposing it publicly.

    Overview

    When enabled, the backend exposes a /metrics endpoint that returns instance-level gauges in the Prometheus exposition format:

    • User and editor counts

    • Number of loaded libraries, domains, perimeters, assets, threats

    • Number of compliance assessments, risk assessments, risk scenarios, risk acceptances

    • Number of applied controls and evidences

    • License expiration date, instance creation date, last login date

    • Build information (version, commit, schema)

    Set the following environment variable on the backend container:

    The endpoint is disabled by default (EXPOSE_METRICS=False).

    If your prometheus runs in local you can for example check the /metrics endpoint with this config

    If you have multiple instances on different machines, add them to targets:

    Start Prometheus with:

    The Prometheus UI is available at http://localhost:9090. Search for ciso_assistant_nb_users to confirm that scraping is working.

    From a machine that has access to the backend (not from the public internet):

    You should see output similar to:

    If the endpoint returns a 404, check that EXPOSE_METRICS=True is set and that the backend has restarted.

    Enabling the endpoint

    Security — never expose /metrics publicly

    The /metrics endpoint is unauthenticated. If you enable it, make sure it is never reachable from the public internet — either by restricting access to trusted IP ranges, or by binding the endpoint to an internal interface only.

    Prometheus configuration (single VM)

    Verifying the endpoint

    EXPOSE_METRICS=True
    global:
      scrape_interval: 30s
    
    scrape_configs:
      - job_name: ciso-assistant
        static_configs:
          - targets:
              - localhost:8000  
        metrics_path: /metrics/
        static_configs:
          - targets:
              - 192.168.1.10:8000
              - 192.168.1.11:8000
    prometheus --config.file=prometheus.yml
    curl http://localhost:8000/metrics
    # HELP ciso_assistant_nb_users Number of users in the CISO Assistant instance
    # TYPE ciso_assistant_nb_users gauge
    ciso_assistant_nb_users 3.0
    ...

    Updating your local instance

    How to update your local instance. All docker images are available on ghcr with the specific versions matching the repo tags. The latest tag points to the most recent release for both back and front.

    Hands-free

    The easiest way to update your on-prem/local instance (pro or community)

    Run the script update-ciso-assistant:

    ./update-ciso-assistant.sh

    Detailled steps

    In case of issues (unsupported shell, windows, etc.) here are the steps to consider:

    1. backup your db:

      1. if you're using sqlite, copy the file under a different name

      2. if it's postgresql you can use something like pg_dump

    2. stop and clean the containers, this won't affect your data

    docker compose rm -fs

    1. restart the compose and let it handle the migration

    docker compose up -d

    Force remove the previous docker images to get the new ones

    Edge cases

    docker rmi ghcr.io/intuitem/ciso-assistant-community/backend:latest ghcr.io/intuitem/ciso-assistant-community/frontend:latest 2> /dev/null

    Maintenance

    Special cases

    Tips and tricks regarding specific cases

    SELINUX

    If you have selinux enabled on your distro, you might want to check if it's not preventing the mount volume of the docker compose; you can try something like this:

    Recompute assessment results after the semantic compute_result upgrade

    Audits produced before the semantic compute_result aggregation may have stored results that were collapsed under the older boolean logic (any non-empty compute_result was treated as truthy, so a "Non-compliant" choice could still aggregate to Compliant). This applies to audits backed by questionnaires from either path: the library builder or Excel-imported frameworks.

    The recompute_assessment_results Django management command realigns stored results with the current rule.

    Properties:

    • Scoped to compute_result-driven requirements only. The command targets requirement assessments whose requirement carries at least one question choice with a resolvable compute_result. Score-only or manual-entry audits are left alone, so a manually-set result is never silently reset to not_assessed.

    • Idempotent. Running twice is a no-op the second time; rows already aligned are reported as unchanged.

    • Per-batch commits by default. Lock duration stays bounded on large tenants. Use --atomic for all-or-nothing semantics on small datasets.

    • Touches score, result, is_scored, updated_at on the requirement assessments it rewrites. Other fields are left as-is.

    • Re-triggers CA-level hooks after writes: ComplianceAssessment.upsert_daily_metrics() and CEL outcome evaluation are explicitly called once per touched audit, because bulk_update bypasses the RequirementAssessment.save() signal chain. If any hook fails, the command exits with a CommandError listing the failures, so you don't silently end up with up-to-date results but stale metrics or CEL outcomes. Pass --skip-post-hooks to opt out when you handle those hooks separately.

    If you run the application via Docker Compose, prefix with docker compose exec backend (or the equivalent for your deployment).

    chcon -Rt svirt_sandbox_file_t ./db
    # Preview impact, no writes
    uv run python manage.py recompute_assessment_results --dry-run
    
    # Apply to all audits, one transaction per batch (default)
    uv run python manage.py recompute_assessment_results
    
    # Scope to a single audit
    uv run python manage.py recompute_assessment_results \
        --compliance-assessment <uuid>
    
    # Tune batch size or wrap the full run in one transaction
    uv run python manage.py recompute_assessment_results --batch-size 1000 --atomic
    
    # Skip the post-run CA hooks (metrics + CEL outcomes), e.g. when chaining
    # with another job that will recompute them
    uv run python manage.py recompute_assessment_results --skip-post-hooks

    Frequent questions

    Stop and restart

    docker compose down

    docker compose up -d

    Getting the logs

    All services logs combined:

    docker compose logs

    Specific service:

    docker compose logs backend

    Didn't get the prompt for the first user

    If you didn't get the prompt to create the first user, or lost the password but you still have access to the infra level, you can trigger the createsuperuser command to fix that.

    In your compose file folder, try:

    docker compose exec backend uv run python manage.py createsuperuser

    Alternatively, in a docker environment:

    docker ps -a | grep backend (this will get you the id of the Backend for CISO Assistant container, keep it for the next step)

    docker exec -it <the_container_id> uv run python manage.py createsuperuser

    and you should get a prompt now 😉

    docker compose exec backend uv run python manage.py changepassword <user_email>

    You'll get a prompt to change the password

    In some rare cases, the migration of database schemas can take longer than expected or fail silently. First thing to check is the backend container logs:

    Make sure you share these information if you're reporting an issue on Discord or the Support portal.

    If you want to trigger the migration to make sure that all increments have been properly applied:

    most likely because the initialization took longer than expected. Make sure you provide the expected specs or tune the docker compose to give the app more time to finish the init phase.

    The recommended pattern for a first local setup is to go with ./docker-compose.sh ; In case you can't:

    Run

    wait for the init to finish and then trigger the first user creation manually:

    By default, the BODY_SIZE_LIMIT environment variable is set to 50 MB in the frontend Dockerfile:

    In order to upload larger files, this value must be increased. How to do so depends on you rmode of deployment. Here are relevant docs:

    Lost the first user password

    Random issues after upgrading

    Healthcheck fails during the installation

    Don't want / Can't run the init script

    "Payload too large" when uploading a file to the frontend

    If you use helm, this value is overwritten by the bodySizeLimit variable. Note the camel case here.

    https://docs.docker.com/compose/how-tos/environment-variables/set-environment-variables/
    https://helm.sh/docs/helm/helm_env/
    https://docs.docker.com/reference/cli/docker/container/run/#env
    docker compose logs backend
    docker compose exec backend uv run python manage.py migrate
    docker compose up -d
    docker compose exec backend uv run python manage.py createsuperuser
    # frontend/Dockerfile
    
    ENV BODY_SIZE_LIMIT=50000000

    Setting up mailer

    CISO Assistant uses SMTP to send transactional emails (password reset, superuser creation, notifications). This page covers configuration and the TLS specifics introduced in 3.16.

    Environment variables

    EMAIL_HOST=smtp.example.com
    EMAIL_PORT=465
    EMAIL_HOST_USER=noreply@example.com
    EMAIL_HOST_PASSWORD=<secret>
    DEFAULT_FROM_EMAIL=noreply@example.com
    
    # Pick ONE of the two (not both):
    EMAIL_USE_SSL=True    # SMTPS (typically port 465)
    EMAIL_USE_TLS=False
    
    # or
    EMAIL_USE_SSL=False
    EMAIL_USE_TLS=True    # STARTTLS (typically port 587)

    For local development you can run MailHog and point EMAIL_HOST at it with both flags set to False.

    TLS certificate requirements (3.16+)

    Since 3.16, the backend image runs rootless and read-only, and ships with a recent Python/OpenSSL stack that enables strict X.509 verification (VERIFY_X509_STRICT + VERIFY_X509_PARTIAL_CHAIN).

    This has two consequences:

    1. The old recipe of running update-ca-certificates from command: in docker-compose.yaml no longer works — it requires root and write access to /etc/ssl/certs/, both denied by the new container. See the deprecated section below if you are still on an older image.

    2. Every certificate in the chain presented by your SMTP server must satisfy the strict checks. A single non-compliant intermediate will fail the whole verification.

    Your SMTP server certificate and every certificate in its chain must include:

    • BasicConstraints — CA:FALSE on the leaf, CA:TRUE on intermediates and root

    • KeyUsage — at minimum digitalSignature, keyEncipherment on the leaf

    If you get an error like:

    regenerate the offending certificate with the missing extension. Inspect a cert with:

    You cannot modify the system trust store at runtime anymore. Instead, mount a PEM file containing the CA(s) to trust and point OpenSSL at it via SSL_CERT_FILE:

    How it works:

    • Django's mailer goes through smtplib, which builds its TLS context with ssl.create_default_context().

    • That function asks OpenSSL to load its default trust store.

    • When SSL_CERT_FILE is set, OpenSSL uses

    Requirements for the bundle file:

    • A single PEM file, concatenating your root CA and any intermediates needed to validate the SMTP server's chain.

    • Each cert in the bundle must itself satisfy the strict X.509 checks listed above (BasicConstraints, KeyUsage, AKI).

    From the backend container:

    A clean (250, b'2.0.0 OK') means TLS and trust are correctly configured. Any SSL: CERTIFICATE_VERIFY_FAILED will name the missing extension or the failing cert.

    You can also trigger a password reset from the UI and watch the backend logs — failures are logged at iam.models with email_host, email_port, and the underlying SSL error.

    Older versions ran the container as root with a writable filesystem, which allowed mounting a CA at runtime and refreshing the trust store from command::

    When upgrading to 3.16+, remove the command: override and switch to the CA bundle method above.

    Authority Key Identifier (AKI) — on every cert in the chain, not only the leaf
  • a complete fullchain (leaf + intermediates), served in order by the SMTP server

  • that file instead
    of the system bundle (
    /etc/ssl/certs/ca-certificates.crt
    ).

    Trusting a private / self-signed CA

    REQUESTS_CA_BUNDLE is only honored by the requests/urllib3 libraries (used by outbound HTTP calls such as OIDC/SAML metadata fetch). It has no effect on SMTP, so you don't need to set it for the mailer.

    Verifying the setup

    Deprecated: rescue mailer

    The EMAIL_*_RESCUE variables (a secondary mailer used as fallback) are deprecated and will be removed in a future release. They are not a workaround for TLS issues — fix the certificate instead.

    Deprecated: update-ca-certificates recipe (pre-3.16)

    This section is kept for users still on backend images older than 3.16. Do not use it on 3.16+ — the recipe silently fails on the rootless/read-only container. Use the CA bundle method instead.

    [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed:
    Missing Authority Key Identifier (_ssl.c:1081)
    openssl x509 -in cert.pem -noout -text | grep -A1 "Authority Key Identifier\|Basic Constraints\|Key Usage"
    services:
      backend:
        image: ghcr.io/intuitem/ciso-assistant-community/backend:3.16.1
        environment:
          - EMAIL_HOST=smtp.example.com
          - EMAIL_PORT=465
          - EMAIL_USE_SSL=True
          - EMAIL_USE_TLS=False
          - SSL_CERT_FILE=/certs/ca-bundle.pem
        volumes:
          - ./ca-bundle.pem:/certs/ca-bundle.pem:ro
    python -c "import smtplib, ssl; \
    ctx = ssl.create_default_context(); \
    s = smtplib.SMTP_SSL('smtp.example.com', 465, context=ctx); \
    print(s.noop()); s.quit()"
    services:
      backend:
        image: ghcr.io/intuitem/ciso-assistant-community/backend:<old-tag>
        environment:
          - EMAIL_HOST=smtp.example.com
          - EMAIL_PORT=465
          - EMAIL_USE_SSL=True
          - SSL_CERT_FILE=/etc/ssl/certs/smtp.example.com.pem
        volumes:
          - ./smtp-fullchain.crt:/etc/ssl/certs/smtp.example.com.pem:ro
        command: |
          sh -c 'update-ca-certificates && <original entrypoint>'

    Settings

    The Settings page in CISO Assistant is where instance-wide configuration lives — the dials and switches that affect everyone using the platform, regardless of which domain or perimeter they're in.

    Settings are grouped into the following categories:

    • General settings — display preferences, default language, currency and daily rate, AI/LLM provider configuration, retention defaults, and a handful of behavioural toggles (self-validation, MFA enforcement, external-link warnings).

    • Feature flags — toggles that turn whole product areas on or off. Use these to tailor the UI to what your team actually needs and to keep advanced or experimental capabilities out of sight until you want them.

    • — the remediation deadlines (in days) that apply to vulnerabilities by severity, and the anchor date used to compute the clock.

    • — switches for the optional external feeds (KEV, EPSS, NVD enrichment) and the network timeout the platform uses when reaching them.

    • (PRO) — replace the default logo, favicon, and client name with your organisation's identity.

    • (PRO) — override the subject and body of system emails, and the .docx templates used for document exports.

    Editing settings requires the change_globalsettings permission. In practice, this means a Domain Manager on the global domain or an equivalent custom role.

    Settings on this page are global — they apply to the whole instance. Domain-level overrides aren't available at this layer; if you need per-domain behaviour, look at the relevant domain or perimeter's own settings.

    Permissions

    Scope

    Vulnerability SLA policy
    Security intelligence feeds
    Branding
    Custom templates

    Overview

    This section is being expanded.

    Material to come: organisation setup (users, groups, custom roles, teams), the IAM model, single sign-on (SAML, OIDC) with per-provider guides (Entra ID, Okta, Google Workspace, Keycloak), bringing content in through and the , and changing the interface language.

    libraries
    data import wizard

    Migrate between different databases

    You think it is time to change or try a new database on CISO Assistant? You were using SQLite and now want to switch to PostgreSQL, or the other way around? This guide is for you.

    Primordial step: create backups

    Do not forget that this kind of operation can be tricky and may impact your data if something goes wrong.

    To stay safe, we strongly recommend creating a backup of the volume, disk, or db/ folder used to host your CISO Assistant instance.

    We also recommend testing your backup procedure by deploying another CISO Assistant instance and restoring the backup into it. This will help verify that your backups work correctly before you start switching database engines.

    Switch from SQLite to PostgreSQL

    Here is a complete guide of all the steps you should perform (after backing up your volume).

    The new PostgreSQL-backed instance must run the exact same CISO Assistant version as the source SQLite instance. The restore will refuse a backup produced by a different version. Migrate first, then upgrade afterwards if needed.

    1. Export your data

    To facilitate the backup and restore workflow, we designed a backup-restore page with a button to back up the database.

    Go in Extra > Backup & restore, then click on Export database. You will get a .bak file.

    You can install whichever PostgreSQL setup you prefer, as you only need the environment variables afterwards to connect it to CISO Assistant. Here are the two main ways:

    Depending on your OS, install PostgreSQL — here on Ubuntu:

    Configure your PostgreSQL instance with at minimum:

    Also check the port on which PostgreSQL is running (normally 5432).

    In your docker-compose.yml, add a service like this:

    Define these environment variables in your docker-compose.yml (or via export if running without containers):

    If PostgreSQL is running on your host (not in a container), set DB_HOST=host.docker.internal and add the following to your backend service:

    Bring the stack back up — if you are using Docker, migrations run automatically at startup:

    Since the PostgreSQL database is brand new and empty, you also need to create a temporary superuser:

    Connect with your new temporary superuser, go to the Backup & restore section, and click the restore button. Select the .bak file you downloaded in step 1.

    Your database will be fully restored. Reconnect with one of your original users.

    The .bak only contains database rows. The actual evidence files (PDFs, images, …) live on the filesystem under db/attachments/, independent of which database engine you use. Database rows reference them by path, so if the files aren't where the rows expect them, evidence records will appear to exist but their attachments will be broken.

    You have two ways to keep them:

    Option A — Same host, same volume (typical case). If you're switching the database engine in place on the same machine and you kept the db/ volume mounted on the new stack, you don't need to do anything: db/attachments/ is already there and the restored records will resolve to the existing files.

    Option B — Cross-host migration, or you want one atomic snapshot. Use the clica CLI shipped under instead of the UI export. It packages the database and every attachment in a single backup, then restores both in one atomic call:

    Requires a Personal Access Token with the backup permission set in .clica.env. The CLI verifies SHA-256 hashes and is resumable. See cli/README.md for setup details.

    The logic is the same in reverse:

    1. Export the database from the Extra > Backup & restore page on your PostgreSQL-backed instance (or run clica backup-full if you want attachments included).

    2. Stop the stack (docker compose down).

    3. Remove the PostgreSQL environment variables (POSTGRES_NAME

    The same version-match rule applies: the SQLite-backed instance must run the exact same CISO Assistant version as the PostgreSQL-backed source.

    ,
    POSTGRES_USER
    ,
    POSTGRES_PASSWORD
    ,
    DB_HOST
    ,
    DB_PORT
    ) and the
    db
    service from your
    docker-compose.yml
    . With
    POSTGRES_NAME
    unset, CISO Assistant falls back to SQLite at
    db/ciso-assistant.sqlite3
    .
  • Bring the stack back up, create a temporary superuser, and restore the .bak file (or run clica restore-full).

  • Keep db/attachments/ in place — the same caveat from step 7 above applies.

  • Evidence files and other uploaded files are not included in this export — they live on disk under db/attachments/ and are handled separately in step 7. If you'd rather get both the database and the attachments in a single bundle, skip this step and use the clica CLI instead — see step 7, Option B.

    2. Stop the instance of CISO Assistant

    3. Set up PostgreSQL

    On your host using a service

    In a Docker container

    4. Connect CISO Assistant to PostgreSQL

    The exact host settings depend on your setup — OS, Docker version, whether you run rootless Docker, or whether you bridge the backend container to the host network. Adjust DB_HOST and extra_hosts accordingly.

    5. Restart, migrate and create a superuser

    This is a temporary user. The backup restore will delete it while giving you back your original users.

    6. Restore your data

    7. Make sure evidence files are still reachable

    Switch from PostgreSQL to SQLite

    cli/
    docker compose down
    sudo apt install postgresql
    POSTGRES_DB=ciso-assistant
    POSTGRES_USER=ciso-assistantuser
    POSTGRES_PASSWORD=<choose a password>
    db:
      container_name: db
      image: postgres:16
      restart: always
      environment:
        - POSTGRES_DB=ciso-assistant
        - POSTGRES_USER=ciso-assistantuser
        - POSTGRES_PASSWORD=<your pg password>
      volumes:
        - ./pgdata:/var/lib/postgresql/data
      healthcheck:
        test: ["CMD-SHELL", "pg_isready -U ciso-assistantuser -d ciso-assistant"]
        interval: 10s
        timeout: 5s
        retries: 10
        start_period: 50s
    POSTGRES_NAME=ciso-assistant
    POSTGRES_USER=ciso-assistantuser
    POSTGRES_PASSWORD=<your pg password>
    DB_HOST=db
    DB_PORT=5432
    extra_hosts:
      - "host.docker.internal:host-gateway"
    docker compose up -d
    docker exec -it backend uv run python manage.py createsuperuser
    # On the source instance — produces backup.json.gz + attachments/ + manifest
    uv run clica.py backup-full --dest-dir ./db_backup
    
    # On the new (PostgreSQL-backed) instance, after step 5
    uv run clica.py restore-full --src-dir ./db_backup

    Feature flags

    Feature flags turn whole product areas on or off. They're how you tailor the navigation and the surface area to what your team actually uses, and how you keep experimental or specialised features out of sight until you want them.

    Flags affect what's visible in the sidebar, what appears in CRUD pages, and which permissions are even relevant. They do not delete any underlying data — turning a flag off hides the feature; turning it back on restores the UI as it was.

    Operations

    • xrays — the X-rays inconsistency-detection page.

    • incidents — incident management.

    • tasks — the task-management module (one-off and recurring tasks).

    • control_plan — the consolidated control-plan view across applied controls.

    • risk_acceptances — the risk-acceptance workflow.

    • exceptions — security-exception tracking.

    • follow_up — findings assessments (follow-up).

    • ebiosrm — the EBIOS RM module.

    • scoring_assistant — the OWASP-based scoring assistant.

    • vulnerabilities — vulnerability tracking.

    • compliance — compliance assessments (audits). Effectively master switch for the entire compliance pillar.

    • auditee_mode — the read-only auditee surface for external assessors. Default off.

    • campaigns — bulk-orchestration of audits across many perimeters. PRO.

    • bia — business impact analyses.

    • tprm — third-party risk management.

    • contracts — contracts surface inside TPRM. Default off.

    • privacy — the privacy register pillar (master switch).

    • security_advisories — the security advisories catalogue.

    • cwes — the CWE catalogue.

    • metrology — metric definitions, instances, and dashboards.

    • reports — the reports surface. Default off.

    • advanced_analytics — Per-audit dashboard (compliance by section, controls coverage, timeline, evidence coverage, threats, exceptions). Default off.

    • outgoing_webhooks — outgoing webhooks. Default off.

    • audit_log_forwarding — to an external SIEM over HTTP or Kafka. PRO. Default off.

    • idp_groups — : the IdP groups menu, the SCIM settings tab, and the IdP groups column on the users table. PRO.

    • project_management — projects, accreditations, responsibility matrices. Default off.

    • journeys — preset journeys for bootstrapping new organisations or domains.

    • comments — comments on objects.

    • object_audit_trail — per-object button on detail pages, gated by the Can view object audit trails permission. PRO.

    • experimental — feature-gate for the experimental area. Use with caution.

    Defaults marked Default off are off in fresh installs. Everything else defaults to on. Restart isn't required when a flag is toggled, but a hard refresh in the browser is.

    validation_flows — configurable approval workflows that mirror internal review or management-approval processes, attached to objects whose state changes warrant sign-off. Default off.
  • organisation_issues — context register: issues affecting the organisation.

  • organisation_objectives — context register: organisational objectives.

  • policy_documents — the dedicated Policies surface (a filtered view of applied controls).

  • document_management — the standalone module: the reading catalogue, document list, and templates. Author or upload documents through a draft → published lifecycle, independent of policies.

  • quantitative_risk_studies — Monte-Carlo quantitative risk.
  • inherent_risk — surface inherent-risk columns alongside residual risk on assessments. Default off.

  • audit_tree_inheritance — combine an audit's results with parent-domain audits on the same framework. Reveals the Domain inheritance strategy and the Combined view on the . Default off.

  • posture_assessments — : continuous measurement of assets against technical baselines (CIS Benchmarks, hardening guides) with recurring scan results. Default off.

  • personal_data — personal-data inventory inside the privacy register.
  • purposes — purposes register.

  • right_requests — data-subject right requests.

  • data_breaches — data-breach tracking.

  • service_accounts — for machine-to-machine API access via OAuth2 client credentials. PRO.

  • chat_mode — the in-product chat assistant. Default off; only visible when ENABLE_CHAT is set on the instance.

  • terminologies — organisation-specific label overrides.

  • custom_fields — org-defined typed fields on objects (Projects, Assets, Applied controls); see . PRO. Default off.

  • focus_mode — UI mode that filters the entire workspace to a single domain. PRO. Default off.

    Governance

    Risk

    Compliance

    Resilience

    Third-party and privacy

    Catalog

    Metrology and reporting

    Integrations and automation

    Project management

    Workflow

    Experimental

    Advanced Analytics
    forward the audit log
    SCIM 2.0 provisioning and IdP group mapping
    audit trail
    Documents
    general setting
    Framework report
    technical postures
    service accounts
    Custom fields

    General settings

    Instance-wide settings that don't belong to a more specific category. Grouped here by intent — the order in the UI may differ.

    Display and interface

    • Security objective scale — the labels used for ratings of security objectives (e.g. C/I/A).

    • EBIOS radar configuration — the max radius and the green / yellow / red zone radii used to draw the EBIOS RM radar chart.

    • Aggregated scenario matrix — toggles the aggregated view of scenarios on the risk-matrix display.

    • Risk matrix axis options — swap axes, flip vertical, custom axis labels. Cosmetic adjustments to how every risk matrix is rendered.

    • Display qualifications as risk categories — swaps the term qualification for risk category throughout the interface: field labels on risk scenarios, incidents, feared events, escalation thresholds and quantitative risk scenarios, plus the matching filters and analytics charts. The values themselves (confidentiality, integrity, …) are managed as either way.

    • Default language — fallback locale for users who haven't picked a preference and for system-generated emails. Must be one of the languages enabled in the instance build.

    • Currency — the unit used when displaying applied-control costs and quantitative-risk amounts.

    • Daily rate — default daily cost used when expressing effort in monetary terms.

    • Conversion rate — write-only field used when changing the currency to convert existing cost amounts in one operation.

    When you change the currency with a conversion rate, the platform sweeps every applied control's cost structure and applies the conversion. Without a conversion rate it just relabels — the numbers stay the same.

    • Allow self-validation — whether a user can validate workflows they themselves created. Off by default for separation-of-duty reasons.

    • Show warning on external links — interstitial prompt before opening links that leave the platform.

    • Enforce MFA — make multi-factor authentication mandatory for every user account.

    • Built-in metrics retention (days) — how long built-in metric samples are kept before being aged out. Minimum 1.

    • Enable email notifications — master switch for outbound email notifications. See also .

    These settings drive the optional AI features (chat mode, agentic workflows, RAG over the knowledge base):

    • LLM provider — which model server the platform calls: Ollama, or OpenAI-compatible (LM Studio, vLLM, llama.cpp...) for any server speaking the OpenAI chat completions API, hosted or local.

    • Ollama base URL, Ollama model, Ollama embedding model — used when the provider is Ollama.

    To connect a hosted service such as OVHcloud AI Endpoints or OpenRouter, see .

    • Default custom analytics dashboard — UUID of the dashboard shown by default on the analytics page.

    Shown only when the Domain-tree audit inheritance feature flag is on (under the Compliance assessments group).

    • Domain inheritance strategy — when the same framework is audited at several levels of the domain tree, decides how a child audit combines results with its parent audits. Options: No inheritance (default), Parent always wins, Child always wins, Best case (optimistic), Worst case (prudent). Scores from a different scale are normalised to the top parent's scale. This one org-wide setting drives the Combined view on the and the inheritance panel in . Leaving it on No inheritance keeps the feature dormant even with the flag enabled.

    Allow assignments to entities — whether requirements and tasks can be assigned to third-party entities (not just internal users).

  • Mapping max depth — how many frameworks a chained mapping path may span when projecting one framework onto another, counted as nodes in the path (2–5, default 3). A value of 3 allows one pivot — A → B → C. See .

  • API base URL, Model name, API key — used when the provider is OpenAI-compatible. The key is write-only and never returned by GET.
  • Embedding backend — which backend powers semantic search over knowledge. Local sentence transformers or Ollama; hosted providers are not offered here, so selecting one for the LLM leaves embeddings where they are.

  • System prompt — system prompt prepended to chat-mode conversations.

  • Send temperature to the model and Temperature — whether to pass a sampling temperature, and its value. Some servers reject the parameter, which is why it can be switched off.

  • Language

    Money

    Behaviour

    Retention

    Notifications

    AI / LLM provider

    Local or self-hosted LLMs. The Ollama URL and OpenAI API base URL are checked when you save them and must resolve to a public address — private, loopback, and internal IPs are rejected to prevent server-side request forgery (SSRF). To point at a local or in-network model (for example Ollama on localhost, LM Studio, or an in-cluster endpoint), start the backend with the environment variable ALLOW_PRIVATE_NETWORK_REQUESTS=True. (This variable was previously named WEBHOOK_ALLOW_PRIVATE_IPS; the old name is no longer recognized.)

    Analytics

    Domain-tree audit inheritance

    terminology
    Setting up mailer
    Hosted AI providers
    Framework report
    Advanced Analytics
    transitive inference

    Security intelligence feeds

    CISO Assistant can optionally enrich its vulnerability and security-advisory catalogues by polling external threat-intelligence feeds. These switches control which feeds are active and how the platform reaches them.

    All feeds are off by default — they make outbound network calls, so opt in deliberately.

    Available feeds

    • KEV feed (kev_feed_enabled) — CISA's Known Exploited Vulnerabilities list. Tags vulnerabilities that are confirmed to be exploited in the wild so they can be prioritised.

    • EPSS feed (epss_feed_enabled) — FIRST's . Attaches a probabilistic exploitation score to each CVE, useful for prioritisation alongside CVSS severity.

    • NVD enrichment (nvd_enrich_enabled) — pulls extra metadata from the (CWE mappings, affected configurations, references).

    • Network timeout (network_timeout) — seconds to wait before giving up on a feed call. Default 30, range 5-120. Tune up if you're behind a slow egress proxy; tune down if you want feed failures to surface quickly rather than block other work.

    • Enabling a feed doesn't backfill the entire history — feeds are consulted from the moment they're enabled. To enrich historical entries, look for a "refresh" action on the relevant catalog (depends on the feed).

    • Feed calls happen in background jobs (Huey workers), so toggling a feed doesn't block the request that saves the settings.

    • Outbound HTTPS access to the feed endpoints is required. The platform doesn't ship with mirrored data.

    Network

    Operational notes

    Exploit Prediction Scoring System
    NIST National Vulnerability Database

    Vulnerability SLA policy

    The Vulnerability SLA policy defines, by severity, how many days a vulnerability is allowed to remain open before it breaches the organisation's service-level agreement.

    The platform uses this policy to compute remediation deadlines, surface overdue vulnerabilities, and feed SLA dashboards.

    Anchor

    • SLA anchor — the date used as day 0 when computing the deadline. Two options:

      • detected_at — the date the vulnerability was first recorded in CISO Assistant (default).

      • published_date — the date the vulnerability was publicly disclosed (relevant when working from CVE feeds).

    The choice matters: published_date tightens deadlines for vulnerabilities that were known publicly before you imported them; detected_at gives a fresh clock starting from import.

    For each severity level, set the number of days allowed to remediate. Leave a field empty (null) to mean no policy at this severity.

    • Critical — typically the tightest (e.g. 7-14 days).

    • High — typically 30 days.

    • Medium — typically 60-90 days.

    • Vulnerabilities whose anchor_date + deadline_days is in the past are flagged as SLA breached.

    • Severity is read from the vulnerability record itself; the policy is a lookup, not a per-vulnerability field.

    • Changes to the policy apply going forward and retroactively recompute the breach status of existing vulnerabilities.

    Low — typically 180+ days, or unset.
  • Info — usually unset; informational entries aren't on a clock.

  • Deadlines by severity

    Behaviour

    Allowed IP whitelist

    Control which IP addresses and CIDR ranges are allowed to reach the CISO Assistant backend. Administrators manage the allowlist from the settings UI, and the infrastructure layer picks it up automatic

    What it does

    The Allowed IPs whitelist lets administrators decide which IP addresses and CIDR ranges are permitted to reach the backend API. It is the simplest way to restrict API access — for example, to let a CI runner, an office network, or a machine running the MCP server talk to your instance while keeping everyone else out.

    You manage the list from Settings → Infrastructure:

    Settings → Infrastructure → Allowed IPs
    • Type an IP address (e.g. 203.0.113.4) or a CIDR range (e.g. 198.51.100.0/24) and click Add.

    • Remove an entry with the ✕ next to it.

    • Click Save to apply your changes.

    Both IPv4 and IPv6 are supported, up to 50 entries.

    • CISO Assistant SaaS — already enabled. The Infrastructure tab is available to administrators out of the box; just manage your allowed IPs.

    • On-premises — disabled by default. If you want this self-service allowlist, enable it by setting the following environment variable on the backend and restarting it:

      When disabled, the Infrastructure tab is hidden and the API endpoint below is not registered.

    Once configured, the allowlist is published on an /infra-config/ endpoint so your reverse proxy, firewall, or security group can read it and apply the rules automatically — instead of you editing infrastructure config by hand.

    From a machine that can reach the backend (not from the public internet):

    If the endpoint returns a 404, make sure ENABLE_INFRA_CONFIG_MANAGEMENT=True is set and that the backend has been restarted.

    Branding

    Available on the PRO plan.

    Branding

    Branding settings let you replace the default CISO Assistant visuals with your organisation's identity — useful when the platform is deployed for end-customers, when a parent company hosts multiple subsidiaries, or simply to align the UI with internal design guidelines.

    Settings

    • Client name — the display name used in headings and email signatures.

    • Logo — replaces the default product logo in the header. Accepted formats: .png, .jpeg, .jpg, .webp, .svg.

    • Favicon — replaces the browser-tab icon. Accepted formats: .ico, .png, .jpeg, .jpg, .webp, .svg.

    • Show images to unauthenticated users — when on (default), the logo and favicon are visible on the login screen and other pre-authentication pages. Turn off to keep branding gated behind authentication.

    • Logo and favicon are stored as files inside the instance, not as external URLs. Upload them through the Settings UI rather than editing the database directly.

    • The platform serves a content-hash header alongside each image so browser caches stay coherent when the file is replaced.

    Operational notes

    ENABLE_INFRA_CONFIG_MANAGEMENT=True
    curl http://localhost:8000/infra-config/
    {
      "allowed_ips": ["203.0.113.4", "198.51.100.0/24"]
    }

    The list is a strict allowlist:

    • Empty list → no access. Saving with no entries blocks all traffic to the backend. The UI asks you to confirm before you do this.

    • 0.0.0.0/0 or ::/0 → any IP. These wildcard ranges open access to everyone, which defeats the purpose of the allowlist.

    Make sure your own IP (and anything that needs API access) is in the list before you save.

    On SaaS, changes take ~10 minutes to apply. After you save, allow up to 10 minutes for the new rules to take effect — a background job reconciles the allowlist with the infrastructure on a 10-minute cycle. There's nothing to configure; just wait before testing. On-premises, propagation depends on how you wire enforcement (see Availability below).

    Availability

    On-premises, you have to wire up enforcement yourself. Enabling the flag only exposes the allowlist on /infra-config/ — it does not filter traffic on its own (the automatic 10-minute reconciliation mentioned above is specific to CISO Assistant SaaS). You are responsible for consuming the endpoint and applying the rules in your own infrastructure.

    In particular, /infra-config/ is served at the URL root, not under /api/. The default Caddy configuration only reverse-proxies /api/* to the backend and everything else to the frontend, so the endpoint is not reachable through Caddy until you add a route for it. Edit your Caddy configuration to proxy it directly to the backend — for example:

    Keep /infra-config/ restricted to your trusted infrastructure (it is unauthenticated — see the warning below).

    If you rely on API access — for instance the MCP integration — IP filtering must be in place and your IPs added to the allowlist. SaaS administrators only need to add their IPs; on-premises administrators should enable the feature first.

    How the infrastructure layer consumes it

    The /infra-config/ endpoint is unauthenticated, exactly like /metrics. Never expose it to the public internet — keep it reachable only from your infrastructure layer (restrict it to trusted networks or bind it to an internal interface).

    The Infrastructure settings tab showing the Allowed IPs list with add, remove and save controls
    reverse_proxy /infra-config/* backend:8000
    reverse_proxy /api/* backend:8000
    reverse_proxy /* frontend:3000

    Custom templates

    Available on the PRO plan.

    Custom templates

    Custom templates let you replace the default content CISO Assistant uses for outbound emails and for document exports.

    Administrators only. Creating, editing and deleting custom templates is restricted to users with the Administrator role. Templates control the wording of system emails and the body of exported documents, so a malicious or careless template could mislead recipients (e.g. a forged password-reset email) or embed inappropriate content in official exports.

    Word templates carry additional risk:

    Three template types live under this setting:

    • Email templates — the body and subject of system-generated emails (notifications, invitations, password reset, …).

    • Word templates — .docx files used as the visual skin for document exports (audit reports, risk-treatment plans, BIA outputs).

    • Document layout templates — .html files that control the PDF layout of managed documents (cover page, header/footer, branding).

    Every template is identified by two fields:

    • Template key — a stable identifier for what the template represents (e.g. audit_completion_notification, audit_report_export). The platform looks up the active template by key when the relevant action fires.

    • Language — the locale the template applies to. The platform falls back to the instance's default language if no template for the user's locale is present.

    A template is only used when its is_active flag is on, which lets you stage a draft alongside the live version and flip the switch when ready.

    Each email template carries a subject and a body. Body content supports the same templating variables as the default emails — use the in-app preview to inspect the variables available for a given key.

    Each Word template is an uploaded .docx file containing styled placeholders. The platform substitutes the dynamic content (assessment data, scores, evidence list) when generating the export.

    Document layout templates control how a managed document is rendered to PDF — on Export PDF and when a document is published. Each is an uploaded .html file (Django template syntax, with CSS in a <style> block), registered under the document_pdf template key, per language.

    When an active template exists for the document's language, the platform renders the document's content into your layout instead of the built-in one — letting you add a cover page, headers and footers, and your organisation's logo (from ). The template receives the document's title, rendered content, version, document_type, date, and the organisation logo.

    Download the built-in default first (from the setting) to use as a starting point, then upload your customised version. The built-in layout is used as a fallback when no active template exists for a language, and also if a custom template contains a disallowed tag or fails to render — a broken template never blocks a document from being published or exported.

    • Editing a template doesn't retroactively change documents that have already been exported.

    • Inactive templates remain in the database for audit-trail purposes.

    Template injection — .docx templates are rendered with a Jinja2-based engine. A crafted template can contain expressions that are evaluated on the server, which an attacker could abuse to read data or run unintended logic during export (server-side template injection).
  • Malicious macros — .docx files can embed VBA macros that execute on the machine of whoever opens the exported document. A booby-trapped template effectively ships malware to every report recipient.

  • Document layout templates carry the same template injection consideration: .html templates are rendered server-side with Django's template engine before the PDF is produced, so a crafted template could evaluate unintended expressions.

    Keep this permission limited to trusted administrators, only upload templates from sources you control, and review any template before activating it.

    Template key and language

    Email templates

    Word templates

    Document layout templates

    Operational notes

    Branding

    Organization

    You can find here CISO Assistant global organization. All entities will be linked to or contained within these objects.

    A folder organization

    For Access Control purpose, CISO Assistant data is organized in a tree of folders. Starting from a root folder called Global, it divide into sub-folders called domains. The organization of the tree is not hard-coded, it is entirely determined by configuration. Any object in CISO Assistant is attached to a folder (including folders), either directly or indirectly through a parent object that is attached to a folder.

    Organization example

    So, what is a domain?

    A domain permits to organize your work depending on your use of CISO Assistant. For example, inside a company, you can create a domain for each department for which you need to carry out a variety of perimeters, or if you have different customers, you may as well have a domain for each one in order to delimit your work area.

    Utility

    A domain is the first thing you create on CISO Assistant. It will bring together all objects you need to complete your different perimeters. Every role/permission a user has on a domain are applicable to all objects/actions across the domain. It's all about organization, the only technical aspect is access control, and this is achieved by adding the user to the relevant user group.

    Role assignment

    In the first/open source version of CISO Assistant, custom role assignment is not available. So, when you create a domain, user groups concerning this domain are automatically created for each built-in role. All you need to do, is to assign your users to their user groups. To learn more about this, jump to .

    Perimeters are fundamental context objects defined by the entity using CISO Assistant. They are grouped in domains. They will contain all your risk and audits. Apart from being able to group your various evaluations across the different domains.

    There are two specific fields, internal reference and status. Here are the various status options:

    • -- (None)

    • Design

    • Development

    • Production

    The purpose of a perimeter is at first, it's organizational aspect to solve a problem. But it also makes it possible to improve analytics by breaking them down according to the different assessments, whether for risk or compliance, so as to make your project management more precise and reduce noise.

    User groups go hand in hand with domains. they associate permissions with users and define their scope, by being attached to a domain. They follow a simple and consistent RBAC model from a role containing permissions and a domain determining the perimeter. Go to the page for more details.

    End of life

  • Dropped

  • Perimeters

    User Groups

    User groups
    User groups
    folder organization

    User groups

    User groups are built-in objects giving permissions to all users inside of them, with a specific role across a scope.

    For now, it is not possible to create custom role assignments so you need to use built-in user groups. They are linking a domain with a role which contains precise permissions, that will be given to users in this group.

    Roles

    Let's give some details on the 5 built-in roles:

    Role
    Permissions

    Administrator

    Once your instance is created, five user groups are already present:

    • Global - Administrator

    • Global - Analyst

    • Global - Reader

    • Global - Approver

    They give corresponding permissions on Global scope so on every object of your instance.

    They are created for each domain you add. For example, if you create a domain R&D, there will be:

    • R&D - Domain Manager

    • R&D - Analyst

    • R&D - Reader

    • R&D - Approver

    They give corresponding permissions on the domain scope so on every object inside R&D.

    You can manage the members of a user group directly from the group's detail page. This is available to administrators, and to domain managers for the groups of their own domains: membership is governed by the change user group permission on the group's domain, so a domain manager can add or remove members without needing global user-management rights.

    Open the user group and click Add members. A picker opens listing the users that are not yet in the group:

    • type in the search field to filter by email, first name or last name, or switch to Browse for a table view with per-column filters;

    • tick Include inactive to also list deactivated users;

    • your selection is kept while you search and change pages, and is summarised at the bottom of the picker;

    On the group's Users tab, tick the members to remove, then click Remove from group:

    Global - Respondent

    R&D - Respondent

    click Add members to confirm.

    full access (except approval), and specifically management of domains, users and users rights

    Domain manager

    full access to selected domains (except approval), in particular managing rights for these domains. Read access to global objects

    Analyst

    read-write access to selected perimeters/domains. Read access to global and domain objects

    Reader

    read access to selected perimeters/domains

    Approver

    like reader, but with additional capability to approve risk acceptances

    Respondent

    see for more details

    Django superuser is given administrator rights automatically on startup.

    Global user groups

    Domain user groups

    Managing group members

    Adding members

    Removing members

    Two safeguards apply: the last member of the Global - Administrator group can never be removed, and domain managers cannot remove themselves from a domain administrator group — another administrator has to do it.

    Adding members to a domain user group
    Removing selected members from a user group
    Assignments / respondent mode
    Add members picker on a user group
    Selecting members and removing them from the group

    Add and manage users

    Under Organization, click on Users and then Add user:

    Set up the email of the new user:

    Once created, a new user doesn't have any permissions by default. Click edit and update the user groups:

    If you are working on a single domain, or working on solo, you might just set `Global - Administrator`

    When the user are added, and if the mailer is set, he/she will receive an email to set up the password. If not, you can set a temporary password as illustrated above.

    Disable a user's MFA

    If a user has lost access to all their MFA factors (phone wiped, hardware key lost) and has no recovery codes left, an administrator can disable their MFA from the user's edit page. The link only appears when the target user has MFA enabled and you are not editing yourself. See for the full procedure.

    Setting up Multi-Factor Authentication (MFA) → Admin recovery

    Custom roles

    Fine-grained permissions management

    Enterprise (PRO) feature — ships in the Enterprise edition and is not reachable on the community edition.

    Custom roles allow you to refine access control when very specific permissions need to be granted to a user.

    In CISO Assistant, domains are the primary mechanism for restricting access. Custom roles should only be created when domain-based restrictions are insufficient.

    Keep in mind that custom roles increase IAM complexity and make access reviews more difficult. In most cases, the default roles are sufficient.

    Learn how to create and customize roles such as DPO and OPS within your organization

    Sign in as an Admin on your CISO Assistant instance and follow the steps below.

    1. Introduction

    This guide walks you through setting permissions and assigning user groups to streamline your CISO Assistant's role management.

    Introduction

    2. Click "Organization"

    Navigate to the Organization section to begin managing your team's roles.

    Access the Roles tab to view and modify existing roles.

    Initiate creating a new role by selecting the option to add one.

    Enter the name for the new role, such as 'DPO', to define its identity.

    Save the newly created role to confirm its addition to your organization.

    Open the permissions settings for the new role to customize access.

    Expand the permissions list to view all available options.

    Select all permissions to grant comprehensive access to the role.

    Save the permission settings to apply them to the role.

    Start creating another role by selecting the add role option again.

    Name this role, for example 'OPS', to specify its function.

    Save the role to add it to your organization's role list.

    Access the permissions for the newly created role to tailor its access.

    Open the detailed permissions menu to adjust specific controls.

    Select the option to edit applied controls for fine-tuning.

    Modify the applied control by entering a specific control number, such as '205'.

    Confirm the changes made to the applied control settings.

    View the applied control details to verify the configuration.

    Update the applied control with another control number, like '207', if needed.

    Return to the permissions overview to continue adjustments.

    Select all permissions to ensure full access for the role.

    Save all permission changes to finalize the role's capabilities.

    Switch to the User Groups section to manage group memberships.

    Navigate to the Users tab to assign roles to individuals.

    Select a user to modify their group memberships and roles.

    Open the user's group assignment settings to begin editing.

    Enter the role name, such as 'OPS', to assign it to the user.

    Choose the corresponding user group, like 'ACME - OPS', for the role.

    Input another role name, for example 'DPO', for additional assignments.

    Select the matching user group, such as 'Global - DPO', for this role.

    Review all assigned user groups and roles to ensure accuracy.

    Save the user group and role assignments to complete the process.

    This guide detailed how to create and configure custom roles like DPO and OPS, assign comprehensive permissions, and manage user group memberships effectively. It ensures your organization’s roles are tailored and users are properly assigned for optimal access control.

    3. Click "Roles"

    4. Click here

    5. Fill "DPO"

    6. Click "Save"

    7. Click here

    8. Click here

    9. Click "Select all"

    10. Click "Save"

    11. Click here

    12. Fill "OPS"

    13. Click "Save"

    14. Click here

    15. Click here

    16. Click here

    17. Click "Edit applied control"

    18. You can select an individual permission

    19. Click here

    20. Click here

    21. Click here

    22. Or you can click "Select all"

    23. Click "Save"

    24. Click "User groups" to see your newly added roles

    26. Click "Users"

    27. Click here

    28. Click here

    29. Fill "OPS"

    30. Click "ACME - OPS"

    31. Fill "DPO"

    32. Click "Global - DPO"

    33. Pick your user groups

    34. Click "Save"

    Custom roles for CISO Assistant
    Click 'Organization'
    Click 'Roles'
    Click here
    Fill 'DPO'
    Click 'Save'
    Click here
    Click here
    Click 'Select all'
    Click 'Save'
    Click here
    Fill 'OPS'
    Click 'Save'
    Click here
    Click here
    Click here
    Click 'Edit applied control'
    Fill '205'
    Click 'View applied control'
    Fill '207'
    Click here
    Click 'Select all'
    Click 'Save'
    Click 'User groups'
    Click 'Users'
    Click here
    Click here
    Fill 'OPS'
    Click 'ACME - OPS'
    Fill 'DPO'
    Click 'Global - DPO'
    Click 'Save'

    Understanding the IAM model

    Deep dive into CISO Asisstant IAM model

    Access security is a foundational aspect of any risk or compliance management platform. In this article, we’ll explore how authentication, authorization, and accounting — the three pillars of the AAA model — are structured and applied within CISO Assistant.


    1. Authentication: SAML vs OIDC

    CISO Assistant integrates with leading identity providers (IdPs) via SAML and OIDC, enabling secure and seamless single sign-on (SSO).

    SAML

    • legacy protocol based on XML

    • common in large enterprises, especially for AD

    • browser-based redirection with signed assertions

    • modern standard built on OAuth2

    • uses JWT tokens for identity transport

    • also browser-based, but more lightweight and versatile

    Recommendation: If your IdP supports both, prefer OIDC — it's more modern, flexible, and aligned with today’s security practices.


    Multi-Factor Authentication (MFA) is critical for access protection. CISO Assistant supports MFA in two distinct modes, depending on how users authenticate:

    • MFA is handled entirely by the identity provider (IdP)

    • the IdP enforces the policy (push notifications, TOTP, biometrics, etc.)

    • for local accounts, CISO Assistant includes native MFA

    • based on TOTP (e.g., Google/Microsoft Authenticators) and WebAuthn / passkeys (hardware security keys, platform authenticators)

    • recovery codes are issued at enrolment so the user can self-recover from a lost factor


    CISO Assistant implements a robust Role-Based Access Control (RBAC) model that balances flexibility, clarity, and operational simplicity.

    Each object type has granular CRUD permissions (create, read, update, delete). This model applies across all business entities: users, backups, risks, policies, incidents, data processing, and more. There are more than 200 permissions in CISO Assistant.

    Permissions are grouped into a small set of standard roles:

    • Administrator – full access to all objects and settings

    • Analyst – full access to most objects, but cannot modify access control

    • Viewer – read-only access

    Roles are assigned within a domain — a flexible concept representing any relevant business context.

    For example, a domain can represent:

    • a legal entity

    • a country or region

    • a subsidiary

    Domains are hierarchical: a role assigned to a parent domain (e.g., "Group") automatically applies to all its subdomains (e.g., subsidiaries, teams).

    Access control is defined via explicit assignments:

    A role ➡️ on a domain ➡️ for a group of users

    Users do not have direct roles. They inherit permissions through membership in one or more groups.

    Groups act as the central pivot for managing access:

    • receive role assignments

    • grant users permissions via group membership

    • defined locally

    • optionally synced with an IdP (via external plugin)

    🚀 This simple yet powerful model accommodates the vast majority of real-world access scenarios. And when needed, the system is fully extensible: it supports custom roles, custom role assignments, and custom user groups to fit even the most specific organizational needs.


    CISO Assistant doesn’t just secure human access — it also supports secure, auditable access for automated systems and integrations through Personal Access Tokens (PATs).

    A Personal Access Token is a time-limited secret that allows a script, CI/CD pipeline, or service to authenticate with the platform's API on behalf of a user or machine identity — without requiring an interactive login.

    • time-bounded: expiration is mandatory

    • RBAC-compliant: inherits the creator’s permissions

    • revocable: can be revoked by user or admin

    • admins can restrict who may generate PATs

    • all tokens are auditable and managed via UI or API

    This ensures tight control over non-human access, balancing automation flexibility with strict security hygiene.

    The following schematic illustrates the fundamental concepts of IAM in CISO Assistant.

    All objects of CISO Assistant support a built-in flag called is_published.

    Objects with the flag is_published are visible in subdomains as if they were attached to each subdomain of the object's domain. This mechanism only concerns visibility, not creation/udpate/deletion. All objects are currently published, except assessments (audits, risk analysis, BIA, entitiy assessments)

    To avoid an object being published, the simplest solution is to put it in a leaf subdomain.

    The plan is to remove this mechanism by Q2 2026 and introduce dynamic groups instead (e.g. the group of all users).

    You can attach this object to a subdomain (e.g. named "published"), and add every user in the group corresponding to reader role on the subdomain. This does not rely on the publication mechanism, and is more generic.

    CISO Assistant includes native tracking of all key actions:

    • logins, restorations, configuration changes, approvals…

    • a searchable audit log accessible via the UI or API

    This enables complete accountability over critical operations.

    CISO Assistant's AAA model is built on:

    • Open standards (SAML, OIDC, TOTP, RBAC)

    • A structured yet manageable authorization system

    • secure automation through scoped, revocable Personal Access Tokens (PATs)

    It supports complex organizations while remaining readable, scalable, and compliant with modern security expectations.

    if a user loses every factor and runs out of recovery codes, an administrator can disable their MFA from the user's edit page — see Setting up MFA → Admin recovery. The link is hidden on your own edit page; to disable your own MFA, use the standard MFA settings page on My profile → Settings.
    Approver – strictly limited to approving risk acceptance requests
    a business unit
  • any other meaningful organizational structure

  • Built-in traceability from the ground up

    OIDC (OpenID Connect)

    2. MFA

    SSO-Based Authentication (SAML / federated OIDC)

    Local Authentication

    3. Authorization: Structured and Hierarchical RBAC

    Fine-Grained Permissions

    Predefined Roles

    Hierarchical Domains

    Role Assignments

    User Groups

    4. Machine Identity: Personal Access Tokens with Expiration & Control

    Definition

    Key features

    Governance controls

    5. Illustration

    6. Publication mechanism

    Can I make an object visible to all users without attaching it to global?

    7. Accounting: Full Audit and Traceability

    In Summary

    SSO

    Configure Single Sign-On with different SAML or OpenID Connect providers

    Documented providers

    • Microsoft Entra ID

    • Okta

    • Keycloak

    By default, logging out of CISO Assistant only ends the local CISO Assistant session. The identity provider session stays open, so clicking Log in with SSO again signs the user straight back in without re-authenticating.

    To also close the identity provider session on logout, enable Enable service provider-initiated single logout in the SSO settings. When it is on, logging out of CISO Assistant redirects the browser through the identity provider's logout endpoint.

    This is service provider-initiated single logout: CISO Assistant asks the identity provider to end its own session for the user. Whether that in turn signs the user out of other applications federated to the same identity provider depends on the identity provider's single-logout configuration and is not something CISO Assistant controls or can guarantee.

    The option is off by default, and each protocol needs a logout endpoint on the identity provider side:

    • OIDC — the provider must expose an end_session_endpoint, and <frontend_url>/login must be registered as an allowed post-logout redirect URI. See .

    • SAML — the identity provider Single Logout Service URL must be available (read from the metadata, or set in the SLO URL field). See .

    Enabling SSO adds the Log in with SSO button but leaves the email/password form in place, so users can still authenticate locally. To make SSO the only way in, turn on Force SSO Login in the SSO settings.

    When Force SSO Login is enabled, local password authentication is disabled for everyone — a user who tries the password form is rejected with "This user is not allowed to use local login."

    To keep a few accounts able to log in locally (typically break-glass administrators, or a service account used while the identity provider is being set up), enable the per-user Keep local login flag on their user record. These accounts continue to work through the standard password form even while SSO is forced.

    Some accounts get Keep local login enabled by default when they are created:

    • Superusers created with createsuperuser (or at first boot), so the initial administrator is not locked out.

    • Third-party users (portal / TPRM accounts).

    Note that this is only a default on the flag, not a permanent exemption: a regular user promoted to superuser afterwards does not get it automatically, and unticking Keep local login on any of these accounts removes their local access like anyone else.

    SCIM-provisioned users, by contrast, are SSO-only by design.

    By default the login page shows the standard email/password form alongside a Log in with SSO button. You can send users straight to your identity provider — skipping the form — by appending ?sso to the login URL:

    Opening that link starts the SSO redirect immediately, exactly as if the user had clicked Log in with SSO. It's convenient as a bookmark, or as the link you publish internally when SSO is the expected way in.

    To send the user to a specific page after they authenticate, add a next parameter:

    Single Logout

    Keep CISO_ASSISTANT_URL set to the public frontend URL, otherwise the post-logout redirect will not resolve.

    Forcing SSO and local-login exceptions

    Turning on Force SSO Login clears the password of every account that does not have Keep local login enabled. Set Keep local login on your exception accounts before you enable Force SSO Login — otherwise their passwords are wiped, and re-enabling the flag afterwards does not restore them (the user has to go through a password reset, which requires a working mailer). Always confirm at least one break-glass account can still log in before forcing SSO.

    Direct SSO login link

    ?sso only triggers the redirect when SSO is enabled. Users who are allowed to keep local login — for example break-glass administrators — can still reach the password form through the plain /login URL.

    Google Workspace
    OpenID Connect
    SAML
    https://<your-instance>/login?sso
    https://<your-instance>/login?sso&next=/analytics

    Teams

    Teams in CISO Assistant are used to group users who work together on the same security activities, such as risk assessments, compliance programs, or audits.

    Each team has a Team Leader, optional Deputies, and Members, making it easy to reflect real-world responsibilities and delegation. A team can also have a dedicated team email address for shared communications. Teams centralize ownership, collaboration, and notifications by allowing CISO Assistant to automatically reach the right people based on their role within the team.

    Tasks, assessments, assets, applied controls, etc., can be assigned to teams, in the same way as to users.

    OpenID Connect (OIDC)

    Configure CISO Assistant with OpenID Connect (OIDC)

    Once you've retrieved the Client ID, the Client Secret and the Issuer URL (sometimes called the discovery or .well-known URL) from your provider, the configuration on CISO Assistant is pretty simple.

    1. Log in into CISO Assistant as an administrator > Extra > Settings

    2. Navigate to SSO settings

    3. Enable SSO

    4. Select the OpenID Connect provider

    5. Enter the Client ID

    6. Enter the Client secret

    7. Enter the Server URL

    8. And that's it! Don't forget to click the 'Save' button

    9. You should now be able to see the Login with SSO button

    Turn on Enable service provider-initiated single logout in the SSO settings to close the OIDC session at the identity provider when users log out of CISO Assistant (see for the general behavior). It additionally requires:

    • an end_session_endpoint in the provider's OpenID configuration, and

    • <frontend_url>/login registered as an allowed post-logout redirect URI on the OIDC client.

    CISO Assistant calls the end-session endpoint with client_id, id_token_hint, and that post-logout redirect URI.

    Be aware that the user needs to be created on CISO Assistant to be authenticated with SSO.

    CISO Assistant automatically sends a standards-compliant state and nonce on every OIDC authorization request (43 characters matching ^[A-Za-z0-9-._~]{43,128}$), and validates the nonce claim returned in the id_token. No configuration is required. This is helpful for identity providers that enforce format or length constraints on these parameters. Per OIDC Core 3.1.3.7, the nonce sent in the authorization request must be present and match in the id_token — a missing or mismatched nonce will reject the login.

    Single Logout

    With Microsoft Entra ID, OIDC logout still prompts the user to select an account, because Entra ignores the standard id_token_hint. The logout itself works, but the prompt cannot be suppressed without Entra-specific configuration. For a prompt-free single logout with Entra ID, use SAML instead.

    Single Logout

    Identity providers

    You can log into CISO Assistant with any identity provider (IdP), given that it supports either SAML or OpenID Connect (OIDC).

    Don't find documentation on how to set up SSO with your identity provider? Feel free to reach out to us on Discord, or contribute to the docs.

    SCIM provisioning and IdP groups

    Provision users from your identity provider with SCIM 2.0, and map external IdP groups to CISO Assistant user groups so that roles are granted automatically.

    SCIM 2.0 lets your identity provider (Okta, Microsoft Entra ID, Keycloak, …) push users into CISO Assistant automatically, so you no longer have to create accounts by hand. IdP groups are the bridge between a group that exists in your identity provider and the CISO Assistant user groups it should grant.

    This is a PRO feature. It is gated by the IdP groups feature flag (see ). While the flag is off, the IdP groups menu, the SCIM settings tab and the IdP groups column on the users table stay hidden. The flag is enabled by default on PRO instances.

    The IdP groups feature flag in Settings › Feature flags.

    How it works

    Authentication and provisioning are two separate concerns, handled by two complementary mechanisms:

    • Your IdP authenticates users through SAML or OpenID Connect (OIDC).

    • Your IdP provisions users and their group memberships through SCIM.

    The link between the two worlds is the IdP group — a faithful mirror of a group that exists in your identity provider. An administrator maps each IdP group to one or more user groups. A user who belongs to an IdP group then inherits the roles of every user group it is mapped to.

    This is a groups of groups model: membership flows from IdP group → user groups → roles, and the effective roles are recomputed on the fly. A user's direct (manually assigned) user groups and the ones inherited through their IdP groups are simply added together — neither overrides the other.

    IdP groups live under Organization > IdP groups in the sidebar. The page behaves like any other object table — view, create, edit and delete.

    Creating or editing an IdP group asks for two things:

    • Name — the display name of the group as it exists in your identity provider.

    • User groups — one or more CISO Assistant this IdP group should grant. Edit this list at any time; every member of the IdP group is re-granted immediately.

    The members of an IdP group are managed by SCIM and shown read-only. You will also find an IdP groups column on the Organization > Users table, listing the IdP groups each user belongs to.

    1. Log in as an administrator > Extra > Settings and open the SCIM tab.

    2. Copy the SCIM endpoint URL (for example https://<your-instance>/api/scim/v2/). This is the base URL your identity provider connects to.

    3. Click Generate token and copy the bearer token that is displayed.

    You can generate several tokens (one per integration) and revoke any of them at any time from the same screen.

    • Each IdP group is identified by the UUID that CISO Assistant assigns it. Your identity provider stores that id and reuses it, so renaming a group in the IdP simply updates its name — memberships and the user-group mapping are preserved.

    • The first time your IdP pushes a group that does not exist yet, CISO Assistant creates the IdP group automatically.

    • Deleting an IdP group (or removing it from the IdP) removes the access it granted, but never touches a user's manually assigned user groups — those are a separate, direct membership.

    • SCIM provisions accounts; it does not replace authentication. Provisioned users still sign in through your configured provider.

    • CISO Assistant implements the inbound SCIM 2.0 Users and Groups resources (RFC 7643/7644) and is identity-provider agnostic.

    In your identity provider's provisioning settings, enter the SCIM endpoint URL and authenticate with the token using the Authorization: Bearer <token> scheme.

  • Assign users and groups to CISO Assistant in your identity provider, and let it provision them.

  • An IdP group grants nothing until you map it to at least one user group. SCIM can keep pushing memberships into an unmapped IdP group safely; those users gain access only once the mapping exists.

    Managing IdP groups

    IdP groups are administered globally and are only visible to administrators, just like and roles.

    Configuring SCIM

    The token is shown only once. Copy it now — for security reasons it cannot be retrieved again. If you lose it, revoke it and generate a new one.

    Identity, renames and deletion

    Notes

    Related

    User groups
    SSO
    SSO
    User groups
    Understanding the IAM model
    Feature flags
    Organization › IdP groups — each IdP group and the user groups it grants.
    Creating an IdP group: its IdP-side name and the user groups it grants.
    The IdP groups column on the users table shows SCIM-managed memberships.
    Settings › SCIM — the endpoint URL and bearer-token management.
    Feature flags
    Community vs PRO
    User groups

    SAML

    Please note: if OIDC mode has ben configured before, you must reset the Client ID field to 0 in the OIDC tab and save before proceeding.

    Configure CISO Assistant with SAML

    Once you've retrieved the IdP Entity ID, the Metadata URL and the Entity ID from your provider (see the list of providers for specific details), the configuration on CISO Assistant is pretty simple.

    1. Log in into CISO Assistant as an administrator > Extra > Settings

    2. Enable SSO

    3. Enter the Idp Entity ID

    4. Choose the option 1 or 2 depending of your provider and fill Metadata URL or SSO URL, SLO URL, x509 certificate retrieved from your provider

    5. Check that the SP Entity ID is similar to the Entity/Client ID specified on your provider

    6. And that's it! Don't forget to save changes

    7. You should now be able to see the Login with SSO button

    • Allow single label domains: This allows you to authenticate through SAML on a single-label domain (e.g. https://ciso-assistant:8443). If this is left unchecked, the only host forms allowed are:

      • IPv4

      • IPv6

    Turn on Enable service provider-initiated single logout in the SSO settings to close the SAML session at the identity provider when users log out of CISO Assistant (see for the general behavior).

    It also needs the identity provider's Single Logout Service URL. When you configure the identity provider by Metadata URL, this is read automatically from the metadata — the SLO URL field is only used when you configure the identity provider manually.

    Some identity providers require signed logout requests. In that case, enable Logout request signed in the advanced SAML settings and configure the SP private key and certificate — and register that SP certificate with the identity provider so it can verify the signature. Microsoft Entra ID, for example, rejects unsigned SAML logout requests.

    FQDN (e.g. https://www.example.com/)

  • localhost

  • Authn request signed: allows the Service Provider (SP) to digitally sign the SAML authentication request sent to the Identity Provider (IdP).

    This option should be enabled if your IdP requires signed authentication requests or if you are looking to enforce additional security on SAML authentication flows:

  • Failure to do so will prevent proper SAML configuration. This behavior is known and will be addressed in future releases.

    Single Logout

    Be aware that the user needs to be created on CISO Assistant to be authenticated with SSO.

    Single Logout

    Keycloak

    Configure Keycloak as an Identity Provider for CISO Assistant

    If Keycloak and CISO Assistant are both deployed locally with docker, you'll need to make sure that both containers can communicate together. You can do this with a .

    Go into your Keycloak admin console

    1. Open the sidebar menu > Clients and Create client

    2. Choose SAML client type and name it ciso-assistant or with your custom SP Entity ID

    3. Fill the Home URL with your <base_url> and Valid redirect URIs with <backend_url/*>

      If you have some problems to configure these urls you can ask for help on or by emailing us

    4. Go into Keys and disable Signing keys config

    5. Go into Advanced and fill ACS field with <backend_url/api/accounts/saml/0/acs/> (on a cloud instance it is simply <base_url/api/accounts/saml/0/acs/>)

    6. Go to Client scopes and click on ciso-assistant-dedicated

    7. Add a predefined mapper and check all X500 ones

    8. Click on X500 surname and replace SAML Attribute name with http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname

    9. Click on X500 givenName and replace SAML Attribute name with http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname

    10. Go into Realm settings > General, you will find the Metadata URL

    11. You'll find inside the Metadata URL the Entity ID

      The same metadata also contains Keycloak's Single Logout Service URL, so it is picked up automatically. To also close the Keycloak session when users log out of CISO Assistant, just turn on Enable service provider-initiated single logout in the SSO settings.

    Go into your Keycloak admin console

    1. Open the sidebar menu > Clients and Create client

    2. Choose OpenID Connect client type and give it a Client ID, then click Next

    You can now with the parameters you've retrieved.

    Enable Client authentication, make sure Standard flow is selected, then click Next

  • Enter your deployment's Root URL. It is the URL of your frontend.

    1. Set it to <frontend_url>

    2. For cloud deployments, you must set it to <base_url>

  • Set the Home URL to /

  • Enter your Valid redirect URIs

    1. Set it to <backend_url>/api/accounts/oidc/openid_connect/login/callback/

    2. For cloud deployments, you must set it to <base_url>/api/accounts/oidc/openid_connect/login/callback/

  • Enter your Valid post logout redirect URIs

    1. Set it to <frontend_url>/login

    2. For cloud deployments, set it to <base_url>/login

  • Once your client is created, you can find its Client secret under the Credentials tab. You can copy it from there

  • Go into Realm settings > General to find the OpenID Endpoint Configuration, which you will have to paste into CISO Assistant's Server URL SSO parameter

  • Adding a user in your application doesn't automatically create the user on CISO Assistant

    Discord
    configure CISO Assistant
    bridge network

    Microsoft Entra ID

    Configure Microsoft Entra ID as an Identity Provider for CISO Assistant

    Go into your Azure portal home

    1. Open the sidebar menu and click on Microsoft Entra ID

    2. Click on Add button > Entreprise application

  • Click on Create your own application

  • Enter a name and then click Integrate any other application you don’t find in the gallery (Non-gallery)

  • Click on Single sign-on from the sidebar menu or on Set up single sign on bellow Getting Started and choose SAML

  • In the first box Basic SAML Configuration, specify the Entity ID, it has to be the same than SP Entity ID in CISO Assistant (see next screenshot)

  • Add the Reply URL: <base_url>/api/accounts/saml/0/acs/ (for example with localhost: https://localhost:8443/api/accounts/saml/0/acs/)

  • In the third box SAML Certificates, copy the App Federation Metadata Url as it is the Metadata URL in CISO Assistant (see next screenshot)

  • In the fourth box Set up <App_name>, copy the Microsoft Entra Identifier as it is the IdP Entity ID in CISO Assistant

  • Make sure you use the same Identifier (Entity ID) that you've set earlier and appear on block 1, on CISO Assistant SP Entity ID:

  • Click on Users and groups in the sidebar menu, and Add user/group to give them access to CISO Assistant with SSO. The matching key will be the email and you'll be able to grant their permissions on the applications.

  • You can now configure CISO Assistant with the 3 parameters you've retrieved.

  • 1. Introduction

    Go to your Microsoft Azure Portal

    Introduction

    2. Navigate to App Registrations

    Click the App registrations section to add a new application for OIDC configuration. You can also use the search bar if you don't find it in the suggestions.

    Navigate to App Registrations

    3. Start New Application Registration

    Start New Application Registration

    4. Name your application

    Name your application

    5. Select Web Platform in Redirect URI options

    Select Web Platform in Redirect URI options

    6. Enter the callback URL of your instance

    The callback URL is: <ciso_assistant_url>/api/accounts/oidc/openid_connect/login/callback/ for

    for instance, for localhost: http://localhost:8000/api/accounts/oidc/openid_connect/login/callback/

    Adding a user in your Entra application doesn't automatically create the user on CISO Assistant

    7. Complete Application Registration

    8. Copy the Application Client ID

    9. Past it into the Client ID field

    10. Open Certificates & Secrets

    11. Create a New Client Secret

    12. Add your Client Secret

    13. Copy the fresh Client Secret Value

    14. Past it into the Secret field

    15. Go back to your App Overview

    16. Inside Endpoints copy the OpenID Connect metadata URL

    17. Paste it into the Server URL field

    18. Save your configuration

    You have successfully configured OpenID Connect (OIDC) integration with EntraID.

    Enter the callback URL of your instance
    Complete Application Registration
    Copy the Application Client ID
    Past it into the Client ID field
    Open Certificates & Secrets
    Create a New Client Secret
    Add your Client Secret
    Copy the fresh Client Secret Value
    Past it into the Secret field
    Go back to your App Overview
    Inside Endpoints copy the OpenID Connect metadata URL
    Paste it into the Server URL field
    Save your configuration

    Google Workspace

    Configure Google Workspace as an Identity Provider for CISO Assistant

    Google Workspace doesn't allow callbacks to urls containing http or localhost so it can be tricky to test it locally. You should deploy CISO Assistant with a FQDN to bypass these restrictions.

    Go into Google Workspace Admin console

    1. On the sidebar menu, go to Applications > Web and mobile applications

    2. Click on Add an application > Add a custom SAML Application

    3. Enter ciso-assistant or the name of your choice and click on continue

    4. You can copy the SSO URL, Entity Id and x509 certificate here but you'll be able to retreive them later

    5. Fill ACS URL with <base_url>/api/accounts/saml/0/acs/, enter the Entity ID which has to be the same than SP entity Id in CISO Assistant (ciso-assistant by default) and choose Email in Name ID Format

    6. Add two mappings for First name and Last Name, fill them with those two values: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname

    7. On application home page, you can now find the Entity ID, SSO URL and x509 certificate

    You can now with the 3 parameters you've retrieved.

    Add a user in your application doesn't automatically create the user on CISO Assistant

    configure CISO Assistant

    Libraries

    Bringing content into CISO Assistant

    Libraries are how content gets into CISO Assistant — frameworks, threats, risk matrices, reference controls, mappings. They ship as YAML files, are versioned, and can be upgraded or removed cleanly.

    This section covers everything you need to manage them on your instance:

    • Designing your own libraries — the Excel-to-YAML authoring workflow.

    • Getting your custom framework — quick-start for adding a single framework.

    • — direct import of CIS/CSA spreadsheets.

    • — pull a newer version of an already-loaded library.

    • — refresh built-in libraries after updating your instance.

    • — remove a loaded library when it's no longer in use.

    See also: , .

    CIS Controls / Cloud Controls Matrix (CCM)
    Library upgrade
    Upgrading a library
    Library clean-up
    Libraries concept
    Frameworks concept

    Okta

    Configure Okta as an Identity Provider for CISO Assistant

    Go into your Okta admin console (it should look like this: https://<your_url>.okta.com/admin/dashboard)

    1. In the sidebar menu, click on Applications > Applications

    2. Click now on Create App Integration

    3. Select SAML 2.0 and click on Next

    4. Choose an App name and click on Next

    5. Add the Single sign-on URL: <base_url>/api/accounts/saml/0/acs/ (for example with localhost: https://localhost:8443/api/accounts/saml/0/acs/) (see screenshot below)

    6. Add the Audience URI (SP Entity ID), it has to be the same than SP Entity ID in CISO Assistant (see screenshot below)

    7. Choose Email as the Application username

    8. Add Attribute Statements

      • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname for user's first name

      • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname for user's last name

    9. Click on Next and fill in the Feedback page as you wish then click on Finish

    10. In the Settings box inside SAML 2.0:

      • Copy the Metadata URL and paste it into the Metadata URL field in CISO Assistant

      • Copy the Issuer url and paste it into the IdP Entity ID field in CISO Assistant

    11. Go to the Assignments tab

    12. Click on Assign and choose whether you want to assign users or specific groups

    You can now with the 3 parameters you've retrieved.

    Add a user in your application doesn't automatically create the user on CISO Assistant

    configure CISO Assistant

    Multi-Factor Authentication (MFA)

    Multi-factor authentication adds an extra layer of security to your account. CISO Assistant supports both TOTP authenticator apps and WebAuthn security keys (FIDO2, hardware keys, fingerprint, passkey

    CISO Assistant supports two second-factor methods, and both can be enrolled on the same account:

    • TOTP — time-based one-time passwords generated by an authenticator app on your phone (Google Authenticator, Microsoft Authenticator, 1Password, Authy, Bitwarden, …).

    • Security keys (WebAuthn) — hardware tokens (YubiKey, Titan, SoloKey, …), platform authenticators (fingerprint readers, Windows Hello, Touch ID, Face ID), and passkeys. Anything that speaks FIDO2 / WebAuthn works.

    Recovery codes are always issued alongside the chosen method so you can regain access if you lose both your phone and your security key.

    Pick at least one of the following:

    • A smartphone with an authenticator app installed (for TOTP), or

    • A WebAuthn-capable device — a hardware security key, or a platform authenticator like a fingerprint reader, Windows Hello, Touch ID, or a passkey-capable browser.

    Plus, of course, access to your account settings on CISO Assistant.

    1. Sign in to your account and navigate to My profile.

    1. Select Settings.

    2. Look for the Security section and click Enable 2FA.

    3. Set up your authenticator app:

    1. Sign in and navigate to My profile → Settings.

    2. In the Security section, choose to enrol a security key.

    3. When the browser prompts you, present the authenticator:

    You can enrol multiple credentials on the same account — common patterns are a hardware key as the primary and a phone/passkey as the backup, or one key kept at the office and another at home.

    After enabling MFA, you'll receive a set of recovery codes. These codes are crucial for regaining access to your account if you:

    • Lose your phone or security key

    • Uninstall your authenticator app

    • Cannot reach any of your enrolled second factors

    If a user has lost access to every enrolled second factor (phone wiped, hardware key lost) and has no recovery codes left, an administrator can disable their MFA from the user's edit page:

    1. Sign in as an administrator and navigate to Organization → Users.

    2. Open the affected user and click Edit. In the security section of the edit page, click disable their MFA.

    1. On the confirmation page, type the confirmation word shown on screen (the localized word for "yes") and submit.

    All of the user's MFA authenticators (TOTP, WebAuthn credentials, recovery codes) are removed. The user will need to enable MFA again on their next login.

    When MFA is enabled, the login flow asks for a second factor after the password. If you've enrolled both a security key and TOTP, the platform prefers the security key prompt by default and offers a "use authenticator app instead" link as a fallback. Either method completes the sign-in.

    • Test your MFA setup by logging out and back in.

    • If you enrolled a hardware key, enrol a backup (a second key, a passkey, or TOTP) — losing the only one is the most common lockout scenario.

    • Reach out for support if you encounter any issues during setup.

    Starting v3.13.0 you can enforce MFA for all users by enabling this flag. Users will see a persistent redirect to the MFA configuration page until enrolment is done. The feature doesn't interfere with SSO as long as the user doesn't have both a local account and an SSO one.

    Open the app on your smartphone.
  • Scan the QR code displayed on screen.

  • Alternatively, enter the provided secret code manually.

  • Enter the 6-digit verification code shown in your authenticator app.

  • Click Enable 2FA to complete the setup.

  • Hardware key — insert it and tap when it blinks.
  • Platform authenticator — confirm via fingerprint, face recognition, or device PIN.

  • Passkey — pick the existing passkey from your password manager.

  • Give the credential a recognisable name (e.g. "YubiKey blue", "MacBook Touch ID") so you can identify it later if you enrol several.

  • Prerequisites

    Enable TOTP (authenticator app)

    Enable a security key (WebAuthn)

    Important: save your recovery codes

    Security Warning:

    • Store your recovery codes in a secure location, separate from your password

    • Each recovery code can only be used once

    • Never share your recovery codes with anyone

    • Consider storing a copy both digitally (in a password manager) and physically (printed in a secure location)

    Admin recovery: disabling another user's MFA

    Audit notes:

    • Every admin MFA disable is logged on the backend (admin id/email, target id/email, number of authenticators removed).

    • The link is hidden on your own edit page — to disable your own MFA, use the standard MFA settings page on My profile → Settings.

    • Only users in the built-in Global - administrator group can disable another user's MFA.

    Logging in with MFA

    Next steps

    Enforce MFA for all users

    The "Disable MFA" link on a user's edit page (visible only to admins, when the target user has MFA enabled).
    The confirmation page requires typing the localized confirmation word shown on screen before MFA can be disabled.

    Designing your own libraries

    This documentation explains how to create, maintain and evolve custom libraries for CISO Assistant using Excel, YAML, and the official tools provided in the community repository.


    A library is a container that bundles one or more governance objects that can be imported into CISO Assistant.

    A single library may contain:

    • Framework

    Threats

  • Reference controls

  • Risk matrices

  • Answer sets

  • Score definitions

  • Implementation groups

  • Mappings between frameworks

  • Libraries are versioned, portable, and reusable across projects.

    In practice:

    • Excel (.xlsx) is the authoring format

    • YAML (.yaml) is the import/export format

    • Python tools are used to convert and validate data


    Before creating your first library, it is important to understand a few core concepts.

    A framework is a hierarchical structure representing a standard, regulation, or internal control model.

    A framework is composed of:

    • Organizational nodes (categories, sections, subsections, information, ...)

    • Requirements, which are the assessable elements

    Only requirements can be assessed during audits.

    Hierarchy example of a framework

    In a framework:

    • Categories and sections are structural

    • Requirements are assessable

    This distinction is explicit in Excel via the assessable column.

    Frameworks are hierarchical by nature.

    • Each row in Excel has a depth

    • Depth starts at 1

    • Deeper levels represent nested structures

    CISO Assistant supports deep hierarchies, but depths above 6 are strongly discouraged for readability.

    Each object is uniquely identified by a URN.

    • ref_id is the human-defined identifier

    • URNs are generated using urn_prefix + ref_id

    • URNs must remain stable across versions

    Implementation Groups allow you to:

    • Scope requirements

    • Build subsets of a framework

    • Adapt questionnaires to context or maturity level

    They are optional but highly recommended for complex frameworks.

    Frameworks can define:

    • Scoring models

    • Answer sets

    • Conditional questions

    • Weighted scoring

    These elements allow frameworks to behave as questionnaires, not just checklists.

    Mappings describe relationships between requirements from different frameworks.

    They are used to:

    • Translate compliance

    • Compare standards

    • Build equivalency views

    Mappings are directional and typed (equal, subset, superset, intersect).


    Here is the recommended procedure for creating and maintaining custom libraries:

    1

    Define the framework structure or use an existing one

    Plan the structure and decide whether to start from scratch or reuse an existing framework.

    2

    Generate a base Excel file (v2 format)

    Use the provided tooling to create a valid v2 Excel skeleton.

    3

    Fill in framework content

    Populate the _content tabs with requirements.

    4

    Use the conversion tool to generate a CISO Assistant-compatible YAML library.

    5

    Upload and validate the generated YAML in CISO Assistant.

    6

    Follow versioning and URN stability rules when updating.


    Excel is the recommended authoring format because:

    • It is accessible to non-developers

    • It enforces structure

    • It reduces YAML syntax errors

    • It supports collaboration and review

    Excel files are converted to YAML only at the final step.

    Excel files follow strict conventions.

    Tabs are divided into:

    • _meta tabs → configuration and metadata

    • _content tabs → actual objects and data

    Each object type has:

    • One _meta tab

    • One _content tab (except library_meta)

    Before creating or editing your own framework, we strongly recommend reviewing the provided example file example_framework.xlsx.

    This file is a reference implementation of the Excel v2 format and is designed to help users understand how a valid framework is structured.

    The Excel v2 format is powerful but can be confusing at first. The example framework helps you understand:

    • How _meta and _content tabs are organized

    • How hierarchy is expressed using depth and row order

    • The difference between structural nodes and assessable requirements

    • How advanced fields (implementation groups, questions, answers, scoring) are represented

    • How real-world frameworks should be laid out in Excel

    The file is intentionally:

    • Color-coded to highlight structure

    • Annotated with cell notes (look for the small triangle in the top-right corner of cells)

    1

    Open example_framework.xlsx in Excel or LibreOffice and explore the tabs and cell notes.

    2

    If you would like to see what this example looks like directly in CISO Assistant, convert it using the standard conversion tool:

    Convert the example
    python convert_library_v2.py example_framework.xlsx

    Use the example file whenever you:

    • Start a new framework from scratch

    • Are unsure about the meaning of a column

    • Encounter validation errors during conversion

    • Want to check whether your Excel file follows best practices

    This tab defines the library itself.

    Mandatory fields include:

    • type

    • urn

    • version

    • locale

    • ref_id

    • name

    • description

    • copyright

    • provider

    • packager

    A framework is defined using:

    • One _meta tab of type framework

    • One _content tab listing all nodes

    The _content tab is ordered top-to-bottom and defines the hierarchy.

    Important columns:

    • assessable

    • depth

    • ref_id

    • name

    • description

    • implementation_groups (if applicable)

    • questions / answers (if applicable)

    • min_score, max_score, scores_definition_ref (optional requirement-level scoring override)

    Framework _meta tabs define the default scoring scale with min_score, max_score, and scores_definition. A row in the framework _content tab can override that scale for a specific requirement:

    • min_score — integer minimum score for this requirement.

    • max_score — integer maximum score for this requirement.

    • scores_definition_ref — name of a scores object block from the framework's alternatives registry to use as the level labels for this requirement.

    Each field cascades independently. Leave the cells blank to inherit the audit-level value at runtime; that audit value is usually initialised from the framework when the audit is created. If you override the range, make sure the referenced alternative covers every integer score from min_score to max_score; otherwise conversion or import validation will reject the library. Also keep choice add_score values within the requirement's effective range.

    Threats represent events or situations that may negatively impact an organization.

    Typical examples include:

    • Data breach

    • Ransomware attack

    • Insider threat

    • Loss of availability

    Threats are designed to be reusable across multiple frameworks and libraries.

    Threats are defined using:

    • One _meta tab of type threats

    • One _content tab listing individual threats

    Each threat includes:

    • A ref_id

    • A name

    • A description (optional)

    • Annotations (optional)

    Threats are usually referenced from framework requirements using their URN.


    Reference controls describe controls or safeguards that can mitigate threats or help fulfill requirements.

    They are typically used to:

    • Document expected controls

    • Link requirements to best practices

    • Support evidence collection and audits

    Examples:

    • Access control policy

    • Backup procedures

    • Network segmentation

    • Incident response process

    Reference controls are defined using:

    • One _meta tab of type reference_controls

    • One _content tab listing individual controls

    Each control include:

    • A ref_id

    • A name

    • A description (optional)

    • A category (policy, process, technical, physical, procedure) (optional)

    • An CSF function mapping (optional)

    • Annotations (optional)

    Risk matrices are used to model risk evaluation logic, typically combining probability and impact into a resulting risk level.

    They define how risk is calculated, not how compliance is assessed.

    Risk matrices are usually:

    • Independent from frameworks

    • Shared across multiple projects

    • Maintained separately from compliance libraries

    For this reason, they are most often packaged alone in their own library, without any framework.

    A risk matrix is defined using:

    • One _meta tab of type risk_matrix

    • One _content tab describing:

      • Probability levels

      • Impact levels

      • Risk levels

      • The risk grid mapping probability × impact to risk

    The grid defines the logical relationship between values. The visual rendering (orientation, colors, layout) is handled by the CISO Assistant interface.

    Risk matrices are not trivial to design correctly, especially the grid logic.

    For this reason, we strongly recommend starting from one of the existing examples available in tools/excel/matrix.

    These examples:

    • Are already valid and tested

    • Follow best practices

    • Can be adapted to your own risk model

    Risk matrices can be converted and imported using the same tools as other library objects.


    All tools described below are located in the /tools directory of the community repository.

    These tools are designed to:

    • Reduce human errors

    • Enforce the CISO Assistant data model

    • Make libraries easier to maintain over time

    You do not need to use all tools in every project. Each tool addresses a specific user intent, described below.

    Before using any of the conversion or preparation tools, make sure your environment is correctly set up.

    You will need:

    • Python 3.14 or higher and pip (included with Python)

    • A local copy of the community repository

    In the /tools directory, run the following commands:

    This installs all required Python dependencies needed to run the tools.


    Tool: prepare_framework_v2.py

    This tool helps you create a clean and valid Excel file that already follows the v2 format rules.

    • Creating a framework from scratch

    • Avoiding mistakes in _meta and _content tabs

    • Standardizing framework creation across teams

    • Speeding up initial setup

    • Generates a fully structured Excel file

    • Creates required _meta and _content tabs

    • Adds metadata and columns directly inside Excel cells

    • Prevents common structural errors

    By default, the tool uses a configuration file named prepare_framework_v2_config.xlsx, which:

    • Is self-documented

    • Can be edited directly

    • Avoids complex command-line arguments

    You may also use a YAML configuration file:

    This is intended for advanced users who prefer YAML-driven configuration.


    Tool: convert_library_v2.py

    This is the most frequently used tool.

    It converts one or more Excel files into CISO Assistant-compatible YAML libraries.

    • Generating a YAML file from an Excel framework

    • Validating Excel consistency

    • Importing libraries into CISO Assistant

    • Updating an existing framework

    This will:

    • Validate the Excel file

    • Generate my_framework.yaml

    • Report clear errors if something is wrong

    In most situations, this command is sufficient.

    Verbose mode:

    • Explains what the tool is doing

    • Helps understand validation errors

    • Is very useful during early framework design

    This will:

    • Convert all .xlsx files in the folder

    • Generate one YAML file per Excel file

    Optional output directory:

    Compatibility modes exist only for legacy or special cases.

    • --compat 0 (default): Recommended for all new libraries

    • --compat 1: Used only to maintain libraries created before v1.9.20

    • --compat 2: Prevents URN cleaning (advanced / niche use cases)


    Tool: convert_v1_to_v2.py

    This tool helps migrate old v1 frameworks to the v2 format, as the v1 Excel format is deprecated.

    • Updating legacy frameworks

    • Preserving historical identifiers

    • Preparing old content for long-term maintenance

    This produces a new v2-compatible file.


    Mappings describe how requirements from two frameworks relate to each other.

    They are used for:

    • Compliance translation

    • Framework comparison

    • Cross-standard reporting

    1

    Generate a Mapping Excel file

    Tool: prepare_mapping_v2.py

    Usage:

    Generate mapping skeleton
    python prepare_mapping_v2.py source.yaml target.yaml

    This tool:

    • Reads both frameworks

    • Generates an Excel mapping file

    • Lists all source and target requirements

    You then manually define:

    • Mapping between the two frameworks

    • Relationship type (equal, subset, superset, intersect)

    • Optional rationale and strength

    2

    Once the Excel file is completed:

    The conversion tool will:

    • Validate the mapping

    • Generate a YAML mapping library


    Once your Excel file has been successfully converted into a YAML file, the final step is to import the library into CISO Assistant.

    This operation is performed directly from the CISO Assistant interface and does not require any additional tooling.

    Before importing your library, make sure that:

    • Your Excel file has been successfully converted using convert_library_v2.py

    • The resulting .yaml file contains no validation errors

    1

    Open CISO Assistant

    2

    In the left navigation menu, go to:

    Governance → Libraries

    3

    Click on the button

    4

    Select your generated .yaml file

    5

    If the file is valid:

    • The import will be accepted immediately

    • The library will be added to your available libraries

    Once the library is imported, go to Compliance → Frameworks.

    Your custom framework will appear in the list (you can search it in the search bar). It can now be used in audits if it's a framework, or used as mapping of it's a mapping

    If the import fails, CISO Assistant will display an explicit error message.

    Common causes include:

    • Missing mandatory fields in library_meta

    • Invalid or duplicated URNs

    • Inconsistent framework hierarchy

    • Invalid references to threats, controls, or IGs

    In most cases:

    • Fix the issue in Excel

    • Re-run convert_library_v2.py

    • Re-import the updated YAML file

    After importing a framework, it is strongly recommended to:

    • Create a test audit using the framework

    • Verify:

      • Hierarchy rendering

      • Assessable requirements

      • Questions and answers

      • Scores and implementation groups

    This validation step ensures that:

    • The framework behaves as expected

    • No structural or logical issues remain


    Always increment version in the library_meta sheet.

    If the version is unchanged, CISO Assistant will ignore the update.

    Never change:

    • urn_prefix

    • ref_id of existing nodes

    Changing URNs breaks:

    • Mappings

    • Historical assessments

    • References

    • Start small, then extend

    • Test with minimal frameworks

    • Avoid deep hierarchies

    • Use Implementation Groups early (if necessary)

    • Keep Excel files clean and ordered


    • Forgetting to increment the version

    • Using v1 format instead of v2 format

    • Changing ref_id on existing nodes

    • Overusing advanced fields too early

    • Creating overly deep hierarchies


    For advanced or low-level options, always refer to the dedicated README on GitHub.


    NOTE: This section is still under reworking. For complementary informations, please refer to the dedicated README on GitHub.

    1. What is a Library in CISO Assistant?

    Install Python requirements
    pip install -r requirements.txt
    Generate skeleton
    python3 prepare_framework_v2.py
    YAML-driven configuration
    python3 prepare_framework_v2.py -i prepare_framework_v2_config.yaml
    Convert a framework
    python3 convert_library_v2.py my_framework.xlsx
    Verbose mode
    python3 convert_library_v2.py my_framework.xlsx --verbose
    Bulk conversion
    python3 convert_library_v2.py path/to/folder --bulk
    Bulk conversion with output dir
    python3 convert_library_v2.py path/to/folder --bulk --output-dir out_folder
    Migrate v1 to v2
    python3 convert_v1_to_v2.py old_framework.xlsx

    In practice, Risk matrices and Mappings between frameworks have their own library for practical reasons.

    2. Key Concepts

    2.1 Frameworks and Requirements

    2.2 Assessable vs Non-assessable Nodes

    2.3 Hierarchy and Depth

    2.4 URNs and ref_id

    Changing URNs breaks mappings and historical data.

    2.5 Implementation Groups (IG)

    2.6 Scores and Answers

    2.7 Mappings

    3. Recommended Workflow

    4. Creating a Framework using Excel (v2 format)

    This section doesn't explain all the object types yet, neither the type of values to put in the columns. In the meantime, you can refer to the for more up-to-date information.

    4.1 Why Excel?

    4.2 Excel file structure (v2)

    4.3 Example Framework (Strongly Recommended)

    Why this example matters

    Recommended way to use the example

    When to come back to the example framework

    Before opening a support ticket related to framework creation, consulting the example framework may sometimes solve your problem.

    4.4 The library_meta Tab

    Versioning is critical. If the custom framework is already imported into CISO Assistant and the version number has not been incremented, CISO Assistant will not suggest an update.

    4.5 Framework definition Tabs

    Order matters: the hierarchy is inferred from row order + depth.

    Requirement-level scoring overrides

    4.6 Threats

    Structure

    A library may contain only threats, without any framework. This is a common pattern when building shared threat catalogs reused across multiple frameworks.

    4.7 Reference Controls

    Structure

    Reference controls can be defined independently of any framework and packaged in their own library, exactly like threats.

    4.8 Risk Matrices

    Typical usage

    Structure

    Important Note: Use Existing Examples

    5. Using the Tools

    Prerequisites

    This setup only needs to be done once.

    5.1 Creating a Framework Skeleton (Recommended Starting Point)

    Typical use cases

    What this tool does

    Recommended usage (simple)

    Advanced usage

    After running this tool, the library_meta tab and the framework _meta tab usually do not need to be modified again, except if you want to:

    • Add translations

    5.2 Converting an Excel file to a Library (Main conversion step)

    Typical use cases

    Basic usage (recommended for most users)

    Verbose mode (recommended during troubleshooting)

    Bulk mode (multiple frameworks)

    Compatibility modes (advanced users)

    If you are unsure, do not use compatibility modes.

    5.3 Migrating Legacy Frameworks (v1 → v2)

    Typical use cases

    Usage

    If you use convert_library_v2.py on an Excel file converted into v2, the YAML structure may be completely different from your original YAML file and break your audits if you import it into CISO Assistant!

    You can use the convert_v1_to_v2.py script if you created your framework using the v1 format and provided that you HAVE NOT YET imported your framework into CISO Assistant.

    You can also use it if you notice that the URNs in the YAML file created with the v2 version of your framework are identical to the URNs in the YAML file of the v1 version of your framework. You can also try using the script's compatibility modes to recover the old structure.

    The result must be reviewed manually. Migration fixes Excel structure, not design quality. In some cases, you should still simplify and clean legacy content afterward.

    6. Creating Mappings between Frameworks

    7. Importing a Custom Library into CISO Assistant

    7.1 Prerequisites

    7.2 Importing the Library

    7.3 After import: Where to find your Framework

    7.4 Common import errors

    7.5 Testing your Framework after import

    8. Updating and Maintaining Libraries

    8.1 Version Management

    8.2 URN Stability

    8.3 Best Practices

    9. Common Pitfalls

    10. Final Notes

    (Old) Videos

    IMPORTANT NOTICE: The following sections contain information that is no longer up to date, but some parts are still useful today. Please consult them with caution.

    Testing your custom framework

    Full guide (French)

    Automatically create reverse mappings

    Add advanced objects (scores, answers, IGs)
    Convert mapping to YAML
    python convert_library_v2.py mapping.xlsx

    Convert Excel to YAML

    Import the library into CISO Assistant

    Maintain and update the library

    Convert the Mapping to YAML

    Confirm the upload

    dedicated README on GitHub
    Purple button with a white file in it and a "+" sign

    CIS Controls / Cloud Controls Matrix (CCM)

    Importing CIS Controls or CSA CCM

    CIS Controls and the Cloud Security Alliance's Cloud Controls Matrix (CCM) ship as Excel spreadsheets that CISO Assistant can convert and load directly — no command-line preparation required.

    CIS and CSA have restrictive licence terms on their content, so the spreadsheets are not bundled with CISO Assistant. You have to download the official spreadsheet from CIS or CSA yourself and then upload it to the platform.

    Direct import

    1. Download the CIS Controls or CCM spreadsheet from the relevant authority's website.

    2. In CISO Assistant, go to Libraries and click Add your own library.

    3. Select the downloaded spreadsheet and upload it. CISO Assistant converts it to the platform's library format on the fly.

    4. Once the conversion finishes, load the new library like any other.

    If you need to adjust the conversion (custom packager name, modified spreadsheet, additional mappings), the conversion logic is available as standalone Python tools in the repository:

    The standard flow is to copy the spreadsheet into the tools folder and run convert_cis.sh (Linux/Mac) or convert_cis.bat (Windows). For finer control, run tools/excel/cis/prep_cis.py first to set a custom packager string, then pass the prepared spreadsheet to convert_library_v2.py. The output YAML can be uploaded as a custom library and loaded.

    See the and the for parameters and edge cases.

    Advanced: customise the conversion

    CIS Controls converter
    CCM converter
    dedicated README for CIS Controls
    dedicated README for CCM
    Decoupling concept — full screen is recommended for a better experience.