Configuration
This page describes the YAML configuration file. The container image uses
/etc/kestrelynx/config.yml by default. Unknown YAML fields produce an error.
The complete annotated example is available in
config.example.yml.
Schedule
| Option | Default | Description |
|---|---|---|
schedule.daily_at |
empty | Local time in HH:MM. When empty, run every 24 hours from startup. |
schedule.run_on_start |
true |
Run one scan immediately when KestreLynx starts. |
Use the container's TZ environment variable to select the timezone used by
daily_at.
Scanning
| Option | Default | Description |
|---|---|---|
scan.severity |
[HIGH, CRITICAL] |
Trivy severities retained for analysis and notification. |
Allowed severity values are UNKNOWN, LOW, MEDIUM, HIGH, and CRITICAL.
Notification destinations
At least one destination is required.
| Option | Default | Description |
|---|---|---|
notify.slack_webhook_url |
empty | Slack incoming webhook URL for channel notifications. |
notify.slack_bot_token |
empty | Slack bot token with chat:write. Set together with slack_channel to enable thread posts and links to the previous report. |
notify.slack_channel |
empty | Destination Slack channel ID for bot delivery. |
notify.generic_webhook_url |
empty | Endpoint that receives structured JSON. |
notify.language |
en |
Language for Slack notifications and PR bodies: en or ja; other values are configuration errors. Generic webhook JSON remains in English. |
notify.notify_on_clean |
false |
Send a notification when no vulnerabilities are found. |
Configure either slack_webhook_url or the bot-token pair, not both. A generic
webhook can be used alongside either Slack delivery method.
See Thread reports for thread placement and how to read the footers.
To use Japanese Slack notifications:
See Notification language for the fixed text that is translated and the content that remains in English.
Notification mode
| Option | Default | Description |
|---|---|---|
notify.mode |
diff |
diff reports changes; full reports all current findings on every scan. |
notify.full_report_day |
monday |
Weekday for a full report in diff mode. Use never to disable it. |
See Package changes for changes treated as differences, and Scan notification conditions for when notifications are sent.
State and Docker
| Option | Default | Description |
|---|---|---|
docker.socket |
/var/run/docker.sock |
Path to the Docker socket. |
state.path |
/var/lib/kestrelynx/state.json |
File used for scan history and diff calculations. |
The intel feed cache lives in an intel directory beside state.path.
The default path is /var/lib/kestrelynx/intel.
See Setup instructions for persisting the directory containing state.path, and History continuity for how history is handled.
Remediation plans and pull requests
See the remediation overview for an entry point and Enabling remediation for setup instructions.
Enablement settings
| Option | Default | Description |
|---|---|---|
remediation.enabled |
false |
Enable remediation plans. |
remediation.pull_requests.enabled |
false |
Enable fix pull requests; requires remediation plans and a GitHub token. |
See Plan and PR execution scope for the processing enabled by each setting.
GitHub access
| Option | Default | Format and requirements |
|---|---|---|
remediation.github.token |
empty | GitHub token without whitespace or control characters; required when pull requests are enabled. |
| Purpose | Required permissions |
|---|---|
| Plans for public repositories | Anonymous reads without a token |
| Plans for private repositories | Contents: Read on a fine-grained token limited to the target repositories |
| Creating and managing PRs | Contents and Pull requests: Read and write on a fine-grained token limited to the target repositories |
Restrict the configuration file to its owner. See Credential destinations for where the token is sent.
Storage location
| Option | Default | Format and description |
|---|---|---|
remediation.storage_dir |
/var/lib/kestrelynx/remediation |
Absolute directory for plans, delivery records, PR records, and the tool cache. |
Changing state.path does not change this location.
See Stored files for its contents.
Image registry authentication
| Option | Default | Description |
|---|---|---|
remediation.registries |
[] |
Per-host credentials for private-image candidate selection and comparison scans. |
| Field | Default or requirement | Format and validation |
|---|---|---|
host |
required | Hostname or IPv4 address as used in image references, with an optional port from 1 to 65535; no scheme, path, or user information. |
username |
required | Nonempty string without whitespace, control characters, or :. |
password |
required | Nonempty password or access token without whitespace or control characters. |
token_hosts |
[] |
Additional token service hosts allowed to receive credentials; each value uses the same format as host. |
- Hostnames are case-insensitive, and
docker.io,index.docker.io, andregistry-1.docker.ioare treated as the same host - Credential entries must not have duplicate
hostvalues after normalization - For Docker Hub authentication, set
host: docker.ioandtoken_hosts: [auth.docker.io]
See Credential destinations for destination and redirect restrictions, and Private image authentication for setup instructions.
Source mappings
| Option | Default | Description |
|---|---|---|
remediation.mappings |
[] |
Map running Compose workloads to their GitHub source files. |
Each entry sets workload, repository, and base_branch, plus exactly one source type.
| Field within a mapping | Requirements and format |
|---|---|
workload |
Required; compose/<project>/<service>, matching the running workload's Compose labels. |
repository |
Required; GitHub repository in owner/name form. |
base_branch |
Required; valid Git branch name used to read sources and as the PR base. |
compose.path / compose.service |
Required for Compose mappings; repository-relative Compose file and service name. |
dockerfile.path |
Required for Dockerfile mappings; repository-relative Dockerfile. |
dockerfile.target |
Optional build stage; omitting it selects the last stage; at most 128 bytes of letters, digits, _, ., or -, starting with a letter. |
dependencies.directory |
Required for dependency-file mappings; dependency directory, with . representing the repository root. |
- Paths must be normalized within the repository, without a leading
/,./,.., or backslashes - A workload can have one mapping of each source type in separate entries
- Shared dependency directories or Dockerfiles must use the same base branch
- A service in the same Compose file in the same repository must not be mapped to multiple workloads
- Repository names are case-insensitive when checking for duplicates
See Base image identification for discovery from Compose build and matching against an explicit Dockerfile, and Supported input formats for supported inputs.
Processing limits
The following options are under remediation.limits.
| Option | Default | Units and allowed range |
|---|---|---|
candidate_scans_per_cycle |
10 |
Candidate-image scans per cycle; positive integer. |
baseline_rescans_per_cycle |
10 |
Baseline rescans per cycle to match comparison conditions; positive integer. |
registry_requests_per_cycle |
200 |
Image-registry HTTP requests per cycle, including token exchanges; positive integer. |
tag_pages_per_repository |
20 |
Tag-list requests per image repository, including requests to find the target version series; positive integer. |
cycle_timeout |
30m |
Deadline for planning, dependency updates, and PR processing; positive duration, excluding ordinary running-image scans. |
new_prs_per_cycle |
3 |
New PRs per cycle when PRs are enabled; positive integer. |
open_prs |
10 |
Open KestreLynx PRs across all configured repositories when PRs are enabled; positive integer. |
dependency_jobs_per_cycle |
3 |
Dependency update units attempted per cycle; positive integer, not a count of packages or containers. |
job_timeout |
6m |
Deadline for each work container's creation, execution, and result collection; from 1m to 60m30s. |
See Reason codes for outcomes caused by limits, PR management for PR handling, and Work container execution for execution deadlines and cleanup.
Work image source
| Option | Default | Format and validation |
|---|---|---|
remediation.worker.registry |
empty | Docker Hub mirror in lowercase host[:port][/path] form; empty uses Docker Hub. |
- Do not include a scheme, tag, digest,
//, or.. - Paths use lowercase letters, digits, and the separators
.,_, and- - The mirror must serve
library/nodeandlibrary/pythonwith the same contents as the official images under the specified host and path
See Pinning official images for pinning and handling unavailable images, Supported runtimes for version series, and Work image downloads for network destinations.
Minimum tool release age
| Option | Default | Format and allowed range |
|---|---|---|
remediation.worker.tool_versions.min_release_age |
72h |
Minimum wait between publication and use of npm, pnpm, or uv; positive duration such as 72h or 30m, excluding 0 and negative values. |
See Waiting after tool publication for the decision rules and Tool downloads and verification for download checks.
Tool cache capacity
| Option | Default | Format and allowed range |
|---|---|---|
remediation.worker.tool_versions.cache_max_size |
1GiB |
Maximum npm, pnpm, and uv cache size; integer bytes or an integer followed by B, KiB, MiB, or GiB, with a minimum of 128MiB. |
See Tool cache reuse for checks before reuse and handling insufficient capacity.
Worker program location
| Option | Default | Format and scope |
|---|---|---|
remediation.worker.program_dir |
empty | Empty or an absolute directory containing a worker program for development; not required for standard releases. |
See Container inputs for checks when passing the program to a work container.
Startup validation
The following combinations cause startup errors.
- Enabling PRs without
remediation.enabled - Enabling PRs without
remediation.github.token - Enabling remediation plans with
kubernetes.enabled: true
Token format, storage, mappings, processing limits, registry credentials, and work container settings are validated even when the feature is disabled. These configuration checks do not establish that a remote repository or image is accessible.
Runtime usage
Runtime usage is an experimental feature.
| Option | Default | Description |
|---|---|---|
runtime.enabled |
false |
Read Sensor evidence and include runtime usage in notifications. Leave disabled when no Sensor is installed. |
runtime.mute_unfixable_not_in_use |
false |
Mute eligible findings with no fix and no observed use for 7+ days in Slack. Requires runtime.enabled: true; priority is unchanged and all findings remain in the generic webhook. |
runtime.evidence_dir |
/var/lib/kestrelynx-runtime |
Absolute path where the Sensor evidence volume is mounted. Must match the Sensor's --evidence-dir. |
With runtime.enabled: false, KestreLynx does not open the evidence directory
or add runtime information to notifications. Ecosystem labels and webhook
ecosystem fields apply independently of this setting.
Setting both runtime.enabled: true and kubernetes.enabled: true is a
configuration error. Runtime usage is available only for Docker.
When enabled, KestreLynx also uses Docker API GET /containers/{id}/json,
in addition to GET /containers/json. Containers with the label
io.kestrelynx.runtime.exclude=true are excluded from runtime usage
assessment; only the lowercase value true matches.
See Runtime usage for Sensor setup, observation rules, muting conditions, notification resumption, and permissions.
Kubernetes
| Option | Default | Description |
|---|---|---|
kubernetes.enabled |
false |
Scan a Kubernetes cluster instead of a Docker host. |
kubernetes.api_server |
empty | Kubernetes API server URL. When empty, use KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT. A non-empty value must start with https://. |
kubernetes.token_file |
empty | ServiceAccount token file. When empty, use /var/run/secrets/kubernetes.io/serviceaccount/token. |
kubernetes.ca_file |
empty | Cluster CA bundle in PEM format. When empty, use /var/run/secrets/kubernetes.io/serviceaccount/ca.crt. |
kubernetes.tls_server_name |
empty | Override the server name used to validate the API server's TLS certificate. Empty means no override. |
kubernetes.namespaces |
[] |
Namespaces to scan. Empty or omitted means every namespace. |
Setting docker.socket to a value, including "", together with kubernetes.enabled: true
fails at startup. Omitting the key or setting it to null does not cause this conflict.
An empty docker: section is accepted. Remove the entire docker: section when enabling Kubernetes.
Inside a cluster, api_server, token_file, and ca_file can remain empty to
use the Pod's injected API server address and mounted ServiceAccount token and
CA. With Kubernetes enabled, startup fails if api_server is empty and either
API server environment variable is missing. The CA bundle must be readable and
contain valid PEM certificates at runtime; there is no insecure fallback.
Each namespace must be a DNS-1123 label: lowercase alphanumerics and hyphens, 1–63 bytes, starting and ending with an alphanumeric. When namespaces are set, Pods, ReplicaSets, and Jobs are listed separately in each namespace. Node listing remains cluster-wide.
Environment
| Option | Default | Description |
|---|---|---|
environment.name |
empty | Optional name for this instance's scan history. Empty means the unnamed default environment. |
A non-empty name must be a DNS-1123 label: lowercase alphanumerics and hyphens, 1–63 bytes, starting and ending with an alphanumeric. Values are not normalized; uppercase letters, dots, underscores, and whitespace are rejected.
When set, the name appears as [name] in the Slack header and as name in the
generic webhook payload's environment object. That object always includes
kind, either docker or kubernetes, derived from the enabled adapter. The
environment kind is not configurable. The webhook omits name when it is empty.
The name labels scan history rather than identifying the host; it is not derived from a hostname or IP address. It is safe to keep the same name across host rebuilds and migrations while retaining the state file. Adding, changing, or removing the name does not reset history, change first-seen dates, or re-notify existing findings.
Exploitation-based triage
| Option | Default | Description |
|---|---|---|
triage.enabled |
true |
Enable CISA KEV- and EPSS-based prioritization. |
triage.act_now_epss |
0.10 |
EPSS probability at or above which a CVE becomes act now. |
triage.watch_epss |
0.01 |
EPSS probability at or above which a CVE is at least watch. |
triage.kev_url |
empty | Override the CISA KEV feed URL, for example with a local mirror. |
triage.epss_url |
empty | Override the EPSS feed URL, for example with a local mirror. |
triage.discussion_links |
true |
Look up Hacker News discussions for act-now CVEs. |
See Outbound communication for where KestreLynx connects and what it sends.
Thresholds must satisfy: