Skip to content

kaveo · Get started

Configuration

Every kaveo setting is an environment variable. Reference for database, scanning, AI providers, feature flags, authentication and integrations.

On this page

How configuration works#

kaveo follows the 12-factor model: every setting is an environment variable. The api and the worker read them at startup, and most names carry the prefix KAVEO_. A few are read without it: DATABASE_URL, MIGRATE_DATABASE_URL and MIGRATIONS_DIR, the standard AWS_* SDK variables, and the hosted AI keys, which are also accepted under their usual names (ANTHROPIC_API_KEY, OPENAI_API_KEY, and XAI_API_KEY or GROK_API_KEY).

Detector thresholds and KAVEO_KEV_CATALOG_PATH are read once, when the detector code loads. A non-integer threshold falls back to its default, and an unknown KAVEO_DETECT_MIN_SEVERITY turns the severity floor off, so a typo never stops a scan. Suppression is stamped at scan time: a change applies to new scans, and past scans keep their labels.

The images do not contain a .env file. A value reaches kaveo only when Docker Compose passes it into the container.

How settings reach the containers#

An override file can pull each value from .env, so secrets stay out of the override itself:

yaml
# compose.override.yml
x-kaveo-extra: &kaveo-extra
  KAVEO_REMEDIATION_EXECUTOR: ${KAVEO_REMEDIATION_EXECUTOR:-offline}
  KAVEO_SLACK_WEBHOOK_URL: ${KAVEO_SLACK_WEBHOOK_URL:-}

services:
  api:
    environment:
      <<: *kaveo-extra
  worker:
    environment:
      <<: *kaveo-extra

An empty value is fine for a text setting such as a URL or token. For a number, boolean or fixed-choice setting, give the ${NAME:-default} form a real default: an empty value for those stops the api and worker at startup.

Apply both files together:

bash
docker compose --env-file .env -f infra/docker-compose.yml -f compose.override.yml up -d

Pass --env-file explicitly. Recent Compose versions look for .env next to the first compose file, in infra/, rather than in the directory you run the command from. The Make targets accept the same command through their COMPOSE variable:

bash
make up COMPOSE="docker compose --env-file .env -f infra/docker-compose.yml -f compose.override.yml"

These settings need the override:

  • Logging, telemetry and capacity: KAVEO_LOG_LEVEL, KAVEO_LOG_FORMAT, KAVEO_TELEMETRY, KAVEO_DB_POOL_MIN, KAVEO_DB_POOL_MAX, KAVEO_SCAN_MAX_CONCURRENCY, KAVEO_ATTACK_PATH_MAX_ROWS, KAVEO_MAX_SCAN_NODES, KAVEO_RATE_LIMIT_PER_MINUTE, KAVEO_WORKER_LEASE_SECONDS, KAVEO_BACKUP_DIR
  • Sessions and identity: KAVEO_SESSION_TTL_HOURS, KAVEO_OIDC_*, KAVEO_SAML_*, KAVEO_MFA_SECRET_KEY, KAVEO_MFA_ISSUER, KAVEO_SCIM_TOKEN
  • Detection: KAVEO_DETECT_*, KAVEO_KEV_CATALOG_PATH, KAVEO_AWS_DEFAULT_REGION
  • AI: KAVEO_XAI_API_KEY, KAVEO_GROK_BASE_URL
  • Remediation and integrations: KAVEO_REMEDIATION_EXECUTOR, KAVEO_SLACK_WEBHOOK_URL, KAVEO_GITHUB_REPO, KAVEO_GITHUB_TOKEN, KAVEO_JIRA_*, KAVEO_MAILER, KAVEO_SMTP_*, KAVEO_SES_REGION, KAVEO_MAIL_FROM, KAVEO_PUBLIC_WEB_URL
  • Other clouds: the variable named by each Azure, GCP, Kubernetes or GitHub account's env:NAME credential reference. See Connect cloud accounts.

Required before first start#

Compose refuses to start until POSTGRES_PASSWORD, POSTGRES_APP_PASSWORD and KAVEO_BOOTSTRAP_PASSWORD are set. Generate each one separately:

