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...
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...
This is CISO Assistant documentation. You'll find advice on how to get started, and details on our vision of risk and compliance assessment.








Small tutorial to learn how to create your first perimeter and be prepared for risk and compliance assessment
Small tutorial to learn how to create your first compliance assessment
Main concepts of the mapping feature


CISO Assistant can send you email notifications to keep you informed about deadlines, assignments, and status changes.
Through implementation groups
Guidelines on data import format
authors and reviewers are matched by email address
Establishing a security posture in flashcards mode

Productivity tips series
How to delete/remove a loaded library


























Configure Okta as an Identity Provider for CISO Assistant











Configure Google Workspace as an Identity Provider for CISO Assistant
























Configure Keycloak as an Identity Provider for CISO Assistant



























For fine-grained permissions management - PRO feature
Minor nonconformity, Major nonconformity, etc.
./docker-compose.sh./docker-compose-build.sh

git pull
docker compose down
sudo chown -R 1001:1001 ./dbdocker compose up -dgit pull
docker compose down
sudo chown -R 1001:1001 ./db
docker compose -f docker-compose-build.yml up -d ./docker-compose.sh./docker-compose-build.shdocker compose downimage: ghcr.io/intuitem/ciso-assistant-community/frontend:v3.15.2
# replace with (for example)
image: ghcr.io/intuitem/ciso-assistant-community/frontend:v3.16docker compose up -ddocker exec -it backend id uid=1001 gid=1001 groups=1001#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.12-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./docker-compose.sh



#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.12-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.shcd config
# stop and remove containers
docker compose -f docker-compose-custom.yml rm -fs
# delete the db and proxy config
git clean -fdx .
Deep dive into CISO Asisstant IAM model
How to add custom certificates for your remote installation

