Skip to content

Vectasec · Get started

Configuration

Every environment variable the Vectasec engine, console and collector read, with defaults, and which ones you must set before exposing a service.

On this page

How configuration is loaded#

You configure Vectasec through environment variables. The engine (API and worker), the console and the collector each read their own set, and the connections you add carry their own settings.

The engine loads a .env file only from its two entry points: the vectasec CLI, which includes vectasec worker, and the engine API's bundled entry point. It uses the nearest .env at or above the working directory, and a variable already set in the environment always wins. Start the API with its bundled entry point rather than bare uvicorn. That entry point reads the file and applies ENGINE_HOST and ENGINE_PORT, and bare uvicorn does neither. Write plain NAME=value lines: the loader ignores lines with an export prefix and keeps quotes and trailing comments as part of the value.

The collector never reads .env. Its settings come only from its own environment and the files you point it at, so a stray file cannot change its TLS verification.

A minimal engine environment for a real deployment looks like this. Replace every placeholder and supply the secrets from your secret store.

bash
DATABASE_URL=postgresql://USER:PASSWORD@HOST:5432/postgres
SUPABASE_URL=https://YOUR_PROJECT_REF.supabase.co
VECTASEC_ENGINE_TOKEN=REPLACE_WITH_A_LONG_RANDOM_SECRET
VECTASEC_ENGINE_TOKEN_TENANT=YOUR_TENANT_UUID
VECTASEC_COLLECTOR_TOKEN_SECRET=REPLACE_WITH_A_SEPARATE_RANDOM_SECRET

Engine settings#

Core#

VariableDefaultPurpose
DATABASE_URLunsetRequired. Postgres DSN for the control plane. The engine and worker connect with a role that bypasses RLS, so treat this value as a root credential.
SUPABASE_URLunsetRequired to verify user JWTs. Signing keys are fetched from <SUPABASE_URL>/auth/v1/.well-known/jwks.json.
SUPABASE_SERVICE_ROLE_KEYunsetOptional. Lets the engine invite new members and delete accounts through the Supabase Auth admin API. Never give it to the console.
ENGINE_HOST127.0.0.1Bind address. Use 0.0.0.0 only inside a container or on a private network.
ENGINE_PORT8000Listen port.
ENGINE_CORS_ORIGINShttp://localhost:3000Comma-separated allowlist of browser origins.

The repository's root .env.example also sets KAFKA_BOOTSTRAP=localhost:9092 for the local dev stack. No scan reads it today, so pass the broker address with --bootstrap or the console form.

Authentication#