bash
openssl rand -hex 24

Set KAVEO_SESSION_COOKIE_SECURE explicitly as well: true when Caddy serves TLS, false only for a plain-HTTP bring-up. Compose passes an empty value when it is unset, and the api and worker do not start with an empty value. The .env.example file leaves it empty, so fill it in when you copy that file.

Variable reference#

"Set by compose" means the stock compose file fills the value in. Rows marked "Needs an override" follow the rule above.

Core and database#

VariableDefaultPurpose
DATABASE_URLset by composeApp connection string. Plain postgresql:// scheme. Compose logs in as the non-superuser application role, so row-level security applies.
MIGRATE_DATABASE_URLset by composeSuperuser connection, used only by the migration runner for DDL. Empty falls back to DATABASE_URL.
MIGRATIONS_DIR/app/db/migrations in composeWhere the migration runner reads SQL files.
POSTGRES_PASSWORDrequiredPostgres superuser password.
POSTGRES_APP_PASSWORDrequiredPassword for the non-superuser application role, created on first database init.
KAVEO_ENVIRONMENTprod in compose, dev in codedev, prod or test. When KAVEO_SESSION_COOKIE_SECURE is not set, anything but dev sets Secure on the session cookie.
KAVEO_SESSION_COOKIE_SECURErequired in composetrue or false. Overrides the cookie Secure flag. Set false only for a plain-HTTP bring-up.
KAVEO_LOG_LEVELINFOLog level. Compose passes LOG_LEVEL, which kaveo does not read. Needs an override.
KAVEO_LOG_FORMATtexttext or json. Needs an override.
KAVEO_SITE_ADDRESS:80Caddy site address. A real hostname turns on automatic TLS.
KAVEO_HTTP_PORT / KAVEO_HTTPS_PORT80 / 443Host ports Caddy publishes.
KAVEO_IMAGE_TAGlatestTag for the web, api and worker images.
KAVEO_DB_POOL_MIN / KAVEO_DB_POOL_MAX1 / 10Connection pool bounds for one api replica. Needs an override.
KAVEO_SCAN_MAX_CONCURRENCY8Width of the scan fan-out across accounts, regions and collectors. Your AWS API rate limit is the ceiling. 1 scans serially. Needs an override.
KAVEO_ATTACK_PATH_MAX_ROWS50000Row cap on attack-path enumeration. Truncation is logged. Needs an override.
KAVEO_MAX_SCAN_NODES0Cap on graph rows one scan loads for the report. 0 means no cap. Needs an override.
KAVEO_RATE_LIMIT_PER_MINUTE0Requests per rolling minute per client address, per api replica. Over budget returns 429. 0 is off. The address is the direct peer, which behind the stock Caddy proxy is Caddy itself, so size the budget for all traffic through it. Needs an override.
KAVEO_WORKER_LEASE_SECONDS900A scan running longer than this is presumed dead and re-queued. Keep it above your longest scan. Needs an override.
KAVEO_BACKUP_DIR/var/lib/kaveo/backupsWhere pg_dump archives are written. Compose mounts a named volume at this path. Needs an override to change.
KAVEO_BACKUP_BEFORE_MIGRATEtrue in compose, false in codeTake a pg_dump snapshot before applying pending migrations.

Bootstrap and access#

VariableDefaultPurpose
KAVEO_BOOTSTRAP_EMAILplaceholderEmail of the owner account created on first start. Set an address you control.
KAVEO_BOOTSTRAP_PASSWORDrequiredOwner password. Used only while the users table is empty, so changing it later does not change the existing owner.
KAVEO_SESSION_TTL_HOURS168Session lifetime. Needs an override.
KAVEO_SUPERADMIN_EMAILSunsetComma-separated emails marked as platform superadmins at boot. They can act in any org with the X-Kaveo-Org header.
KAVEO_APPROVAL_REQUIREDtrueNew sign-up and SSO accounts stay pending until a superadmin approves them.
KAVEO_SIGNUP_ENABLEDfalseSelf-serve sign-up. While off, SSO sign-in works only for emails that already have an account.
KAVEO_SHARE_TTL_DAYS30Lifetime of a read-only report link.
KAVEO_PUBLIC_ORIGINhttp://localhostBrowser-facing origin. Google, Microsoft and GitHub sign-in callbacks are built from it.