caddy_data directory, as it is already mounted by default in the volumes, and specify the path to the files: caddy:
container_name: caddy
image: caddy:2.10.0
...
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'# .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.comservices:
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
- |
poetry 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.10.0
restart: unless-stopped
ports:
- 8443:8443
command:
- caddy
- reverse-proxy
- --from
- https://localhost:8443
- --to
- frontend:3000
volumes:
- ./db:/datax-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"chmod 600 .envdocker-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 -ddocker compose --env-file .env.prod -f docker-compose.yml -f docker-compose.prod.yml up -dcaddy:
container_name: caddy
image: caddy:2.10.0
...
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 logs backenddocker compose exec backend poetry run python manage.py migratedocker compose up -ddocker compose exec backend poetry run python manage.py createsuperuser# frontend/Dockerfile
ENV BODY_SIZE_LIMIT=20000000 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:9000CISO Assistant uses SMTP to send transactional emails (password reset, superuser creation, notifications). This page covers configuration and the TLS specifics introduced in 3.16.
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)update-ca-certificates recipe (pre-3.16)/etc/ssl/certs/ca-certificates.crt[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:ropython -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>'./update-ciso-assistant.shdocker rmi ghcr.io/intuitem/ciso-assistant-community/backend:latest ghcr.io/intuitem/ciso-assistant-community/frontend:latest 2> /dev/nullgetting the incremental updates of your framework, matrix or catalog

helm install ciso-assistant-release oci://ghcr.io/intuitem/helm-charts/ce/ciso-assistant -f custom.yamlSwitch the UI language
library_meta Tab


python convert_library_v2.py example_framework.xlsxpip install -r requirements.txtpython3 prepare_framework_v2.pypython3 prepare_framework_v2.py -i prepare_framework_v2_config.yamlpython3 convert_library_v2.py my_framework.xlsxpython3 convert_library_v2.py my_framework.xlsx --verbosepython3 convert_library_v2.py path/to/folder --bulkpython3 convert_library_v2.py path/to/folder --bulk --output-dir out_folderpython3 convert_v1_to_v2.py old_framework.xlsxpython prepare_mapping_v2.py source.yaml target.yaml

How to contribute to CISO Assistant internationalization
How to submit a framework, matrix or catalog to the community repository
Personal Access Token to interact with the API














export DJANGO_DEBUG=Truepython3 manage.py runservercurl --request GET \
--url http://127.0.0.1:8000/api/assets/ \
--header 'authorization: Token a6a120f....'
Integrate CISO Assistant with third-party providers






CRQ quick start
This guide explains how to connect your AI assistant to CISO Assistant using the Model Context Protocol (MCP). Once set up, you'll be able to ask your AI to create risk assessments, manage compliance



git clone https://github.com/intuitem/ciso-assistant-community.git
cd ciso-assistant-community/cli# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"cd /path/to/ciso-assistant-community/clicp .mcp.env.example .mcp.env# Your Personal Access Token from Step 1
TOKEN=your-token-here
# Your CISO Assistant API URL
API_URL=http://localhost:8000/api
# Set to "true" if using HTTPS with a valid certificate
# Set to "false" for local development or self-signed certs
VERIFY_CERTIFICATE=false{
"mcpServers": {
"ciso-assistant": {
"command": "uv",
"args": [
"--directory",
"/path/to/ciso-assistant-community/cli",
"run",
"ca_mcp.py"
]
}
}
}{
"mcpServers": {
"ciso-assistant": {
"command": "uv",
"args": [
"--directory",
"/Users/yourname/ciso-assistant-community/cli",
"run",
"ca_mcp.py"
]
}
}
}{
"mcpServers": {
"ciso-assistant": {
"command": "uv",
"args": [
"--directory",
"C:\\Users\\yourname\\ciso-assistant-community\\cli",
"run",
"ca_mcp.py"
]
}
}
}{
"mcpServers": {
"ciso-assistant": {
"command": "uv",
"args": [
"--directory",
"/home/yourname/ciso-assistant-community/cli",
"run",
"ca_mcp.py"
]
}
}
}{
"mcpServers": {
"ciso-assistant": {
"command": "uv",
"args": [
"--directory",
"/path/to/ciso-assistant-community/cli",
"run",
"ca_mcp.py"
],
"env": {
"TOKEN": "your-token-here",
"API_URL": "http://localhost:8000/api",
"VERIFY_CERTIFICATE": "false"
}
}
}
}{
"mcpServers": {
"ciso-assistant": {
"command": "uv",
"args": [
"--directory",
"/path/to/ciso-assistant-community/cli",
"run",
"ca_mcp.py"
]
}
}
}{
"mcpServers": {
"ciso-assistant": {
"command": "/Users/yourname/.cargo/bin/uv",
"args": [
"--directory",
"/path/to/ciso-assistant-community/cli",
"run",
"ca_mcp.py"
]
}
}
}which uv # macOS/Linux
where uv # Windows{
"mcpServers": {
"ciso-assistant": {
"command": "/path/to/uv",
"args": [
"--directory",
"/path/to/ciso-assistant-community/cli",
"run",
"ca_mcp.py"
],
"env": {
"TOKEN": "your-personal-access-token",
"VERIFY_CERTIFICATE": "false",
"API_URL": "http://localhost:8000/api"
}
}
}
}{
"mcpServers": {
"ciso-assistant": {
"command": "/Users/yourname/.cargo/bin/uv",
"args": [
"--directory",
"/Users/yourname/ciso-assistant-community/cli",
"run",
"ca_mcp.py"
],
"env": {
"TOKEN": "your-personal-access-token",
"VERIFY_CERTIFICATE": "false",
"API_URL": "http://localhost:8000/api"
}
}
}
}cd /path/to/ciso-assistant-community/cli
uv run ca_mcp.pywhsec_... secret.{
"type": "appliedcontrol.created",
"timestamp": "2025-11-13T14:35:06Z",
"data": {
"id": "53709ff2-ade7-4172-9dee-daa580cbba5b"
}
}{
"type": "appliedcontrol.created",
"timestamp": "2025-11-13T14:35:06Z",
"data": {
"id": "53709ff2-ade7-4172-9dee-daa580cbba5b",
"name": "MFA Enforcement",
"status": "active",
"owner": "john.doe@example.com",
...
}
}import hmac
import hashlib
import base64
import time
def verify_webhook(request, secret):
# 1. Get Headers
msg_id = request.headers.get("webhook-id")
msg_timestamp = request.headers.get("webhook-timestamp")
signature_header = request.headers.get("webhook-signature")
if not (msg_id and msg_timestamp and signature_header):
raise ValueError("Missing webhook headers")
# 2. Verify Timestamp (Replay Protection)
# Reject if older than 5 minutes
now = int(time.time())
if now - int(msg_timestamp) > 300:
raise ValueError("Message timestamp too old")
# 3. Construct Signed Content
# IMPORTANT: Use the raw bytes of the request body
body = request.body.decode("utf-8")
to_sign = f"{msg_id}.{msg_timestamp}.{body}"
# 4. Calculate Expected Signature
# The header format is "v1,signature_hash"
# We only support v1 (HMAC-SHA256) for now
secret_bytes = secret.encode("utf-8")
to_sign_bytes = to_sign.encode("utf-8")
digest = hmac.new(secret_bytes, to_sign_bytes, hashlib.sha256).digest()
calculated_signature = base64.b64encode(digest).decode()
# 5. Compare Securely
# Extract the hash from "v1,..."
provided_signature = signature_header.split(",")[1]
if not hmac.compare_digest(calculated_signature, provided_signature):
raise ValueError("Invalid signature")
return True


Small tutorial to learn how to create your first compliance assessment






































































































































































ServiceNow Integration Guide
Control).(function executeRule(current, previous) {
try {
// Initialize REST Message ('API Name', 'Method Name')
// REPLACE 'CISO_Assistant_Sync' with your actual API Name if different!
var r = new sn_ws.RESTMessageV2('CISO_Assistant_Sync', 'POST_Event');
// Determine Event Type
var eventType = 'sn_update';
if (current.operation() == 'insert') {
eventType = 'sn_create';
} else if (current.operation() == 'delete') {
eventType = 'sn_delete';
}
// Build Payload (Mapping raw database values)
var payload = {
"event": eventType,
"sys_id": current.getValue("sys_id"),
"number": current.getValue("number"),
"short_description": current.getValue("short_description"),
"description": current.getValue("description"),
"state": current.getValue("state"),
"priority": current.getValue("priority"),
"due_date": current.getValue("due_date"),
"sys_updated_on": current.getValue("sys_updated_on")
};
// Send Request
r.setRequestBody(JSON.stringify(payload));
var response = r.execute();
// Log Errors
var httpStatus = response.getStatusCode();
if (httpStatus < 200 || httpStatus >= 300) {
gs.error("CISO Sync Failed: " + httpStatus + " " + response.getBody());
}
} catch (ex) {
gs.error("CISO Sync Error: " + ex.message);
}
})(current, previous);




















