Every API route except GET /health and the /collector/* routes needs the service token or a Supabase user JWT. Collectors authenticate separately, with an enrollment token and then a short-lived collector token. Bare X-VectaSec-* headers are trusted only in dev mode, and a request with no token gets 401. See Security model for how tenants and roles are resolved.

VariableDefaultPurpose
VECTASEC_ENGINE_TOKENunsetShared bearer secret for the console's server side, compared in constant time. Unset disables this path.
VECTASEC_ENGINE_TOKEN_TENANTunsetPins the service token to one tenant UUID. A request naming another tenant in X-VectaSec-Tenant gets 403. Without it, each service-token call must name its tenant in that header.
VECTASEC_DEV_TRUST_HEADERSoff1, true, yes or on makes the engine trust self-asserted X-VectaSec-Tenant and X-VectaSec-Actor headers with no token and skip role checks. It logs a warning at startup. Single-operator local development only.
VECTASEC_ALLOW_SERVICE_SUPERADMINoff1, true or yes lets a platform operator named on the service-token path act as admin in any tenant and use the /admin routes. Leave it off unless you need cross-tenant operator actions from the console.
VECTASEC_COLLECTOR_TOKEN_SECRETderived from DATABASE_URLHMAC key that signs the 3600-second tokens collectors receive at enrollment. With the derived default, any change to DATABASE_URL, such as a password rotation, also changes the key and invalidates tokens issued before it.

AI triage#

AI triage is optional and runs when you triage a finding. Any one key enables it. Providers are tried in the order Anthropic, OpenAI, Gemini, and an unavailable model hands off to the next entry. With every key unset, a deterministic rule-based summary runs locally and nothing is sent to a model provider.

VariableDefaultPurpose
ANTHROPIC_API_KEYunsetEnables Anthropic models, tried first.
OPENAI_API_KEYunsetEnables OpenAI models, tried second.
GEMINI_API_KEYunsetEnables Gemini models, tried last. Use a Google AI Studio key.
VECTASEC_AI_MODELclaude-opus-4-8Primary Anthropic model. claude-sonnet-5 is the fallback.
VECTASEC_AI_OPENAI_MODELgpt-5.2Primary OpenAI model. gpt-5-mini is the fallback.
VECTASEC_AI_GEMINI_MODELgemini-2.5-proPrimary Gemini model. gemini-2.5-flash is the fallback.
VECTASEC_AI_EFFORTmediumEffort level sent with Anthropic requests.
VECTASEC_OPENAI_BASE_URLhttps://api.openai.com/v1OpenAI endpoint override.
VECTASEC_GEMINI_BASE_URLhttps://generativelanguage.googleapis.com/v1betaGemini endpoint override.

Vulnerability feeds#

After each scan that the engine or worker runs, the engine asks OSV (api.osv.dev) and NVD about the component versions it found. Results that a collector pushes are stored as sent and are not enriched from these feeds today. For the three switches below, any non-empty value turns the switch on, so set them to 1 or leave them unset.

VariableDefaultPurpose
VECTASEC_OSV_DISABLEDunsetSkips the OSV lookup.
VECTASEC_NVD_DISABLEDunsetSkips the NVD lookup.
VECTASEC_NVD_ALLunsetQueries NVD for every CPE-bearing component, not only the ones OSV cannot see.
NVD_API_KEYunsetRaises NVD's rate limit from about 5 to about 50 requests per 30 seconds.

Each run makes at most 25 NVD requests. Components past that budget are named in a not-assessable coverage-gap finding rather than skipped silently. An unreachable feed files the same kind of finding. On an air-gapped engine, set both VECTASEC_OSV_DISABLED and VECTASEC_NVD_DISABLED. A disabled feed is recorded as your choice and files no gap findings.

Notifications#

Destinations (Slack, Teams, webhook, email, Jira and SIEM) are configured per tenant in the console under Settings, Integrations. These engine variables are operator-level. See Compliance, reports and alerts.

VariableDefaultPurpose
SMTP_HOSTunsetRequired for email integrations. Without it, every email delivery fails.
SMTP_PORT587SMTP port.
SMTP_STARTTLStrue0, false, no or off disables STARTTLS.
SMTP_FROMvectasec@localhostSender address.
SMTP_USERNAME, SMTP_PASSWORDunsetOptional SMTP login. The password stays in the engine environment and is never stored in the database.
VECTASEC_ALLOW_PRIVATE_NOTIFY_TARGETSoff1, true or yes allows destinations that resolve to private or loopback addresses. Link-local and metadata addresses are always refused.

Console settings#

The console reads its own .env.local. Next.js does not read the repository root .env, so the console gets only the variables you put there. Its .env.example lists the Supabase and email values. Add VECTASEC_ENGINE_TOKEN, and VECTASEC_ENGINE_URL if the engine is not at the default address.

VariableDefaultPurpose
NEXT_PUBLIC_SUPABASE_URLunsetRequired. Supabase project URL. Public by design and inlined into the browser bundle.
NEXT_PUBLIC_SUPABASE_ANON_KEYunsetRequired. Supabase anon key. Public by design, because RLS protects the data.
VECTASEC_ENGINE_URLhttp://127.0.0.1:8000Engine base URL. Read on the server only.
VECTASEC_ENGINE_TOKENunsetMust match the engine's value. Sent as the bearer token on every engine call.
RESEND_API_KEY, EMAIL_FROMunsetOptional sign-in notification emails through Resend. If either is missing, the email is skipped.

The console must never receive SUPABASE_SERVICE_ROLE_KEY or DATABASE_URL. Both bypass RLS, and tenant isolation in the console depends on it reading as the authenticated role.

Collector settings#

VariableDefaultPurpose
VECTASEC_CONTROL_PLANE_URLunsetRequired. Base URL of the engine API that the collector calls outbound. Must be https://.
VECTASEC_ENROLL_TOKEN_FILEunsetPath to the enrollment token. Preferred, and read first when set.
VECTASEC_ENROLL_TOKENunsetThe token itself. Fallback only, because environment variables show up in /proc, docker inspect and kubectl describe.
VECTASEC_TARGETS_FILE/etc/vectasec/targets.jsonThe systems this collector may scan.
VECTASEC_STATE_DIR/var/lib/vectasecHolds the collector id and a hash of the enrollment token.
VECTASEC_COLLECTOR_NAMEhostnameName reported at enrollment.
VECTASEC_CA_BUNDLEunsetCA bundle for a TLS-inspecting egress proxy. The file must exist. When set, it is used for verification and VECTASEC_VERIFY_TLS is not read.
VECTASEC_VERIFY_TLStrueStrict boolean: 1, true, yes, on or 0, false, no, off. Any other value stops the collector at boot.
VECTASEC_TIMEOUT_S, VECTASEC_POLL_WAIT_S, VECTASEC_POLL_INTERVAL_S30, 25, 5Seconds: request timeout, the wait the collector requests on each job poll, and the pause after a poll that returned no jobs.
VECTASEC_HEARTBEAT_INTERVAL_S, VECTASEC_MAX_BACKOFF_S60, 300Seconds: heartbeat interval, and the cap on retry backoff after a failed cycle.
VECTASEC_LOG_LEVELINFOLog level.
VECTASEC_ALLOW_INSECURE_CONTROL_PLANEoffPermits an http:// control-plane URL. Local development only.

Target credentials in the targets file can be written as ${VAR} and are filled from the environment at load, so the file itself holds no secrets. A reference to an unset variable is a boot error. Run vectasec-collector check to validate the configuration and print the redacted targets without contacting anything. The console and API do not mint enrollment tokens yet. See Run a collector in your network.

Connection settings#

Each connector declares its own fields and marks which are required and which are secret. GET /connectors returns those declarations. The console form, the CLI and POST /connections all reject a connection that is missing a required field. Secret fields are split out and stored as one Supabase Vault secret per connection, then merged into the config in memory only at scan or test time. The Vault secret is deleted in the same transaction as its connection.

The CLI has named flags for the common fields (--bootstrap, --url, --host, --port, --token, --admin-token, --username, --password). Anything else a connector reads passes through with --set key=value, which you can repeat. Values arrive as strings, and knob names vary by connector. The CLI connects to the database directly through DATABASE_URL, and without --tenant it writes to the built-in demo tenant. Run these from the engine directory of the release:

bash
uv run vectasec connections add --type kafka --name prod-kafka \
  --bootstrap broker-1:9092,broker-2:9092 --set timeout=30 --tenant YOUR_TENANT_UUID
uv run vectasec connections test prod-kafka --tenant YOUR_TENANT_UUID

PATCH /connections/{id} sets scan_interval_minutes to null (unscheduled) or a value from 5 to 10080. Where the pg_cron extension is installed, as it is on Supabase, a job runs every minute and queues scans for active connections that are due. A collector-mode connection is scanned by an enrolled collector using the credentials in its own targets file, so the connection name must match a target name in that file. The job the collector receives names the target and carries no host or credential.

Every connector's fields are listed in the Connector reference.