Scanning and detection#

VariableDefaultPurpose
KAVEO_SCAN_MODEautoauto tries the role and falls back to the labeled synthetic dataset if that fails. aws collects for real only, and a failed assume fails the scan. synthetic never calls AWS.
AWS_REGIONus-east-1Region for the AWS SDK. Compose also sets AWS_DEFAULT_REGION from it.
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKENemptyBase credentials kaveo assumes the read-only role from. Leave empty on EC2 or ECS to use the instance or task role.
KAVEO_AWS_DEFAULT_REGIONus-east-1Region kaveo starts a session in before it discovers enabled regions. Needs an override.
KAVEO_PRINCIPAL_ARNunsetkaveo's own principal ARN, which you pin in the read-only role's trust policy. Pre-fills the onboarding wizard.
KAVEO_CFN_TEMPLATE_URLunsetYour hosted copy of the read-only role CloudFormation template. Unset hides the quick-create button.
KAVEO_DETECT_SUPPRESS_RULESunsetComma-separated rule ids to label as suppressed. Suppressed findings are still stored and are hidden by default with a visible count. Needs an override.
KAVEO_DETECT_MIN_SEVERITYunsetinfo, low, medium, high or critical. Findings below it are suppressed. Needs an override.
KAVEO_DETECT_ROTATE_AFTER_DAYS90Key age for identity.access_key_rotation. Needs an override.
KAVEO_DETECT_DORMANT_AFTER_DAYS90Unused-key age for identity.dormant_access_keys. Needs an override.
KAVEO_DETECT_DORMANT_USER_AFTER_DAYS90Inactivity for identity.dormant_users. Needs an override.
KAVEO_DETECT_ROOT_USAGE_WINDOW_DAYS90Look-back window for identity.root_recent_usage. Needs an override.
KAVEO_DETECT_MIN_PASSWORD_LENGTH14Minimum length for identity.weak_password_policy. Needs an override.
KAVEO_DETECT_MIN_REUSE_PREVENTION24Password reuse prevention for identity.weak_password_policy. Needs an override.
KAVEO_DETECT_SECRET_UNUSED_AFTER_DAYS90Unused-secret age for secrets.secretsmanager_unused. Needs an override.
KAVEO_REPORT_RELEVANCE_MODEreal_riskreal_risk, strict or all. Shapes the Risk Report only; /v1/findings and compliance still return every finding.
KAVEO_REPORT_HYGIENE_RULESunsetComma-separated rule ids treated as hygiene. Unset uses the built-in set.
KAVEO_KEV_CATALOG_PATHunsetPath inside the container to CISA's official known_exploited_vulnerabilities.json, downloaded out of band. kaveo reads the local file only. A readable file extends the bundled subset; unset or unreadable uses the bundled subset alone. Needs an override and a volume mount.

AI#

