Settings Reference¶
Open Settings with the ⚙ Settings button in the toolbar.
Essential vs All¶
Settings opens on Essential, which shows only the controls a feature is dead without — the AI models, enrichment and exposure API keys, and integration URLs and credentials — across six tabs. All shows everything: 16 tabs and every tuning knob. The choice is remembered per browser.
The rule, for anyone adding a field:
A control is Essential if the feature behind it does nothing until you type something in. Anything with a working default lives under All.
So credentials and endpoint URLs are Essential; timeouts, retry counts, throttle delays, output
caps, CA-bundle paths (_CA) and prompt-file overrides are not. Tabs that manage content rather
than configuration — IOC Whitelist, NSRL, Importers, KEV, Report Templates, Dashboard Views — sit
under All too: they are empty and working out of the box.
Skip TLS verify (DFIR_<NAME>_INSECURE) is the one deliberate exception, on every integration
that has it — MISP, YETI, OpenCTI, DFIR-IRIS, Timesketch, Notion, ClickUp and the notification
webhooks — together with the global Allow insecure TLS to external hosts
(DFIR_TLS_ALLOW_INSECURE_EXTERNAL) a non-loopback host additionally needs. A self-hosted instance
behind a self-signed certificate is dead without one of them, and the error it fails with names no
setting at all, so burying the flag under All left the connect flow failing with no visible knob to
reach for. Prefer a _CA bundle where you have one: it keeps verification on.
Jira and ServiceNow have the same flag and stay out of Essential — their whole block is read-only in
the dashboard by design, a security boundary edited in .env and applied by a restart.
Tools is All-only in full. Every external binary it wires up (Hayabusa, the Velociraptor CLI, Suricata, Snort, YARA) is blank-means-off, so nothing is broken by leaving them unconfigured — setting one up is a deliberate trip to All rather than something a new install must face.
In the markup an Essential control carries a data-essential attribute, so a newly added field
stays out of Essential until someone opts it in.
companion/tests/settings/settingsEssentialAll.test.ts pins the full Essential set; adding to it
means editing that list.
Hiding a field never changes what is saved. Save posts only the keys whose values you actually
changed, so a field you cannot see cannot blank a .env key, and switching modes mid-edit keeps
whatever you have typed.
Search¶
The box beside the Settings title filters every field as you type. Tokens are ANDed and matched as
substrings, against a field's label, its hint, and its env key: max events, DFIR_MAX_EVENTS and
dfir-max-events all find the same control, so a key copied out of .env or the docs works as-is.
Select options are searchable too — ollama finds the AI provider dropdown.
Search always spans All, whichever mode you are in. You search precisely because you cannot find
something, so a search confined to Essential would report "no results" for a field that exists. Tabs
Essential hides — Velociraptor, Tools, Dashboard Views and the rest — appear in the tab bar while a
search is active, each badged with the number of fields it will show. Typing a tab's own name (kev,
whitelist, nsrl) matches the tab and shows its pane unfiltered, which is how the tabs that manage
content rather than configuration stay reachable.
The Essential / All toggle steps aside while a search is active, because search has suspended the Essential filter and the toggle would have no visible effect. Clear the box — empty it, use the ⨯, or press Escape in it — and the toggle returns with your choice unchanged. Searching never rewrites the remembered Essential/All preference, and closing Settings clears the box.
General¶
- Case root location
- Server port
- Log level (debug / info / warn / error) — live toggle, no restart
- Open setup wizard link
- Push ingest token management
- Update check (opt-in dashboard banner for new GitHub releases)
- Theme (dark / light)
- Import severity — manage or clear the remembered minimum-severity import floor (see Importing Evidence)
- Timeline row display — choose which sub-elements show on each forensic-timeline row (see Dashboard → Forensic Timeline)
- Screenshot OCR search — enable/disable local Tesseract OCR indexing of captures
- Evidence drop folder — enable/disable the per-case auto-import watcher, poll interval, and per-file size cap (see Importing Evidence)
- Vim-style timeline navigation — toggle
j/k/f/i/p/n/?keyboard shortcuts on the Forensic Timeline, default on (see Dashboard → Forensic Timeline) DFIR_IMPORT_BULK_MIN_MB/DFIR_IMPORT_BATCH_ROWS(env vars) — the batched Velociraptor import. An export at or aboveDFIR_IMPORT_BULK_MIN_MBMB (default 8;0= always) is imported one batch ofDFIR_IMPORT_BATCH_ROWSrows (default 5000) at a time — tagged, gated and written per batch, with one log line per batch — instead of expanded whole in memory. Under the threshold the import runs as before. See Importing → Large Velociraptor exports.DFIR_MAX_IMPORT_FILE_MB(env var) — the whole-file ceiling for Import-from-path, default 256. A non-Plaso file over it is refused with a 413 that names this knob, before the file is read; Plaso super-timelines stream and are exempt. The drop folder has its own cap,DFIR_DROP_MAX_BYTES(default 200 MB), and since #921 that cap also bounds the SO-CRATES upload, which buffers the whole file.DFIR_MAX_EVENTS(env var) — the per-import event ingestion cap, default 2000. Raise it for cases that need a full MFT/USN import; guarded against 0/negative/NaN silently reinstating the default.DFIR_ALLOWED_ORIGINS(env var) — comma-separated CORS allowlist of extra trusted browser origins beyond loopback, the extension, and any origin the companion itself served; every other origin gets a403. Only needed when the dashboard is reached through a hostname (reverse proxy, hosted deployment) — localhost/LAN/Docker setups need no configuration.DFIR_ALLOWED_HOSTS/DFIR_ALLOWED_HOST_SUFFIXES(env vars) — comma-separated hostnames (or domain suffixes such as.lab.example.com) that this companion answers to. Loopback and bare IP addresses are always accepted, so localhost, Docker, and LAN access viahttp://192.168.1.50:4773need no configuration. An unrecognised name gets a403before any route runs: that is the DNS-rebinding defence, which stops a website you merely visit from pointing its own domain at your machine and reading your case data. Suffixes match on a label boundary, so.acme.comnever matchesevilacme.com.
Authentication¶
Authentication settings are deployment security controls, so they are intentionally not editable
from the dashboard. Set them in .env or the deployment's secret store and restart.
DFIR_AUTH_MODE—single-user(default) orteam; stop the server, change this value, and restart to switch modes. Team identities and roles remain stored while single-user mode is active.DFIR_AUTH_COOKIE_SECURE— secure cookies; defaults on in team modeDFIR_AUTH_SESSION_HOURS— browser-session lifetime, default 12 hoursDFIR_AUTH_BOOTSTRAP_TOKEN— protects first-administrator setup; required in team mode while no identity exists, on any bind address. At least 32 characters, or the server refuses to start. Wrong guesses are rate-limited and audited.DFIR_AUTH_DATA_DIR— optional identity/session database locationDFIR_AUTH_OIDC_ISSUER,_CLIENT_ID,_CLIENT_SECRET,_REDIRECT_URI,_SCOPES— optional organization sign-in
See Team Accounts and Case Roles for setup, roles, service identities, emergency access, and the one-writer deployment model.
AI¶
- Provider, model, API key, base URL (extraction)
- Synthesis model (optional separate model for findings/attacker path) — also configurable directly in the first-run setup wizard's AI step, not just here
- VQL-generation model (optional dedicated model — many general models struggle with VQL syntax)
- Second-opinion model (optional rival model for the 2nd opinion button) and the referee that judges each A-vs-B disagreement (blank = model A)
- Timeout, max tokens, context window size
- Chain-of-Thought (synthesis thinking tokens)
- Anonymisation on/off and per-category toggles — IPs (internal and public), hostnames, usernames, domains, emails, paths, encoded commands, SIDs, credit cards, phone numbers, national ID numbers; see AI Analysis → What the AI Sees for exactly what each one catches, the redacted-export exception for public IPs, and known limitations (the narrow IPv4/IPv6 masking gaps, screenshot IP loss, national-ID false positives)
- Presidio (optional external PII detector) — analyzer URL, confidence floor, and a Test connection button; see Presidio & PII Masking
- Preflight diagnostics disable
- Re-run the setup wizard
- Live AI test — confirms the current key works right now
Screenshot/vision provider — DFIR_VISION_PROVIDER/_MODEL/_KEY/_BASE_URL/_IMAGE_DETAIL configure the screenshot-OCR-only model, renamed from DFIR_AI_* (legacy names still work as a fallback). Text-only AI features run off the synthesis provider and never need a vision provider configured.
Second opinion — DFIR_AI_SECOND_OPINION_MODEL/_PROVIDER/_KEY/_BASE_URL configure model B, the rival model behind the 2nd opinion button. Setting _MODEL turns the feature on; the other three fall back to the vision provider settings when blank.
Referee for 2nd-opinion verdicts — DFIR_AI_RECONCILE_MODEL/_PROVIDER/_KEY/_BASE_URL choose the model that writes the referee suggests line on each disagreement. Leave _MODEL blank and model A (the synthesis model) referees. Set it to same-as-b and model B referees its own findings. Set it to any other model ID for a neutral third referee. The other three fall back to the vision provider settings when blank. See AI Analysis → Second opinion.
Deep pass — DFIR_DEEP_PASS_MAX_BATCHES (default 30) caps how many batches a deep pass run may take, refusing oversized runs up front; DFIR_AI_OBSERVE_PROMPT_FILE is an ejectable override of its batch-observation prompt.
Enrichment¶
Lists all 13 enrichment providers. Each shows:
- Current status (configured / key missing)
- Which environment variable to set
- Enable/disable for this case
Info
Nothing is sent externally until you enable a provider for the specific case you're working on.
Exposure¶
Customer exposure check configuration:
- Add customer domains and email addresses
- Select which providers to use (LeakCheck, HIBP, DeHashed, Shodan)
- Run the exposure check and view results
Integrations¶
- DFIR-IRIS (URL, key, reconnect)
- Timesketch (URL, credentials, reconnect)
- Notion (API token)
- ClickUp (API token)
Velociraptor¶
The shared bundle library — global, like every other Settings tab.
- Reconnect button and ↻ Refresh client list
- Browse server artifacts
- Triage bundle management (built-ins, custom, edit in place, Reset to default)
- Per-bundle defaults (wait, timeout, expiry, per-artifact parameters and exclude filters)
Running a bundle, importing a hunt from the Velociraptor GUI and live monitoring act on the connected case, so they live on the dashboard's Fleet Collection panel. The API config path is set under Integrations.
Tools¶
Run your own locally-installed external tools against raw evidence the Companion can't parse (EVTX/PCAP/files), then ingest the tool's output through the existing importers. The Companion never downloads or bundles a binary — install and update it yourself (repo links are shown per tool).
- Hayabusa / Velociraptor CLI — EVTX → csv/json-timeline / artifact JSON
- Suricata / Snort — PCAP → alerts (Snort uses your own rules file)
- YARA — scan files/dirs → rule matches (file/hash IOCs)
Custom tools — beyond the five built-ins, add your own: a name, the binary path, a run command
(<target> = input file, <output> = output file, omit for stdout), an optional update command, and
the file extensions it handles. The output is auto-detected and routed to the right importer. Add as
many as you like; each appears in the Import/drop banners for its extensions.
Per tool: binary path (blank = off), run-args template (<target>/<output>/<rules> placeholders),
rules path (Snort/YARA), a separate Update rules command + button, an auto-run on drop toggle,
and timeout/output caps. Click Reconnect / apply to apply saved paths without a restart. A raw
.evtx/.evt/.pcap/.pcapng copied into a case's drop/ folder runs automatically when a matching
tool has auto-run on; the Import dialog shows a banner for these formats. Config is stored in .env
(DFIR_TOOL_*, not a secret). Commands run with no shell (args tokenized) and the target path is
contained to the case directory. Master kill-switch: DFIR_TOOL_AUTO_RUN=off.
MCP servers¶
MCP servers are configured in Claude Code, then allowed under
Settings → All → Tools → MCP servers. Companion stores policy and evidence-delivery settings,
not the MCP endpoint or token. Leaving Restrict to tools blank allows all tools offered by an
enabled server; use the field only when you want a narrower allowlist. Investigation timeout
sets DFIR_MCP_AGENT_TIMEOUT_MS; it defaults to 3,600,000 ms (one hour) because memory and disk
analysis routinely outlast ordinary AI requests.
See MCP Analysis for recommended REMnux and SIFT servers, Claude Code registration, shared-path and SCP configuration, validation, security notes, and plain-English prompt examples.
IOC Whitelist¶
Global known-good pattern list:
- Add CIDR, exact, or regex rules
- Optional type scoping (e.g. "only match IPs")
- Import/export as CSV or JSON
- Apply to current case — retroactively marks matching IOCs false-positive
NSRL¶
Known-good file hash database:
- Paste hashes, import a flat hash file, or load an NSRL RDS hash list by file path
- Connect to a large NSRL RDS SQLite database (Node 22.5+)
- Apply to current case
Importers¶
Custom declarative importers:
- List all custom importers (filename, format, match criteria)
- Add a new importer (paste JSON spec)
- Reload importers from disk
- Get AI prompt — copy the prompt to use with your AI assistant to generate a spec for a new file format
- Precedence setting: built-in-first (default) or external-first
Content Tagger¶
Controls the content-based event tagger (companion/data/tags.yaml), env-configured (no dashboard fields):
TAGGER_AUTO— run the tagger automatically after every import (defaulttrue;false= manual-only, via Super-Timeline → Content tagger → Run tagger)TAGGER_SCOPE—forensic|super|both(defaultboth);superonly tags the super-timeline (never mutates severity/MITRE)
KEV¶
CISA Known Exploited Vulnerabilities integration:
- Enable/disable KEV cross-reference
- CVEs in findings/events are checked against CISA KEV
- KEV-listed CVEs are highlighted and mentioned in synthesis context and report
Loading the catalog. "Load from CISA feed" makes the server fetch the feed, so the URL must
be https to a public address. A URL that points at a loopback, private or link-local address is
refused — that is how a feed field turns into a way to read the host's own internal services — and
every redirect is checked the same way. The connection is then pinned to the address that check
approved, so a hostname cannot change what it points at between the check and the connection. A
host that will not resolve is refused rather than tried, so on a DNS outage this reports "could not
be resolved". "Load from server file" reads a saved copy and needs no outbound access at all; use it
when the Companion is air-gapped.
DFIR_KEV_ALLOW_INTERNAL_URL=true— allowhttpand internal addresses, for an organisation that mirrors the KEV feed inside its own network. Off by default.
Report Templates¶
Manage report templates:
- Edit the default template or create new ones
- Set: cover title, subtitle, accent colour, running header/footer, logo visibility
- Enable/disable and reorder report sections
- Mark sections as mandatory at release
- Require independent peer review and/or evidence links for every non-dismissed finding
- Assign a template per case
Critical and High findings always require valid evidence-event links, regardless of template. A template's evidence requirement extends that gate to every non-dismissed finding. Independent review requires team authentication; solo self-review cannot satisfy that rule.
Built-in templates: Standard (full technical report), Executive (condensed), and any you create.
Dashboard Views¶
Preset panel layouts:
| View | Best for |
|---|---|
| Analyst (default) | All technical panels, in the app's intended reading order |
| Lead | Findings, timeline, playbook, hunting |
| Executive | Findings, attack path, countermeasures, exposure |
| Triage | Timeline, IOCs, MITRE, assets |
| Report | Report-oriented panel order |
| Deep-Dive | Evidence chain, hypotheses, threads, notebook |
| Hunt-Prep | Hunting profile, adversary hints, next techniques, query translator |
A new case (or any case with no saved per-case dashboard-view choice) opens with Analyst instead of the raw "Custom" section order. Explicitly picking Custom from the dashboard-view menu still sticks across reloads. A permanent note below all panels points back here for further customization.
Each preset is fully customisable — reorder panels, set a severity floor, cap the timeline row count, link a report template. Saved per case.
Notifications¶
Alert channels for new findings, playbook updates, and investigation milestones:
- Slack webhook
- Microsoft Teams webhook
- Mattermost webhook
- Discord webhook
- Telegram bot
- SMTP email
Each channel has:
- A minimum severity threshold (only notify for High+, for example)
- Per-event-type toggles (findings / playbook / milestones)
- A Test button that sends a test message
Info
Notification configs are stored in a global config file (not .env) and webhook URLs are redacted in all API responses.
Telegram: leave the bot token blank to reuse the war-room bot's
A Telegram channel with no token of its own falls back to DFIR_TELEGRAM_BOT_TOKEN from .env, and the token field
shows (already set). Fill in only the chat ID. The token is never copied into the notification config, so rotating
it in .env rotates the channel too. Type a token here only to send through a different bot.
Audit Export¶
Forward each case's activity log — who did what, when, to which case, and whether the action succeeded — to a SIEM. This is the surface auditors ask for: SOC 2 and ISO 27001 both expect privileged actions to land in central log aggregation rather than only in the tool that recorded them.
Three destination types:
- Splunk HEC — collector URL and an HEC token. Optional index and sourcetype.
- Elasticsearch — cluster URL and an index. Username + password, an API key, or no credential at all for a cluster without authentication.
- Syslog — host, port, and UDP or TCP. RFC 5424, facility
log audit.
Each destination has an on switch, a Test button that sends one clearly-marked test record, and a Send history button.
What each record carries¶
| Field | What it says |
|---|---|
id |
The activity entry's own id. A SIEM that honours it collapses a duplicate from a re-send. |
timestamp |
When the analyst acted — not when the batch was sent. |
caseId |
Which case. |
category, action, detail |
What was done. |
actor |
The name recorded against the action. |
actorId, actorKind |
Present only when an authenticated session made the change. |
actorVerified |
Whether the server verified that name, or the client supplied it. |
outcome |
success or error. A failed privileged action is the interesting one. |
targetType, targetId |
What the action was aimed at, when the entry names one. |
This sends case content off the box
Case identifiers, analyst names, and what each analyst did go to a third-party system. Off by default — each destination is opt-in, and the list starts empty.
Changing the collector asks for the credential again¶
Editing a destination and leaving its token, password, or API key blank keeps the saved one — but only while it still points at the same collector. Change the URL and the credential is not carried across: a Splunk destination repointed at a new host asks for a new HEC token, and an Elasticsearch one drops the saved password rather than presenting it to a different cluster. The index, sourcetype, and username travel with the rest of the config, because they say what to write rather than who may write it.
Switching a destination on forwards only what happens next¶
A destination begins at the current end of every case's log — the position is set the moment it is switched on, not the first time it sends. Turning one on does not ship the history that is already recorded; that is what Send history is for, and it asks before it runs. The reason is the obvious failure: a destination enabled mid-investigation would otherwise push a year of activity into a production SIEM the moment someone ticked a box.
Switching one off and on again works the same way. The gap while it was off is not filled in on the way back up, because "only what happens next" has to mean the same thing every time it is switched on.
After an outage¶
The export remembers how far it got in each case, per destination, and writes that position only after a send is accepted — and for Elasticsearch, only when the cluster's reply actually accounts for every record sent. A collector that is down holds the position where it was, so the next action re-sends from there rather than skipping, and the companion also drains everything still pending once at startup. That second part matters for a case that has gone quiet or been closed: it will never see another action to trigger a send of its own. Splunk and Elasticsearch receive the entry id, so a re-send is collapsed rather than duplicated; a plain syslog receiver has no such mechanism and will show the line twice.
Info
Destinations and their credentials are stored in a global config file next to cases/ (not
.env), and every token, password and API key is redacted in all API responses. Only the TLS
trust for a self-hosted collector is an .env setting: DFIR_AUDIT_CA and
DFIR_AUDIT_INSECURE.
War-Room Bot¶
Inbound slash commands from Slack / Teams / Telegram — see War-Room Slash-Command Bot for setup. Configured entirely in .env; each platform switches on when its secret is set.
| Variable | Meaning |
|---|---|
DFIR_SLACK_SOCKET_MODE |
=on to receive Slack commands over an outbound WebSocket. No tunnel, no Request URL. Needs DFIR_SLACK_APP_TOKEN |
DFIR_SLACK_APP_TOKEN |
App-level token, xapp-…, scope connections:write. Not a bot token |
DFIR_TELEGRAM_POLL |
=on to receive Telegram commands by long polling. No tunnel, no inbound URL. Needs only DFIR_TELEGRAM_BOT_TOKEN |
DFIR_TELEGRAM_BOT_TOKEN |
@BotFather token. Required for polling; in webhook mode it delivers ask/hunt/synthesize results |
DFIR_ALLOWED_HOSTS |
Hostnames the Companion answers to. Required in webhook mode — the tunnel/proxy hostname must be listed, or requests are refused with 403. Not used by Socket Mode or polling |
DFIR_SLACK_SIGNING_SECRET |
Slack app signing secret; enables /integrations/slack/command. Webhook mode only |
DFIR_TEAMS_TOKEN |
Shared bearer token; enables /integrations/teams/command. At least 32 characters, or the server refuses to start. Wrong guesses are rate-limited |
DFIR_TELEGRAM_SECRET_TOKEN |
setWebhook secret; enables /integrations/telegram/command. Webhook mode only. At least 32 characters, or the server refuses to start. Wrong guesses are rate-limited |
DFIR_SLACK_ACTION_USERSDFIR_TEAMS_ACTION_USERSDFIR_TELEGRAM_ACTION_USERS |
Comma-separated user ids allowed to run ask/hunt/synthesize/bind. Unset = open to the whole channel; once set, everyone else is confined to the channel's bound case |
DFIR_SLACK_RESPONSE_HOSTSDFIR_TEAMS_RESPONSE_HOSTS |
Extra hosts an async result may be delivered to, for a self-hosted Slack-compatible server. Defaults cover the platforms' own hosts |
DFIR_TELEGRAM_API_BASE |
Bot API base URL override (default https://api.telegram.org) |
Channel-to-case bindings are stored alongside the notification config, not in .env.
Updates¶
Opt-in GitHub release check. Shows a dashboard banner when a newer version is available. Never auto-installs.
Diagnostics¶
Operator health view:
- Disk usage and warning level on the cases folder
- Case count (open / closed)
- Processing queue (screenshots pending analysis, synthesis in flight)
- Redacted AI config (provider, model, timeout — never the API key)
- Recent AI error counts by type
- AI cost — this case — calls, dollar cost, and token counts broken down by Vision / Synthesis /
Other and by model, read from the provider's real per-call cost and token counts (never a guessed
price). Providers that don't report cost/tokens show "n/a", never a fabricated
$0.00. - Importer health (attempt counts over 24h/7d)
- Local performance and capacity history — bounded importer yield, indexed-query p50/p95,
job stalls/retries, AI latency/rate limits/tokens/cost, export duration/size, live-connection health,
memory, disk and projected case growth. Metric labels are fixed categories and never contain case
titles, evidence, filenames, hostnames, users or IOCs. Set
DFIR_LOCAL_TELEMETRY=offto disable it. - Previewed support bundle — inspect the aggregate-only JSON before copying or downloading it. Secrets, absolute paths, case identifiers and evidence are excluded by default; nothing is sent externally.
- Compute case sizes button
- Live AI test — connectivity test with latency
- Pre-flight check — re-run startup diagnostics on demand
For repeatable capacity testing, run npm run bench:storage -- --sizes=1000000,10000000
--query-runs=20 from companion/. It creates throwaway data outside the cases folder and emits one
JSON result per size with import events/second, cold-open latency, filtered-query p50/p95, export
duration and peak memory. Use the same event sizes, query-run count, hardware and filesystem when
comparing releases.
- Per-case backup list — state backups with one-click restore
- State backup configuration (retention counts, interval)
- Background-job limits — durable history retention, total concurrency, and a per-case running
cap. The per-case cap keeps one large investigation from occupying every worker.
- Evidence integrity — the result of the last chain-of-custody verification: which triggers are
active, how long ago a case was last checked, how many artifacts verified clean, and any case whose
evidence or custody log failed. See Chain of Custody
- Host Clock Skew — each host's measured clock offset from cross-tool timestamp anchors (events
multiple sources independently timestamped), flagged once it exceeds 60 seconds. A host needs
several consistent anchors before its offset is trusted; ↻ Re-measure re-runs detection against
the current timeline, and the Align timelines toggle projects every host onto a common time
axis — affecting the Forensic Timeline, correlation windows, the evidence graph, and reports while
it's on. Alignment never rewrites recorded evidence: each row keeps its original timestamp for
display, alongside the corrected one. An analyst can manually override any host's offset; an
explicit 0 pins that host's clock as already correct.
A **large** offset — beyond about two days — is measured and flagged but never applied on its
own. A VM restored from an old snapshot can be months out, and a fictional offset that size
would move a whole host's timeline, so the panel shows it as *measured but not applied* and
waits for you to confirm the host's clock and type the offset in yourself.
The panel also warns about a host whose **own** timestamps split across a huge gap — say 17 of
214 events dated nine months before the rest. That check needs no second clock, so it still
fires on a case with a single evidence source, where no offset can be measured at all. It is a
warning only: nothing is corrected, and it is usually the first sign of a wrong VM clock.
Finally, a timeline row whose **year** was adjusted at import says so under its timestamp, with
the time it was imported as. Some sources (BSD syslog, Cisco ASA, Snort, a bare time column in a
CSV) carry no year at all, so the import has to supply one and the merge re-anchors an obvious
stray onto the case's dominant year. Only a guessed year is ever moved — a year read out of the
record is evidence and is left exactly as recorded.
Evidence integrity environment variables¶
| Variable | Default | Effect |
|---|---|---|
DFIR_CUSTODY_VERIFY_ON_OPEN_MS |
14400000 (4h) |
How long a case's verification stays fresh. Opening a case re-verifies it in the background unless it was checked within this window. 0 turns on-open verification off |
DFIR_CUSTODY_VERIFY_INTERVAL_MS |
0 (off) |
Interval for a sweep of every case, archived included. Off by default so an idle install does no background hashing — set it if you want unattended assurance across the whole store |
Background-job environment variables¶
| Variable | Default | Effect |
|---|---|---|
DFIR_JOBS_MAX |
100 |
Durable job rows retained per case; pruning removes only the oldest terminal rows, never active jobs or their separate analysis-run manifests |
DFIR_JOBS_CONCURRENCY |
4 |
Maximum jobs running across all cases |
DFIR_JOBS_PER_CASE |
1 |
Maximum jobs running for one case, preventing a busy case from starving the others |
- Case Statistics — per-case totals, per-source event breakdown, and import velocity
- Large-import reliability — atomic state-save retry count for big imports is tunable via
DFIR_ATOMIC_WRITE_RETRIES(default 20, ~8.4s of retries) for setups where antivirus/search indexing can outlast the default retry budget on a large USN/MFT import
Tip
The Diagnostics page is your first stop when something breaks. It shows the AI error count by type — auth errors = wrong key, billing errors = quota exceeded, rate limit = slow down — without ever showing your API key.