VariableDefaultPurpose
KAVEO_AI_PROVIDERoffline in compose, auto in codeoffline, auto, anthropic, openai, grok, bedrock or local. auto picks one hosted provider whose key is set (anthropic, openai or grok) by kaveo's built-in cost ranking and uses it for every tier. With no hosted key set, auto resolves to offline.
KAVEO_MODEL_FASTclaude-haiku-4-5Fast tier. On bedrock and local, set all three tiers to model ids your endpoint serves. On openai and grok, the defaults give way to kaveo's catalog model for that provider; set your own ids to override them, for example when KAVEO_OPENAI_BASE_URL points at another OpenAI-compatible API.
KAVEO_MODEL_MAINclaude-sonnet-5Main tier.
KAVEO_MODEL_DEEPclaude-opus-4-8Deep tier.
KAVEO_ANTHROPIC_API_KEYunsetAlso read as ANTHROPIC_API_KEY. Compose passes only ANTHROPIC_API_KEY, so use that name in .env.
KAVEO_OPENAI_API_KEYunsetAlso read as OPENAI_API_KEY. Compose passes only KAVEO_OPENAI_API_KEY, so use that name in .env.
KAVEO_XAI_API_KEYunsetAlso read as XAI_API_KEY or GROK_API_KEY. Needs an override.
KAVEO_OPENAI_BASE_URLhttps://api.openai.com/v1Any hosted OpenAI-compatible API.
KAVEO_GROK_BASE_URLhttps://api.x.ai/v1xAI endpoint. Needs an override.
KAVEO_BEDROCK_REGIONus-east-1Bedrock region. Bedrock uses the AWS credential chain.
KAVEO_LOCAL_BASE_URLhttp://model:8000/v1 in composeSelf-hosted OpenAI-compatible endpoint, such as the optional model service.
KAVEO_LOCAL_API_KEYunsetBearer token, only if your self-hosted endpoint requires one.
KAVEO_LOCAL_TIMEOUT_SECONDS120Request timeout for local, openai and grok.

Feature flags#

Agent investigation, the patrol, the MCP server and the AWS remediation executor are off until you turn them on. The last three rows cover deployment mode, telemetry and billing.

VariableDefaultPurpose
KAVEO_AGENT_INVESTIGATION_ENABLEDfalseSpecialist agents search a scan's graph for attack paths. When kaveo can assume the account's read-only role, an iam:SimulatePrincipalPolicy check validates each hop; otherwise the chains are stored unvalidated. A run makes many model calls, so it is useful only with a real AI provider.
KAVEO_AGENT_MAX_ITERATIONS12Tool-use loop cap per specialist agent.
KAVEO_AGENT_LEASE_SECONDS1800An agent run older than this is presumed dead and re-queued.
KAVEO_PATROL_ENABLEDfalseAfter each successful scan, drafts fixes for the top new real-risk findings into the approval queue as proposed. It never applies them.
KAVEO_PATROL_MAX_PROPOSALS3Most fixes the patrol drafts per scan.
KAVEO_MCP_ENABLEDfalseTurns on the read-only MCP server at POST /mcp.
KAVEO_REMEDIATION_EXECUTORofflineoffline is a dry run. aws assumes the account's separate write role, only for an approved fix. Needs an override.
KAVEO_DEPLOYMENT_MODEon_premKeep the default for a self-hosted install. It keeps self-serve sign-up, billing and telemetry egress off.
KAVEO_TELEMETRYlocallocal writes usage rows to your database only. off disables it. Needs an override to change.
KAVEO_BILLINGoffKeep off for a self-hosted install.

SSO and identity#

VariableDefaultPurpose
KAVEO_OIDC_ENABLEDfalseOIDC sign-in. Local email and password sign-in keeps working. Needs an override, like every KAVEO_OIDC_* setting.
KAVEO_OIDC_ISSUER / KAVEO_OIDC_CLIENT_ID / KAVEO_OIDC_CLIENT_SECRETunsetYour IdP's issuer and client.
KAVEO_OIDC_REDIRECT_URIhttp://localhost/v1/auth/oidc/callbackCallback registered with the IdP.
KAVEO_OIDC_TOKEN_ENDPOINT / KAVEO_OIDC_JWKS_URIderived from the issuerSet these when your IdP does not serve /token and /.well-known/jwks.json under the issuer.
KAVEO_OIDC_AUDIENCEthe client idExpected aud claim on the ID token.
KAVEO_SSO_GOOGLE_CLIENT_ID / _CLIENT_SECRETunsetGoogle sign-in. A button appears only when both are set.
KAVEO_SSO_MICROSOFT_CLIENT_ID / _CLIENT_SECRETunsetMicrosoft sign-in.
KAVEO_SSO_MICROSOFT_TENANTcommoncommon, organizations, consumers or a tenant GUID.
KAVEO_SSO_MICROSOFT_ASSUME_VERIFIEDfalseBy default kaveo requires the email and xms_edov optional claims. Set true only on a single-tenant install whose tenant you control.
KAVEO_SSO_GITHUB_CLIENT_ID / _CLIENT_SECRETunsetGitHub sign-in.
KAVEO_SAML_IDP_SSO_URL / _IDP_CERT / _SP_ENTITY_ID / _SP_ACS_URLunsetSP-initiated SAML. It turns on when the IdP SSO URL, IdP certificate and ACS URL are all set. The SP entity id defaults to the ACS URL. The api's ACS route is /v1/auth/saml/acs. Needs an override.
KAVEO_MFA_SECRET_KEYunsetEncrypts TOTP secrets at rest. Required for MFA enrollment. Needs an override.
KAVEO_MFA_ISSUERkaveoIssuer name shown in authenticator apps. Needs an override.
KAVEO_SCIM_TOKENunsetStatic bearer your IdP presents to /scim/v2. Unset means SCIM needs an admin session. The stock Caddyfile sends only /v1/* and /mcp to the api, so add a /scim/v2/* route before your IdP can reach it. Needs an override.

Social sign-in callbacks follow the pattern {KAVEO_PUBLIC_ORIGIN}/v1/auth/{provider}/callback, where the provider is google, microsoft or github.

Integrations#

Every setting in this table needs an override.

VariableDefaultPurpose
KAVEO_SLACK_WEBHOOK_URLunsetIncoming webhook for patrol briefs and regression alerts. Treat it as a secret.
KAVEO_GITHUB_REPOunsetowner/name of the repository that receives remediation pull requests.
KAVEO_GITHUB_TOKENunsetNeeds contents:write and pull_requests:write on that one repository. Use a fine-grained or App token.
KAVEO_JIRA_BASE_URL / KAVEO_JIRA_EMAIL / KAVEO_JIRA_API_TOKEN / KAVEO_JIRA_PROJECT_KEYunsetJira Cloud site, account email, Atlassian API token and project key. Jira stays off unless all four are set.
KAVEO_MAILERconsoleconsole logs messages and sends nothing. smtp or ses sends mail.
KAVEO_SMTP_HOSTunsetSMTP server. Unset means SMTP sends nothing.
KAVEO_SMTP_PORT587SMTP port.
KAVEO_SMTP_USERNAME / KAVEO_SMTP_PASSWORDunsetSMTP credentials.
KAVEO_SMTP_USE_TLStrueImplicit TLS on port 465, STARTTLS on any other port. false sends over a plain connection.
KAVEO_SES_REGIONus-east-1SES region.
KAVEO_MAIL_FROMunsetFrom address for both transports. Required for ses.
KAVEO_PUBLIC_WEB_URLunsetConsole origin used for report links in email. Unset sends the PDF without a link.

Per-organization alert channels are managed in the console under Settings → Alerts, not through the environment. See MCP server and integrations.

Production checklist#

Set these before kaveo is reachable by anyone else:

  • Serve over TLS. Set KAVEO_SITE_ADDRESS to your hostname, KAVEO_PUBLIC_ORIGIN to the matching https:// origin, KAVEO_SESSION_COOKIE_SECURE=true, and keep KAVEO_ENVIRONMENT=prod.
  • Use unique random values for the three required secrets, and keep .env out of source control.
  • Set KAVEO_BOOTSTRAP_EMAIL to an address you control before the first start.
  • Keep KAVEO_APPROVAL_REQUIRED=true and KAVEO_SIGNUP_ENABLED=false unless you intend to open sign-up.
  • Use KAVEO_SCAN_MODE=aws for real accounts, so a failed role assumption fails the scan instead of falling back to synthetic data.
  • Set a long random KAVEO_MFA_SECRET_KEY before anyone enrolls in MFA.
  • Keep KAVEO_REMEDIATION_EXECUTOR=offline until the separate write role is deployed and reviewed. See Remediation and autonomous patrol.
  • Keep tokens and webhook URLs in the environment only, and scope KAVEO_GITHUB_TOKEN to the one repository it writes to.