Releases
Changelog
All notable changes to DFIRe, organized by version. The project follows Semantic Versioning.
1.9.0 — September 15, 2026
Added
- Email notifications: A notifier now delivers by email as
well as by HTTP request. Choose the channel at the top of the editor, then
write the recipients, the subject and the body with the same variables a
payload template uses. The body is Markdown, and DFIRe sends it inside a
header and footer the installation defines. Every message carries an HTML
part and a plain text part, and a Plain text only switch
sends the text part alone. Seven new
EMAIL.*variables address the people on a case, the account an event is about, the superusers and the organization contact. DFIRe writes only to active user accounts and to the domains you allow, and the settings tab now reads Webhooks & Email. See Webhooks and Email → Email notifiers and Email delivery → Layout. - Email delivery settings: A superuser points DFIRe at an SMTP server under Settings → Email Delivery, or at Amazon SES, Mailgun, Microsoft 365 or Google Workspace. The tab holds the sender addresses, the credentials, the domains email may go to, and a cap on messages per minute that every notifier counts against together. A test message reports whether the provider accepted it, and names the reason for a refusal. DFIRe stores every secret encrypted and never shows it again, and delivery stays off until you select a provider. See Email delivery, Amazon SES settings, Mailgun settings, Microsoft 365 settings and Google Workspace settings.
- New notifier events: Nine new events cover the
installation and the accounts on it rather than the investigation.
Case Team Changed, Report Finalized,
Backup Finished and DFIRe Update Available
report on a case team, a report reaching version 1.0, the outcome of a
backup run and a newer release, the last of them once per version.
User Logged In, Login Failed,
User Created, User Deactivated or Roles
Changed and API Key Created carry a new
ACCOUNT.*variable family for the account the event is about, which is a different person fromUSER.*whenever an administrator acts on somebody else's account. An API key event names the key and never carries its value. See Webhooks and Email → ACCOUNT.*. - Playbook description, author and owners: A playbook now carries a description in Markdown, an attribution label, a creation date, and the users and roles responsible for keeping it current. A member of a listed role owns the playbook just as a listed user does. An optional setting narrows changing, reviewing and deleting a playbook to its owners, so one person can maintain their own playbooks without access to cases or settings. Anyone with case rights still uses every playbook, and superusers are exempt. A settings export carries all of it, and matches owners by username and role name on import. See Playbooks → Description, author and owners and Who can manage a playbook.
- Periodic playbook review: Set a review period under Settings → Playbook Policy and every playbook gets a deadline. Recording a review stores the reviewer, the time, the revision reviewed, an optional note and a digest of the definition, and nothing edits or deletes those entries afterwards. The playbook list gains owner, last review and review due columns, a badge, and filters for unowned, never reviewed and overdue playbooks. A daily job warns each active owner in the app on the reminder days you configure and on the deadline, and the new Playbook Review Due webhook event carries the playbook and its review status. Review status is advisory, and an overdue playbook stays fully usable for cases. See Playbooks → Periodic review and Webhooks and Email → Playbook review reminders.
Changed
- Playbooks are readable without edit rights: Anyone holding the view permission on playbooks can open one from Settings → Playbooks and read its definition and review history, with the designer read-only in both Visual and JSON modes. Settings is now reachable by every role that holds the view permission. A playbook whose owner is a role is listed as owned, whoever belongs to that role, and the list marks only the one case where ownership has lapsed: a playbook that lists users, lists no role, and whose listed users have all been deactivated. See Playbooks.
- Notifier trigger picker: The picker groups events into five families: Cases and evidence, Compliance timers, Indicators, Playbooks and automation, and Accounts and system. The controls around it say notifier rather than webhook, since a notifier now delivers either way. See Webhooks and Email.
- The default payload carries the whole event: A notifier with no payload template of its own sends every variable category the event carries, rather than a fixed list of them. The keys it sent before are unchanged, so a receiver reading them keeps reading them. A stored secret is still never part of it. See Webhooks and Email → Payload templates.
- Two rules for a System Root account: A superuser must have an email address, and cannot be a service account. DFIRe refuses to clear the email, and refuses the conversion. Existing accounts stay as they are, and the user list flags a superuser that has no email address. See User Management → Superusers.
Fixed
- Numbers read the same everywhere: A count in the interface groups its thousands the way the English text around it does, rather than following the language settings of the computer showing it.
- Case description in a printed report: The printable report renders the case description as Markdown, the way the case screen shows it, and prints it on the page instead of inside a box.
1.8.2 — September 9, 2026
Changed
- The incident clock opens onto its phases: Click the duration in the case sidebar. It shows how long the incident spent in each phase it has been in, and the phase it is on counts on. Both phase pickers now check a phase the incident has been through and left. See Incidents → Time in each phase.
- Three rules now enforced by the server: A phase change event keeps its time, a saved runbook keeps its slug, and Direct Storage refuses a local filesystem target. The web interface already worked this way. The API and the MCP tools now refuse the change with a validation message. A settings import that names a local target for Direct Storage leaves the role unbound.
Fixed
- Tabs of an unassigned case: A case with no lead investigator opened, then every tab inside it answered with a permission error. A user who may claim and lead the case now sees what is in it. Adding anything to the case still means claiming it first.
- Access Roles shows only what you can grant: The editor hides every permission that only its holder may pass on. API key administration and the webhook permissions were missing from that rule, so ticking one failed with a message instead of being hidden. The list now comes from the server. A permission for managing your own API keys is gone from the editor and the shipped roles, because nothing checked it. See User Management — Editing roles.
- Downloading a file from an evidence item: The download did not check how many bytes arrived, so a transfer cut short by a dropped connection saved a partial file that looked complete. In browsers that stream the download to disk, DFIRe now counts the bytes against the size the server announced. It discards a short or over-long file. See Storage — Downloads.
- A webhook content filter could stall delivery: A filter
such as
(a+)+ora*a*bcould hold a delivery worker until DFIRe restarted. DFIRe now reads the shape of a filter and refuses one that can take unlimited time, both when you save it and each time it runs. DFIRe skips a filter it cannot read and still sends the other webhooks for that event. See Webhooks — Trigger tags and the content filter. - Read-only mode covers the Django admin: Without a valid license, DFIRe is read-only. A superuser could still create, change and delete records through the Django admin, which now refuses those changes as well. The admin stays readable, and signing in and out works as before.
- An edit returned an incomplete user summary: Many API responses embed a short user summary. After an edit, that summary left out the API key count, so a client built from the published schema could not read the response. The summary now carries the same fields whether you read or edit.
- The Audit Log was missing from the user menu: Reading the log needs the View auditlog permission, which every shipped role holds. The menu entry appeared only for accounts that could also open Settings. A Standard user or a View Only user had no link to the page. The entry now follows the read permission, and each reader still sees only the entries they may read. See Audit log.
- AI settings after a failed load: When Settings → AI could not read the stored configuration, it showed the shipped defaults instead. Saving from there turned AI features off and cleared the active provider on an installation that had both set. The screen now reports that the settings failed to load and offers Retry, and it shows no form and no save until a load succeeds.
- Connection warning over a working instance: Some features depend on a service that can be unavailable, such as AI features nobody has set up yet. A failure there sometimes raised the full-screen “No connection to server” panel, which hid the message explaining the problem. The panel now appears only when DFIRe itself is unreachable, and the feature shows its own message in place.
- Switching browser tabs no longer reloads the case chat: DFIRe used to close its real-time connection the moment a tab went to the background. Coming back reopened it, and the chat then re-read every message page you had scrolled back through. The connection now stays open for the first five minutes in the background, so a short switch to another tab costs nothing. After a longer absence it reopens as before, and the chat reads back what changed while you were away.
Security
- Administrators cannot reach past their own rights: An administrator who manages user accounts could end every session on a System Root account. One who manages roles could add the Slack user mapping permissions to their own role, map their Slack account to a System Root user, and act as it from Slack. Only another System Root user can sign one out now. The mapping permissions follow the same rule as the other sensitive ones: only a holder may pass them on. See User Management — Editing roles.
- Case access rules hold on every path: The JSON case export checked team membership but not whether your role may read cases. A team member whose role cannot open cases could download the whole case. Over MCP, an AI agent could edit the contents of a case with no lead investigator before claiming it. Both now apply the rules the web interface applies. See MCP Server.
- The Slack signing secret is gone: Slack Socket Mode does not sign requests, so DFIRe stopped using the signing secret when it moved to Socket Mode. The value stayed in the configuration without encryption. DFIRe now leaves it out and deletes any stored value when you upgrade. See Integrations.
- Case write permissions: Conflicting case and item references can no longer bypass viewer restrictions when creating notes or custody records. Items and notes cannot be moved to another case or item.
1.8.1 — September 2, 2026
Changed
- One published End User License Agreement: DFIRe no longer
ships its own copy of the agreement. At first-run setup it reads the version
published at dfire.fi/eula, shows that
version and its date, and records what it showed you once you accept. A new
installation therefore needs internet access during setup. An isolated
installation accepts from the command line instead: run
manage.py accept_eulato see which version applies, then again with--accept. An installation that already accepted an agreement keeps it and is never asked again. See Deployment → Air-gapped deployment.
Fixed
- Case attributes after a playbook change: Changing a case's playbook kept every field of the old one, empty fields included, while the editor offered only the current playbook's fields. A value entered under the old playbook stayed on the case with no way to edit it. DFIRe now keeps a field that holds a value, drops an empty one, and offers every field the case carries. A field the current playbook does not define has a control that takes it off the case. See Playbooks → Swapping a playbook on an existing case.
- Sending a message while the assistant answers: Pressing Enter while an answer streamed did nothing, with no message and no explanation. An urgent line could sit unsent while the writer believed it had gone. DFIRe now says the message was not sent and what to do next, and leaves the text in the box. See Case chat → Asking the assistant.
- Two people changing an action at the same moment: If two status changes on the same case landed within a few milliseconds of each other, one was overwritten: the action appeared to change, then reverted a moment later. Both changes are now kept.
- Angle brackets on the dashboard: Text written with
<in it, such as a command name or a placeholder, showed the escaped form rather than the character. This affected the description on a case card, and an action and what it waits on in the daily summary. All of them now read as typed, the way the case page already does. - AI settings screen on a damaged configuration: A settings import could write an AI configuration that was not an object. The AI / LLM settings screen then failed to load, and could not be saved over. DFIRe now reads such a value as no configuration, so the screen opens and a new configuration can be saved over it.
Security
- Dependency security updates: djangorestframework 3.17.2 (CVE-2026-73228, CVE-2026-73229) and browserslist 4.28.8 (GHSA-c83g-rgw3-j3cx, GHSA-73wf-gq98-2v4g), alongside the routine dependency updates that ship with this release.
1.8.0 — August 30, 2026
Added
- Case Chat: Every case now has a live chat, which also pops out into
a window of its own. The transcript belongs to the case: DFIRe searches it, carries
it through case export and import, and never deletes it. Write
@assistantto ask the AI assistant about the case in front of the team. The assistant reads the case and cannot change it. Chat has its own permissions, and an upgrade gives every role read access and posting to the roles that can already add case notes. See Case Chat. - Case chat over MCP: A connected AI agent can read a case chat and post to it, through a Case Chat tool group that a superuser must turn on. Until then no chat content reaches an agent. A posted message enters the chat and the audit trail as the user whose API key the agent holds. See MCP Server → Case Chat.
- Multi-factor authentication for password accounts: An account that signs in with a password can now require a code from an authenticator app. Set it up from My Profile, and keep the ten recovery codes DFIRe shows once. An administrator can clear MFA for a user who has lost both, and Settings → User Accounts shows which accounts have it on. SSO accounts cannot use it, linking an account to SSO turns it off, and API keys stay outside it. See User Management → Multi-Factor Authentication.
- Requiring multi-factor authentication: A System Root user can require MFA for every password account, from Settings → User Accounts. An account with no authenticator app keeps a set number of password sign-ins to get set up, each naming how many remain. After the last one DFIRe refuses the password until an administrator restores the account's sign-ins. Changing the setting needs MFA on your own account, in both directions. SSO and service accounts stay outside the requirement, and DFIRe never locks out a System Root account. See User Management → Requiring it for everyone.
- Daily token budget for AI features: AI features now spend at most 250,000 tokens a day across every provider. Settings → AI / LLM shows the day's spend beside the budget, with the time left until it resets at midnight UTC. When the day's spend reaches the budget, DFIRe refuses further AI requests until the reset. The budget also applies after an upgrade: raise it if your work needs more, or turn Enable budget off to run without one. See AI Integration.
Security
- Sign-in refuses cross-site requests: The sign-in endpoint accepted a
request from any other site. A page elsewhere could sign a visitor's browser into an
account the attacker controlled, and whatever the visitor filed next went into that
account. Sign-in now needs what every other write in DFIRe already needs, and the
sign-in screen works as before. A script that posts credentials directly must read
/api/sso/providers/first, then send thecsrftokencookie back in theX-CSRFTokenheader. Over HTTPS, add aRefererorOriginheader naming your DFIRe address. - One sign-in screen: The Django admin had its own password form. It checked the same accounts, but went around the sign-in attempt limit, the audit entries, the session list, and the refusals that keep SSO-only accounts and service accounts off password sign-in. That address now redirects to the DFIRe sign-in screen, and returns to the admin page afterwards. Superusers reach the Django admin as before once they sign in.
- A silent WebSocket connection now closes: DFIRe rechecks your
session and your role whenever a WebSocket connection sends its keepalive ping. A
client that sent no ping escaped that check, and could go on receiving a case's
events after the session signed out or its role lost access. DFIRe now closes a
connection that goes three minutes without a ping. The DFIRe interface pings every
25 seconds, so nothing changes for it. A program that opens a WebSocket connection
itself must send
{"type": "ping"}on a similar schedule.
Changed
- Manage Team lists the case team only: The dialog listed every user account with an access selector, which read as though everyone was on the case. It now lists the people assigned to it, and Add User to Case searches for anyone else. Setting a member to None takes them off the case when you save, and closing the dialog with unsaved changes asks first. See Cases.
Fixed
- Live updates no longer stop while a session is still valid: Three situations left a signed-in session on a dead real-time connection until a page reload: waking a computer from sleep with a case in view, moving a team member between investigator and viewer, and revoking one session from My Profile, which dropped the others too. Each now keeps or restores the connection. DFIRe still refuses a session that has really ended.
- Importing a case no longer writes what your role cannot: An import created everything the file carried, as long as you could create or update a case. A role that could not add notes, evidence, timeline entries, indicators, reports, compliance timers or chains of custody still got them by importing a case that carried them. Each part of an import now asks for the permission for what it writes, and names anything it left out in the summary. The rest of the case still arrives. Every shipped role that can import holds all of these, so a standard installation sees no change.
- IOC enrichment history ignores DNS answer rotation: DNS servers rotate the order of records between lookups. The enrichment history read a reordered answer as changed data and recorded a snapshot, so a domain with several addresses collected meaningless history entries. DFIRe now stores the records in a fixed order.
- Jira sync no longer drops freshly exported issues: Jira's search index lags issue creation by a few seconds, so syncing a case shortly after exporting to Jira could mark the new issue links stale and stop tracking them permanently. The sync now confirms with a direct read before it gives up on a link. It still marks a link stale when Jira no longer holds the issue.
- Downloadable default settings file is current: The copy offered for download in the documentation was several releases out of date, so an administrator who imported it to reset the shipped roles got permissions DFIRe no longer uses, and none of the newer ones. The download is now the same file the product installs from.
- Error messages survive proxies: When an external dependency fails (Jira, the license server, an AI provider, or a Direct Storage backend), the API now answers 503 Service Unavailable instead of 502 Bad Gateway. Proxies such as Cloudflare replace the body of a 502 response with their own error page, so installations behind one saw a generic gateway error instead of the actual message. An out-of-range retry count or circuit breaker threshold in the audit forwarder settings now answers with a validation message instead of a server error.
Removed
- Unfinished IOC correlation-request API: It had no interface and never finished its response workflow, and DFIRe already covers the need: adding an indicator that exists in another case notifies you of the match. The "IOC Correlation Requests" permission no longer appears in role settings.
1.7.3 — August 15, 2026
Added
- Secure Development Documentation: A new page describes the automated checks every change to DFIRe passes before release, and how findings that are reviewed and accepted rather than fixed are recorded. See Secure Development Lifecycle.
Security
- Crafted Text No Longer Slows Slack Rendering and Indicator Import: Text built to defeat pattern matching could hold a background worker for several seconds. A case note on its way to Slack, an imported STIX pattern, and a Slack channel name template were each affected. Processing time now grows in step with the length of the input. DFIRe converts a markdown link for Slack only when its label is under 500 characters and its target under 2000. Longer ones stay as written. See Integrations.
- Unexpected Failure Details Are Shown Only to Superusers: When a Jira user search or a CSV import row fails unexpectedly, DFIRe now shows a reference code instead of the underlying error text, which could name internal hosts or database details. A superuser still sees the full message, and the reference code finds it in the server log. See Integrations.
- Webhook Address Blocking Covers Mapped Addresses: A webhook destination written as the IPv6-mapped form of a blocked address, such as the cloud metadata service or the local machine, is now refused like the address itself. Private network destinations remain allowed. See Webhooks.
Fixed
- Offline License Import Works Again: DFIRe could not import an offline license in releases 1.7.0 to 1.7.2. Upgrade to 1.7.3 if you use offline licensing.
1.7.2 — August 13, 2026
Security
- The Stored Jira Token Is Masked Wherever It Is Returned: DFIRe now masks the saved Jira API token in the collaboration settings response. It shows only the few characters that identify which credential DFIRe holds. That response previously returned the token in full. Only administrators can read either settings response, and no stored token changes. See Integrations.
- An Indicator Collection Marked Not Readable Is Now Refused: A TAXII collection with its read permission off no longer serves its indicators or its manifest. DFIRe reported the permission correctly but never applied it, so any key that could reach the collection could read it. A collection created in Settings stays readable, as before. See IOC Management.
Changed
- Exported Objects Use the Standard STIX Identifiers and Markings: DFIRe now identifies an observable by its value, as STIX 2.1 defines. Any platform following the standard derives the same identifier, so a consumer can match an indicator it already holds. Bundles and the TAXII feed now reference the four TLP marking definitions the standard defines, and exported bundles carry those definitions. TLP:AMBER+STRICT travels as TLP:AMBER, the closest marking STIX 2.1 can express. Every observable identifier and marking reference changes once with this release. Update a consumer that matched the old ones, and resynchronize a TAXII client that caches them. Indicator objects keep their identifiers. See IOC Management.
- TAXII Responses Follow the Standard: A page size now counts objects
rather than indicators, so a client asking for 100 objects receives at most 100. DFIRe
caps any response at 500 objects and offers the rest as a further page. Filtering by type,
identifier, object version or specification version now selects what the client asked for.
An empty collection list, object list or manifest omits the list rather than sending an
empty one. DFIRe sends collection dates as
x_dfire_createdandx_dfire_modified, because TAXII 2.1 reserves the unprefixed names. Update a consumer that reads the old names. See IOC Management.
Fixed
- Exported STIX Validates Against the Standard: Bundles from a case, the registry, a bulk export and the TAXII feed now pass validation against the STIX 2.1 schemas, as do the STIX objects in IOC webhooks. Timestamps carry the format the standard requires, and a Windows path or registry key no longer ends its pattern early on a backslash. Directory, mutex, software, user account, registry key and X.509 certificate indicators carry the properties their object types define, instead of a custom field no consumer reads. DFIRe leaves out network traffic, artifact and email message indicators, which it cannot express as valid STIX. Use the CSV export when you need every indicator regardless of type. See IOC Management.
- An Imported STIX Bundle Keeps Its Classification, Confidence and Tags: DFIRe reads those three from the Indicator objects that describe an observable, on both the case IOC tab and the global registry. Every STIX import used to land as Unknown with Low confidence and no tags, including a bundle DFIRe had exported itself. A bundle carrying Indicator objects and no observables now imports the values from their patterns. That shape, which many threat intelligence feeds publish, used to import nothing and report success. See IOC Management.
- Collecting From TAXII Is Reliable: A consumer that collects indicators page by page now receives all of them. Indicators recorded at the same instant could fall on both sides of a page boundary, and DFIRe never sent the ones after it. Asking for a page larger than the cap now returns indicators, rather than a progress record no standard client could read. Exceeding the request rate now answers 429, so a consumer waits and retries instead of stopping as though DFIRe had rejected its key. See IOC Management.
- A Compliance Timer Keeps the ID It Was Created With: The API now refuses a change to a timer ID, matching the settings screen, which has always disabled it after creation. DFIRe used to create a second timer whenever an update carried a different ID, keep the original, and report success under the new one. Everything else in the update still applies. See Compliance Timers.
- The Import Summary Names Only the Evidence That Lost a Chain of Custody: DFIRe leaves the chain of custody out when it imports a case file from another installation. The summary now names only the evidence that arrived carrying one. It used to name every evidence item in the file, including evidence that never had a handover. See Dashboard.
1.7.1 — August 11, 2026
Fixed
- Saved Text Is Kept as Typed: A case called "M&A" now reads "M&A" everywhere, and a category or verdict description shows the "<" that was typed. DFIRe HTML-encoded saved text, so those characters read back as codes in the case header, in lists and in every edit box. Case titles, evidence flag names, timeline entry titles, legal entity contact details, and category and verdict descriptions now store exactly what was entered. Text saved before this release keeps its encoded form until the field is edited and saved again.
- The First Sign-In Profile Screen Is Shown Once and Fails Cleanly: The screen now sends an account that is already set up back to the dashboard, instead of offering a filled-in form it can only refuse. A first or last name past the length limit gets a clear message rather than a server error. The screen saves a chosen profile picture only after it accepts the form, where it previously uploaded the picture first, even when the submission then failed. See Single Sign-On.
- Compliance Timers Read from the Clock: A timer that runs out while a screen is open now reads as breached straight away, everywhere the timer appears. Dashboard cards also show the time left as it stands, and drop a timer once its deadline passes. Screens previously showed the figures from the last load, so a countdown could sit at zero, or a finished timer could read as active, until the page was refreshed. See Compliance Timers and Dashboard.
- Pasted Single Sign-On Values Keep No Stray Spaces: DFIRe now saves a provider's client ID, client secret, discovery URL and sign-in base URL without any space copied along with them. A value pasted with a leading or trailing space was stored as pasted. Every sign-in through that provider then failed, with nothing on the settings screen to show why. See Single Sign-On.
- Each Search Filter Matches One Category: On the search screen, Case now shows only cases and Item only evidence items. A note written on a case was previously listed and counted under Case, and a note on an evidence item under Item. Notes of both kinds still gather under Note. See Global Search.
- Evidence Pickers Say When Their Lists Are Still Loading: The pickers in Add Evidence and Add Related Evidence now say when their lists are loading, and fill in without the window being closed. On a slower connection they opened as empty lists, with nothing to say why. A list that failed to load looked the same as a system with nothing configured, and a failed load now says so. See Evidence Items.
- Imported Settings No Longer Move the Backup Target: Importing a configuration file leaves this instance's database connection settings for backup and restore alone. A file written on another installation carried that installation's connection details. Importing it pointed this instance's backups at the other system's database, with nothing in the import summary to show it. See Configuration.
- Workflow Branches That End the Action: An answer set to end the workflow now completes the action, rather than leaving behind a follow-up action with an unreadable name. The break affected workflows written by an assistant over the MCP server and workflows carried in an imported case. Actions already saved this way now finish correctly, with nothing to re-enter. See MCP Server.
- The API Schema Matches What These Endpoints Return: A client generated from the published schema could not read the case, dashboard statistics, or user list responses as documented. The schema now records what the API returns: no phase on an investigation case, incident times that stay empty until the incident is declared and resolved, counts rather than a case from dashboard statistics, and a definite answer on whether an account signs in without a password. It also records that the incident times cannot be cleared through the API. An account that has never saved preferences now reads as an ordinary password account, instead of leaving those fields blank. See API Access.
Security
- Usernames Are Chosen Once at First Sign-In: The profile screen shown at first sign-in accepts a username only during the sign-in that created the account, and writes the chosen name to the audit log. The screen previously stayed open to the account for its whole life, so any signed-in user could rename themselves at any time, with the change recorded nowhere. A username is an identity: the audit log records it with each entry, and an imported case matches its team by it. Later changes go through a user administrator, and the screen now rejects usernames the rest of DFIRe would not accept. See Single Sign-On.
- Text From Slack Forms Is Handled Like Text From the Web App: Text submitted from a Slack form is now cleaned exactly as the same fields are in the web app. What DFIRe posts back to Slack no longer carries the characters Slack reads as markup, so only the links DFIRe builds are links, and names read as typed. Previously DFIRe stored the text as typed and posted it back into the case channel. A case member could therefore write a link or a channel-wide notification that appeared to come from DFIRe itself. See Integrations.
1.7.0 — August 9, 2026
Added
- Tamper-Evident Chain of Custody: Every custody entry now carries a SHA-256 hash
covering its contents and the hash of the entry before it, so altering a recorded handover
changes its hash and every hash after it instead of passing silently. The Custody tab recomputes
the chain and reports whether it still matches; a chain that fails verification names the entry
it failed at and accepts no further transfers for that item until it is reviewed. Hashes are
shown per entry, printed on the custody receipt and included in the audit record for each
transfer, Download JSON exports a chain that can be checked outside DFIRe with
the published verification script, and administrators can
check every chain on the server with
manage.py verify_custody_chains. Existing custody records are hashed during the upgrade, in the order they have always been displayed. See Evidence — Chain of Custody. - Gemini Enterprise Agent Platform Provider: Gemini models can now be reached through Google's Agent Platform, formerly Vertex AI, in your own Google Cloud project, alongside the existing Google Gemini provider. It authenticates with a service account key file uploaded in Settings → AI / LLM rather than an API key, and the model, location and project are yours to set; leaving the project empty uses the one the key file belongs to. The key file is encrypted in full at rest, the settings screen shows only the service account's email address and project, and a connection can be tested with a newly selected key before it is saved, so a key can be rotated without risking the working one. See AI Integration.
- Knowledge Base over MCP: AI agents can browse, read and write the Knowledge Base through a new Knowledge Base tool group on the MCP server, so a procedure can be explained or applied mid-case and new pages drafted from a prompt. The view permissions and access groups apply to an agent exactly as they do to the person whose API key it uses, password-protected pages and folders are not reachable through MCP at all, and agents cannot delete Knowledge Base content. Knowledge Base pages now also appear in the agent's global search, matching the application's. If you have set the MCP tool-group toggles before, the new group starts disabled: enable it in Settings → Integrations → MCP Server. See Knowledge Base — AI agents.
- Folding Dashboard Cards: The caret on a dashboard case card folds it down to a single bar carrying the title, severity, case number and status, and Collapse all and Expand all apply that to every case listed, so a long list can be read one line per case. Cards also carry a status tint across the top, green while a case is open and grey once it is closed or archived. Cards open expanded. See Dashboard.
- Page Background: A Background setting in the user menu adds an optional slow colour wash behind the application. It is off unless you turn it on, and the choice is remembered for the browser you set it in rather than for your account, so enabling it on your own machine does not change how DFIRe looks on a shared or remote one. Systems set to reduce motion get a still image instead of an animation. See Personal preferences.
Changed
- Upgrading Must Be Asked For: The installer now changes an existing
installation only when it is run with
--upgrade. Run without it in a directory that already holds one, it reports the installed and the current version, changes nothing and stops, so an installer run can no longer upgrade a deployment by surprise. A specific release is selected with./install.sh --upgrade 1.7.0, replacing--versionfor that purpose, and a first installation into an empty directory still needs no flag. The interactive setup has also been rewritten to be readable while it runs. See Updating DFIRe. - What the Audit Log Shows: The audit log now shows every kind of record it holds to the people entitled to read it. Changes to projects, legal entities, runbooks, indicators, evidence types and other shared configuration appear for anyone whose role can read that kind of record rather than for administrators only; indicator associations were missing from a case's trail entirely; and for anyone without permission to see all cases the log also left out notes, item notes, timeline entries, compliance timers, custody transfers and reports, which is what most investigators saw. Filtering by any of those record types returned nothing. The records were always written and what each person may see is otherwise unchanged: case records still appear only for cases they have access to, account, API key, role and system configuration history stays with administrators, and a role without the View auditlog permission continues to see no audit entries anywhere. See Audit Log.
- Chain of Custody Rules: A chain must now begin with an intake on every interface; the API and MCP previously accepted one that opened with a handover from nobody, while Slack already refused it. An intake can no longer be recorded while an item is already held, because an intake names a new custodian without either coming from the current one or carrying the note a correction requires, so repeated intakes were a way to change the recorded custodian silently. Recording a further intake is still how re-acquisition after a release is captured. The custodian a transfer or release must come from is now the recipient of the most recently recorded entry rather than the one with the latest transfer time, which differ only when a handover is recorded after the fact; entries are still listed by transfer time, with the order they were added shown alongside. See Evidence — Chain of Custody.
- Case Import: Importing a case no longer sends outbound webhooks, and the option to enable them during import has been removed, because an import could otherwise deliver hundreds of notifications for activity that had already been reported when it originally happened. Automation rules still run on imported cases. A case exported from a different installation now arrives without its chains of custody, and the import reports which items were affected, because a chain identifies the people and organisations that held the evidence by their identity on the system that recorded them, and those identities cannot be matched elsewhere without asserting handovers that may not have happened. Importing a case this installation exported itself, including after restoring a backup to a new host, is unaffected; use Download JSON on an evidence item to keep its chain verifiable alongside an export sent elsewhere.
- Incident Duration and MTTR: Incident duration now measures the incident, not
the case. It runs from the moment the incident was declared, by escalation or by creation for
cases opened directly as incidents, until the incident reaches the final phase, with closure as
the endpoint for incidents closed unresolved; previously the clock started when the case was
opened, so a case escalated after days of investigation reported those days as incident time.
The declaration and resolution timestamps are editable in Edit Case, the
sidebar, printed reports and CAN report all show the same figure, and a report printed after a
case closes no longer shows a duration that kept growing. The dashboard, analytics and MCP MTTR
figures now share one definition, the average time from declaration to resolution across
incidents resolved in the period, where the three surfaces previously computed different
figures from case creation and closure times and included investigations. Reopening a closed
case no longer resets the incident phase to the first phase, the phase name
Inactiveis reserved and can no longer be given to a phase, and existing incidents are migrated using their recorded escalation time where one exists. See Analytics. - Playbook and Runbook Editors: Playbooks and runbooks are now written on full pages instead of in dialogs. Each runbook step is a card showing the instruction and details the way an investigator will read them, both fields grow as you type so a long instruction wraps in full, an outline down the left lists the steps and marks any that are still unfinished, steps reorder by drag or from the keyboard, and the webhook trigger tag has moved into each step's own menu. A runbook cannot be saved while a step is missing its instruction, and the editor says how many are outstanding rather than reporting it only on save. Runbooks can now also be cloned from the Runbooks list, as playbooks already could, and the playbook designer no longer collects a description and an icon that were never shown anywhere. See Runbooks and Playbooks.
- Interface Consistency: Case, evidence and indicator screens now draw their buttons, fields, tables and file lists from one shared set of components, so controls that do the same thing in different places look and behave the same way. File sections on cases and evidence items expand from the same place, long-form notes and descriptions open in a roomier editor with a preview, and deleting a note asks for confirmation first. Controls now carry names for keyboard and screen reader use throughout, and switching between light and dark mode no longer nudges the page width, which it did because dark mode reserved scrollbar space that light mode did not.
- Bulk Indicator Actions: Publishing, revocation, classification, confidence and TLP are now chosen together in the bulk toolbar and committed with Apply, so a set of changes takes one confirmation instead of one per category. Markings are written before publishing, so raising indicators to TLP:RED in the same action stops them from being published. See IOC Management – Bulk operations.
- Attachment Item Linking: A Secure Storage attachment uploaded to a case can still be linked once to an evidence item in that case through the API. An existing item link can no longer be removed or changed, and Direct Storage associations remain fixed to their storage path. Editing attachment metadata or linking an attachment now writes its audit record in the same transaction, so an edit is rolled back rather than committed without one. Installation superusers retain Django admin access for emergency corrections.
Removed
- Generated Report Update Endpoint:
POST /api/cases/{id}/update-report/has been removed. It edited a case's generated reports, a surface no longer reachable in the application, and it was the one case endpoint that did not respect the write protection on a closed or archived case. Stakeholder reporting is the Case Report, which is unaffected. Scripts calling this endpoint will receive 404.
Fixed
- AI Provider Settings: Several settings on the AI screen did not hold or did not report what they had done. Temperature and max tokens can be cleared again, handing the decision back to the model, where an emptied field previously kept the last saved value, and a max tokens figure too low to hold an answer is now refused at save rather than silently truncating every report and chat reply. Turning off the provider selected as the active LLM API, or removing its credential, now clears the selection instead of leaving AI pointing at a provider that is switched off, and saving with AI enabled and no working provider is refused. A connection test now has the five minutes it was always meant to allow instead of failing after one, its verdict belongs to the settings it was run against and names the model that answered, and the usage table shows when each provider's totals started accumulating and can be reset to begin a new period. Affects all providers. See AI Integration.
- Long Direct Storage Uploads No Longer Stop at 24 Hours: A Direct Storage upload that was still running a day after it started was rejected from that point on and had to be restarted from the beginning, which a disk image over a slow link could never get past. An upload now stays valid for as long as it keeps making progress, and the 24-hour limit applies only after an upload stops sending data, so an abandoned one is still cleaned up. An upload that is rejected because it did stop for that long now says so, instead of reporting only that the session is no longer active. See Storage.
- Compliance Timers: An investigation could start a compliance timer that then appeared nowhere but the Compliance tab, because the case sidebar listed timers only for incidents. The sidebar now shows running timers and breach warnings on every case, in both its collapsed and expanded forms, and a timer past its deadline says Breached and names the deadline it missed. A warning or breach now notifies everyone assigned to the case rather than the lead investigator alone, so a case whose lead had been cleared reaches the rest of the team instead of notifying nobody. The phase and duration displays remain specific to incidents. See Compliance Timers.
- Severity and Lead Investigator Changes on the Timeline: Changing a case's severity now records a timeline event naming the old and new values; severity was the one key case change that left no trace, even though automation rules and webhooks already reacted to it. A change of lead investigator is now recorded wherever it is made, including changes made through the Slack case editor or by an automation rule that sets or clears the lead, which previously left no entry. Automated changes are attributed to Automation. See Timeline.
- Deployment on Windows: The release bundle now starts on Windows. Docker Compose
separates the files listed in
COMPOSE_FILEwith a semicolon on Windows and a colon elsewhere, so the colon in the shipped value made Compose on Windows read the whole value as a single filename and stop with a file-not-found error before any container started. The environment file now sets the separator explicitly, which behaves the same way on every platform. Linux and macOS deployments are unaffected, and the installer writes the setting into the environment file on its next run. See Deployment. - First Login: The profile form shown at first sign-in no longer asks for a Slack ID. A Slack account is linked automatically when one matches the signed-in email, so anyone who left the field blank was told nothing had been linked while the link had already been made, and anyone the match misses can still link from user settings or from Slack.
- Configuration Import: Importing a configuration file whose incident phases sit in different positions than the ones already on the instance failed with a database error and applied nothing, so the import could only be completed by deleting every incident phase by hand first. Phases are now matched by name rather than by position, which also means a case stays in the phase it was in when an import moves that phase up or down the list. Workflow steps that share a position no longer stop an import either. The preview now names the phases an import would remove and what removing them costs, rather than only counting them. See Configuration.
- Playbook Entries of a Deleted Lifecycle Phase: Deleting an incident phase left its playbook entries attached to a phase that no longer existed. They disappeared from the playbook editor while still being saved back with it, so they could not be found or recovered, and recreating a phase with the same name did not bring them back. Deleting a phase now returns its entries to Unassigned, in playbooks and in the checklists of open cases, where they can be given a phase again. Entries orphaned by an earlier deletion appear in Unassigned as well. See Playbooks.
Security
- File Permissions Now Take Effect: The evidence file permissions in the Role Editor are enforced on every upload, download, cancel and storage-sync route. They were checked on the file list and on deleting a file, but not on the routes that transfer the bytes, so a role granted case access without Create attachment could still upload, and one without View attachment could still download from Direct Storage. Case membership was always required and is unchanged, so a user could never reach a case they were not on. Roles that were meant to upload or download already hold these permissions, including every role DFIRe ships; a custom role built by clearing them will now be held to them. View Only keeps read access to files and gains no write access. See Application Security → File Permissions.
- Who May Issue an API Key for Someone Else: The Edit userapikey permission no longer reaches every account. A key authenticates as the account it belongs to, so a role holding that permission could create one on any account, read it once, and act as that account, including System Root. Superuser accounts are now closed to everyone but another superuser, and the permission can issue keys only on service accounts; on ordinary accounts it can still list, edit, disable and delete the keys that exist, but not create or regenerate one. Their keys are also no longer listed to anyone else. Creating your own keys is unchanged. See API Access → Admin Key Management.
- Service Accounts Are One-Way: Marking an account as a service account can now only be undone by a System Root user, and changing the setting in either direction deletes every API key the account holds. Because a service account is the one kind of account a key administrator may issue keys for, a reversible setting meant the status could be switched on to obtain a key and switched back off afterwards. Converting an account now takes its password and SSO login away for good and ends its open browser sessions at once, rather than letting a window that was already signed in carry on, so the change is immediately visible to whoever uses the account. Every conversion is recorded in the audit log against the account, the person who made it and the API key they used if they worked through the API. Setting up an integration is unaffected. See API Access → Service Accounts.
- Password-Protected Knowledge Base Folders: A page left unencrypted inside a password-protected folder is now covered by that folder's password on every route. Such a page was hidden from listings, the tree and search, but could be read in full, and deleted with its version history, by anyone with the ordinary Knowledge Base permissions who knew its address. Pages created inside a protected folder in the normal way were never affected. See Knowledge Base.
- Sessions End When a Password Changes: Changing a password now ends open real-time connections as well as browser sessions. A connection opened before the change stayed authenticated until it was closed for another reason, so a session an account holder meant to revoke by changing their password could keep receiving live case updates. Connections are now checked against the current password both when they open and while they run, matching what the rest of DFIRe already did.
- AI Provider Error Messages: Errors returned by an LLM provider are scrubbed of credential material before they reach the screen, the application log or the audit trail. This now applies on every AI feature rather than only the connection test. Providers are not known to quote credentials back, so this closes a gap rather than a leak.
- Slack Commands Need a Linked Account:
/dfirecommands now require the Slack account running them to be linked to a DFIRe account. Being in a case channel was enough to read case status, the team, recent timeline activity, evidence and indicators out of DFIRe with no DFIRe account at all, and nobody to record the request against. Only/dfire help,/dfire linkand/dfire whoamiwork unlinked, and the refusal tells the user how to link. SSO users are linked automatically and are unaffected. See Integrations — Account linking. - Indicator Tags Are Cleaned Everywhere: Tags are stripped of markup on every route that writes them: the indicator form, bulk tagging, the STIX and CSV imports, enrichment results, and the Slack edit form. Tags arrive from files and threat intelligence feeds outside your control, and only one route cleaned them, so a crafted tag could be stored and shown as-is wherever indicators are listed. Over-long, blank and duplicate tags are dropped on all routes as well. Existing tags are unchanged. See IOC Management.
- CSV Exports Open Safely: The bulk indicator export now neutralises cells that a
spreadsheet would otherwise run as a formula, which every other CSV download in DFIRe already
did. An indicator value, tag or note beginning with
=came from a feed or an import as often as from a person. Every CSV download also now covers the case where the formula follows a line break instead of starting the cell. The indicator export additionally gains the byte marker that makes Excel read it as UTF-8, so accented characters and multi-line notes open correctly.
1.6.0 — July 29, 2026
Added
- Blocked Actions: An action that cannot proceed can be marked blocked, with a note naming what it is waiting on. A blocked action keeps its place in the Actions tab, marked in red with the reason shown, and still counts as outstanding work. Unblocking returns it to what it was doing before. Blocked work carries through to Slack, Jira and the MCP server. See Incidents — Blocking an Action and Integrations.
- Daily Summary: A new Dashboard tab giving an at-a-glance picture for a shift handover or morning standup. Open cases are counted by severity, and each one states where it stands without being opened: its phase, its lead investigator, what moved in the last 24 hours, what is still open and what is blocked. Cases with a missed or approaching compliance deadline are marked. When AI is configured, it can write a short brief over the whole view, which can be copied or printed. See Dashboard — Daily Summary.
- Recovery Screen for Interface Errors: When a page stops drawing because of an unexpected error, DFIRe now shows a recovery screen instead of a blank page. It offers to reload or return to the Dashboard, and lists the technical detail with a Copy details button for support requests. The detail never includes account or session information.
Changed
- The MCP Server Now Matches the Web App and the API: Every change made through the MCP server is recorded in the audit trail against the object that changed, listing the fields that changed, and is written to the server log stream for deployments that forward logs to a SIEM. Tools that create or edit records now apply the same validation as the rest of DFIRe, so cases, teams, actions, evidence, timeline events and reports behave the same however they are reached. The tool for deleting an action has been removed, matching the web app and the API, which have never allowed it; skip the action instead. See MCP Server.
- The Dashboard Names Your Account and Roles: The Dashboard heading states the account you are signed in as and the roles it holds, so you can confirm your own access without opening Settings. See Dashboard.
- Evidence Hierarchy Loops Are Refused Everywhere: An evidence item can no longer be placed underneath one of its own children on any route into DFIRe, including case import. A loop hid the items in it, and everything below them, from the Evidence tab. A move refused in the Evidence tab now says why.
- Bundled Redis Updated to Redis 8: Deployments that use the published Compose files move from Redis 7 to Redis 8 when they upgrade. No configuration change is needed. See Deployment.
- Docker Compose 2.24.4 or Newer Is Required: The installer checks the Docker Compose version before making any change and stops with the version it found if it is older. Upgrade Docker Compose first on a host that is behind. See Deployment.
- Installer Updated for the New Release Workflow: The root
install.shnow downloads and verifies the current versioned release bundle. The same installer supports new installations, managed upgrades, and adoption of eligible existing deployments. See Deployment.
Fixed
- Restoring a Backup from an Older DFIRe Version: Restoring a backup taken by an
earlier version could fail with
Broken pipeand leave the restore unfinished. Restoring an older backup now works: the snapshot is restored as it was, then the database migrations for the running version are applied to bring it up to date. A restore that fails for any reason now leaves the existing database exactly as it was, and reports the underlying database error rather than a broken pipe. Restore also clears everything in the database'spublicschema, so DFIRe must have a database to itself; on a customer-managed PostgreSQL where DFIRe connects as a role that does not own that schema, the restore now stops before making any change and says so. A backup can only be restored onto the PostgreSQL major version it was taken on or a newer one, which PostgreSQL itself requires; DFIRe now checks this before touching the database and names both versions instead of failing part-way. See Backup & Recovery. - Validating a Backup Now Tells You Whether It Can Be Restored: Validation used to report success whenever the file decrypted, even when a restore would have failed. It now answers one of three ways: verified and restorable, cannot be restored on this server with the reasons listed, or could not be fully verified. It shows the PostgreSQL version the backup was taken on next to the version this server runs. Restoring onto a newer PostgreSQL major version is supported, so a backup and a restore can be used to move DFIRe onto a newer database server. See Backup & Recovery.
- Backup Commands Report Failure Properly: The command-line backup tools
used to print an error and still exit as though they had succeeded, so a recovery script
could not tell that a backup or restore had not happened. They now exit with a failure
code. A new
validate_backupcommand gives the same answer as the Validate button for installations where the web interface is not reachable, andrestore_backuprefuses a backup that cannot be restored on this server instead of attempting it. See Backup & Recovery. - Case Exports Carry the Chain of Custody, and Are Not a Backup: An exported case now includes each evidence item's chain of custody and runbook progress, and restores both on import. Neither was included before, so a case moved between installations arrived without the record of who held its evidence. An export has never contained uploaded file contents or the keys that decrypt them, and the documentation wrongly said it did: deleting a case still deletes its files, and importing an earlier export will not bring them back. Use Backup & Recovery to protect against data loss, and see Dashboard — Import Case.
Security
- The MCP Server Enforces the Same Permissions as the API: Every MCP tool now requires the permission its equivalent requires on the API, rather than a broader case or indicator permission. Reads that were over-restricted no longer demand edit permission, and reads that were under-restricted are now gated: most exposed was the reference data lookup, which returned every role with its full permission list to any authenticated caller. Disabled accounts, search results, timeline deletion, report access, action assignment and IOC publishing are all now limited as they are elsewhere. Pulling a full case dump is recorded as an export in that case's audit trail. Review any custom role used by an MCP client after upgrading. See MCP Server.
- IOC Exports Enforce View and Export Permissions: Global, bulk and case CSV and STIX exports, including the legacy bulk STIX route, now require both permission to view indicators and the dedicated indicator export permission. Manual STIX exports include published and unpublished records; TAXII and MISP publication behavior is unchanged. Explicit read permissions now also cover HEAD and OPTIONS requests.
- Hidden Cases No Longer Disclose Membership or Existence Through Auxiliary Endpoints: Slack mention availability and the case timeline, evidence, notes and actions exports now resolve cases only through the signed-in user's visible case set. Hidden and nonexistent case identifiers produce the same result on each endpoint.
- Slack IOC Publish and Unpublish Require Indicator Management Permission: Making an indicator available through TAXII and MISP, or removing it from those feeds, from Slack now requires the same indicator management permission as the web app, API and MCP server. The IOC addition or other edits still complete when the sharing change is refused, and Slack explains why it was skipped.
- Changing a Case Team Requires the Manage Case Teams Permission: Adding or removing investigators and viewers, and changing the lead investigator, now require the manage case teams permission on every interface. It previously took effect only over the MCP server, so a role that could edit cases could change team membership through the API. Every built-in role that can edit cases already has this permission; a custom role built without it can no longer change team membership.
- Publishing an IOC While Adding It to a Case Follows the Normal Publishing Rules: The shortcut that publishes a new indicator to the TAXII and MISP feeds as it is added to a case now requires the indicator management capability, and no longer publishes TLP:RED indicators. It previously required only permission to add IOCs to a case, and direct API callers could publish TLP:RED through it. The indicator is still added to the case when publishing is declined.
1.5.5 — July 23, 2026
Added
- Scheduled Jobs View With a Login Warning: A new read-only Settings → Scheduled Jobs tab (superusers only) lists DFIRe's background jobs with their last and next run times and a Success, Failed or Overdue status. When the schedules are missing altogether (typical after restoring a database backup without restarting the containers) or overdue, every user is warned once per session after login, because scheduled backups and retention silently stop in that state. Restarting the DFIRe containers re-registers the schedules.
- Relink Files After a Storage Target Is Deleted: Deleting a storage target leaves the files in the bucket or share untouched, and the file records can now be reconnected: re-create the target with the same settings and use Relink files on its row in the Storage tab. DFIRe verifies that each file's object actually exists on the target before restoring its link and reports what was found. Importing a configuration backup now keeps matching storage targets in place, so file links also survive a configuration import instead of being orphaned. See Storage.
Changed
- System Settings Redesigned: Every tab in System Settings has been rebuilt on one design pattern: settings are grouped into titled sections that save independently, a save bar appears only when a section actually has unsaved changes, and the case-property catalogs (playbooks, evidence types, runbooks, projects, flags and the rest) share one consistent table layout. User accounts now open in a detail dialog that edits in place, replacing the side drawer. Ordered lists, such as evidence workflow stages, incident lifecycle phases, and runbook steps, are reordered by dragging. Closing a dialog that holds unsaved input asks before discarding it, and so does logging out with unsaved changes anywhere in the app.
- Webhooks Get Their Own Page and Permission: The webhook editor moved to a full page with room for the payload, header, and secret configuration, and webhook management is now granted through the webhook permissions in the Role Editor. A role can be allowed to manage webhooks without holding full system-settings access; previously webhook management required tenant administration rights.
- Settings Sections Are Granted Individually: Every settings section is now
reached through its own permission in the Role Editor rather than through a single
system-settings permission. Automation is granted by the automation rule permissions and user
administration by the user permissions, joining webhooks and the case-property catalogs.
System-wide configuration (storage, single sign-on, integrations, backups and licensing)
stays with the superuser and cannot be delegated. The old "System Settings" permission no
longer grants anything and has been removed from the Role Editor.
Action required: roles that relied on the old permission for automation or user administration lose those sections until a superuser grants the matching permissions in Settings → Access Roles. New installations get them in the DFIRe Admin role automatically. - Message of the Day Is Controlled by Its Content: The login-screen message is shown when the field has text and hidden when it is empty; the separate on/off toggle is gone. A hidden draft left behind by an older release is cleared on upgrade so it cannot publish unexpectedly on a later edit.
- Entities Tab Removed From Settings: Entities are managed on the Entities dashboard; the duplicate management tab in System Settings is gone.
- User Email Addresses Must Be Unique: Creating or editing a user with an email address another account already holds is now rejected, regardless of letter case and including disabled accounts. Duplicate addresses made single sign-on and Jira and Slack user matching ambiguous for everyone sharing the address. Accounts without an email address are still allowed.
- Unified Secrets Handling in the Settings API: Stored secrets across the
settings endpoints (webhook credentials, storage target credentials, Slack and Jira tokens,
SSO provider secrets, LLM and IOC enrichment API keys, and audit log forwarding headers and
passwords) are now returned as masks instead of
being hidden or masked inconsistently: long machine tokens show their first and last four
characters for identification, and passwords show a fixed mask that reveals nothing. On
write, the same rules apply everywhere: omitting a secret field keeps the stored value,
sending back the exact mask keeps it, an empty string clears it, and any other value
replaces it. In the Settings screens, a configured secret shows its mask in the field
placeholder while the field itself stays blank.
Breaking for API clients: sending an empty string for a storage target credential now clears it; it previously meant "no change". Omit the field to keep a stored credential. Empty strings sent to the IOC enrichment settings now also clear the stored key instead of keeping it. - Release Quality Strengthened: Release testing, security and quality gates have been hardened.
- Immutable Docker Compose Releases: Versioned deployment bundles now publish digest-pinned Compose files, checksums, and an annotated environment reference. The lean installer uses the same files as a convenience wrapper and automatically installs, adopts, upgrades, or confirms an existing installation.
Fixed
- Audit and API-Key Client IPs No Longer Trust Forwarded Chains: Audit records,
session metadata, API-key lockouts, and other request attribution no longer accept the
attacker-controlled leftmost value from
X-Forwarded-For. DFIRe now accepts only a validX-Real-IPwhen proxy trust is enabled and otherwise records the direct socket peer. Self-hosters remain responsible for overwriting that header at their trusted proxy boundary and blocking direct backend access. - Weekday-Only Compliance Timers Are Honored: The "weekdays only" option on compliance timers had no effect: a weekday timer still counted every wall-clock hour, including weekends, so it breached at the same moment as a normal timer. Weekday timers now accrue time only Monday through Friday (UTC) everywhere a deadline is computed or shown: the case view, Slack, the MCP tools, the breach checker, timeline events, and case export. Weekday durations are labeled "(weekdays)", and the countdown ticks on weekdays and holds still over the weekend.
- Late Timer Completion Records the Breach: Completing a compliance timer after its deadline through the web app or the MCP tools now marks it breached at completion. Previously the breach flag depended on the periodic breach check having already noticed, so a timer completed shortly after its deadline could be recorded as met. Completing from Slack already recorded the breach.
- New Incidents No Longer Report a False Escalation Over MCP: Opening a case directly as an incident through MCP now records only the case-created event. It previously also recorded an investigation-to-incident escalation that never happened. The new-case webhook and case-opened automation still run once.
- Backup Schedule Changes Take Effect Immediately: Changing the backup schedule now moves the next run to match the new settings; previously the old time stuck, so switching from nightly to hourly still waited for the old nightly slot. Weekly backups also ran one day earlier than the selected weekday, and the every-2-days option ignored the selected time of day. The number of backups to keep now accepts up to 999 and is validated by the server; the form previously lowered larger stored values to 100 without saying so.
- Retention Runs Shown Truthfully: The Retention Policy tab shows the actual last and next run of the retention job instead of claiming it runs daily at 00:01, and warns when the retention schedule is missing, for example after a database restore.
- Jira User Mapping Review Hardened: A display-name match can no longer confirm a user mapping on its own; only an exact, visible email match links automatically. Every name-based candidate now appears for review, including several same-named people proposing the same Jira account, and confirming one dismisses the rest. Previously one candidate could be linked silently while the right person was skipped without a trace. The review table shows each candidate's DFIRe email so same-named people can be told apart, the Jira column shows only what Jira actually returned, and a rejected suggestion keeps the name and email it was proposed for instead of turning anonymous.
- Slack Timer Completion for Administrators: Marking a compliance timer met from Slack was refused for superusers and holders of edit-all-cases rights who were not on the case team, even though the web app and the API allowed it. Slack now applies the same permission rule as the other surfaces.
- SMB Direct Storage Uploads to New Files Restored: Starting a Direct Storage upload to SMB incorrectly treated a missing destination file as a storage failure and stopped before uploading any data. A missing file is now recognized as an available destination, while permission, connection, and protocol errors still stop the upload safely. Existing files remain protected by filename collision handling. (#828)
- Smaller Fixes: An expired API key can no longer be regenerated. The MCP Server tab shows an error instead of a blank default form when the stored settings fail to load, so defaults cannot accidentally overwrite the real configuration. Compliance timer durations are capped at 1,000,000 hours; larger values crashed the timer display. Buttons inside dialogs no longer submit the surrounding form by accident.
Security
- Direct Storage Uploads Cannot Overwrite an Existing Object: Finalizing an S3 Direct upload now creates the object conditionally, so the storage service itself refuses to replace a file that already exists at the same path. DFIRe never deletes or claims an object it cannot prove it created; each upload stamps a per-session ownership token into the object's metadata as that proof, and conflicting objects are preserved and recorded in the audit log. Providers that ignore the condition (such as Backblaze B2) keep prior versions by default, so an overwrite remains recoverable there. (#703)
- Azure Multi-Tenant SSO Restricted to Approved Tenants: Administrators must configure a list of approved Microsoft Entra tenant IDs before enabling a multi-tenant Azure provider. DFIRe verifies that the token tenant matches both its issuer and the configured allowlist; missing, invalid, or unapproved tenants are rejected. (#709)
- Slack Actions Use the Same Write Permissions as DFIRe: Capturing a case note, completing a compliance timer, and editing evidence through Slack now require the same role capability and editable-case access as the corresponding web and API actions. (#736)
- Collaboration Messages Respect Case Visibility: Collaboration message lists are now limited to cases the signed-in user may view, including the separate permission needed to view archived cases. (#814)
- Dependencies Updated: Dependencies were updated to the latest versions that meet the 14-day supply-chain cooldown policy.
- Licensing Is Restricted to Superusers: Activating or replacing a license key, uploading or disabling an offline license, resetting the license-server registration and accepting the end user license agreement were reachable by any role holding the old system-settings permission, despite the Role Editor stating that licensing remains superuser-only. These actions now require a superuser.
- Global IOC Import and Export Enforce Their Own Permissions: Importing indicators into the global registry now requires the Import permission for indicators, and exporting the registry as CSV or STIX requires the Export permission, matching what the Role Editor already lists. Previously any signed-in user could export the entire indicator registry, and importing was allowed by the general permission to add indicators rather than the dedicated Import permission.
1.5.4 — July 12, 2026
Added
- Support Package: A new Support tab in System
Settings generates a single zip file with everything DFIRe support needs to troubleshoot an
installation: application logs, system information, masked configuration, an optional audit log
excerpt of your chosen window, license state, background task state, and database statistics.
The package contains no passwords, keys, or attachment data; the audit excerpt records old and
new values of edited fields, so it can be excluded entirely when audit data must not leave the
installation. The archive can be inspected before sending. It can also be generated on the host
with
manage.py support_packagewhen the web interface is unreachable. Every generation is recorded in the audit log. - Live Application Log Viewer: The same Support tab shows the logs of the backend, task worker, and Slack socket processes live, with errors in red and warnings in amber, text and level filters, pause and resume, and an audited download of the current log file.
- Frontend and Backend Versions Shown Together: The frontend now knows its own version, and both container versions are shown side by side in My Profile and on License & Updates. When the two containers run different releases, a warning tells you to update both, catching updates that pulled one image but not the other. The version pair is also recorded in every support package.
- Jira User Mapping by Display Name, With Confirmation: Automatic user mapping can now find Jira users whose email address differs from their DFIRe address by searching on the display name. Because a matching name alone is not proof of identity, these mappings are held as "Needs confirmation" in Settings → Jira → User Mappings until an administrator confirms or rejects them, and sync ignores them until confirmed. This prevents a name lookalike in Jira from being assigned work or attributed activity in DFIRe. Matches made through the email address are still linked immediately, including when Jira hides the address in search results and the identity is verified by the display name. Rejected suggestions are remembered and not suggested again.
- Delegate Settings Sections by Permission: Playbooks, runbooks, evidence types, triage flags, projects, entities and the other case-property catalogs can now be managed by a role that holds only that section's permission, without granting full system-settings access. A role can be limited to editing playbooks and nothing else, for example. User Accounts, Webhooks and Automation still require system-settings access. See User Management, Role Editor.
- Manage Roles From the Web Interface: Roles can now be created, renamed and deleted in the Role Editor, without dropping to the Django admin site. A role that still has members cannot be deleted until its users are moved elsewhere.
- Assign Multiple Roles to a User: A user can now hold more than one role, and their permissions are the union of all of them. This lets a narrow role, such as playbook editing, be layered on top of a broader one instead of building a bespoke combined role.
- Warning for Directly Assigned Permissions: The User Accounts list now flags accounts that hold permissions granted directly to them rather than through a role, with a warning badge and a count. DFIRe grants access only through roles, so a direct permission (assignable in the Django admin) would otherwise be invisible and could let an account hold more access than its roles suggest. A superuser-only Manage in Django admin link is provided to review or clear such permissions.
- Print a CAN Report: The CAN report now has a Print button, on both the Case Report tab and in the report's version history, that opens a compact one-page layout: the case title, number, lead investigator, creation date and elapsed duration, followed by the Conditions, Actions and Needs sections. Print it on paper or save it as a PDF from your browser to share an incident status snapshot with management. Any earlier version can be printed from the history, not only the latest.
- Predefined Case Codenames: A new Settings → Case codenames tab lets an administrator keep a pool of single-use case codenames, entered as a comma-separated list or, when an AI provider is configured, generated from a short style prompt (for example, "a color and a plant name"). The Create Case dialog then offers a button beside the title that fills in a random unused name from the pool. Once a codename is assigned to a case, even as part of a longer title, it is retired to a used pile and never offered again, so two cases cannot share a name. The used pile is visible only to superusers and can be cleared.
Changed
- Redesigned Role Editor: The Role Editor now edits one role at a time, with an optional second role shown alongside for comparison, replacing the earlier grid of every role at once. Permissions are grouped into collapsible sections per object, each with a Create, Edit, Delete, View summary (plus Manage, Export or Import where an object uses them) so the state of a role reads at a glance. The editor only offers capabilities the signed-in administrator holds themselves.
- Jira Sync Pauses While a Case Is Closed: Closing a case now pauses synchronization of its exported actions and evidence items, and their Jira badges show the paused state. Changes made in Jira no longer modify actions on a closed case; previously a status change or reassignment in Jira kept updating them, bypassing the case's write protection. The case-level Epic link stays active, so moving the Epic out of Done in Jira still reopens the case, and reopening (in either system) resumes the paused links. Archiving a case directly from the open state now also stops sync for all of its links, the same as archiving a closed case.
- Jira Changes Are Attributed to a "Jira Sync" Account: Action updates, completion notes, and case status changes that arrive from Jira are now recorded in the timeline and audit trail as performed by a dedicated Jira Sync service account. Previously they were attributed to an administrator account. The account cannot log in and exists only for attribution.
- Closing a Case No Longer Waits on Jira: The Jira updates triggered by closing, archiving, or reopening a case (Epic transition and comment) now run in the background. Previously the save waited for Jira to respond, so a slow or unreachable Jira made closing a case hang, and a failed update disappeared without a trace; failures are now logged.
- Faster Manual Jira Sync: The per-case Sync action now fetches all linked issues from Jira in batched queries instead of one request per issue, so syncing a case with many exported actions completes in seconds instead of timing out. A deleted Jira issue no longer forces the poller to fall back to one-by-one requests for every other issue.
Fixed
- Saving Jira Settings No Longer Resets Omitted Fields: A configuration save that included only some Jira settings reset the rest to their defaults, which could disable the integration. Saves now change only the fields that were sent, and a save no longer discards another integration's settings saved at the same moment.
Security
- Log Sanitizer Masks Full Header Values: Sensitive headers logged by the application were masked only up to their first space, so a value such as a bearer token could survive into the logs after the masked scheme word. The sanitizer now masks the complete value. Log output is the only place affected; no stored data was involved.
- Role Permissions Enforced on Jira Actions: Exporting cases, actions, and evidence items to Jira, triggering a manual sync, and reading Jira links and comments now require the same case edit and view permissions as the corresponding actions in the web app. Previously these endpoints checked case team membership but not the role's permissions, so a team member whose role granted no edit rights could still export and sync. Jira user search and comment retrieval are also rate limited now, so they cannot be used to exhaust the Jira API quota.
1.5.3 — July 2, 2026
Added
- Automation Rules Run in a Defined Order: Automation rules now execute in a fixed sequence you control by dragging them into position on the Automation settings page. When several rules match the same case change, they run top to bottom and a later rule can override an earlier one: put a default case lead rule first and a "critical cases get a different lead" rule after it, and the outcome is always the override. Every rule change fired by one case edit runs in a single pass, so two rules can no longer race each other. The rule editor also blocks assigning Lead to more than one person up front, instead of rejecting it at save.
- Automation Slack Actions in the Audit Log: Slack channel invitations and removals performed by automation rules are now recorded in the case audit log, alongside the team changes automation already logged.
- Archive Cases Through the MCP Tools: The MCP case tool can now archive a case (open or closed) and reopen an archived one, not just open and close it, matching the transitions available in the web app.
Changed
- Slack Channels No Longer Depend on a Linked Lead: With Slack enabled, every new case now gets a Slack channel, created by the DFIRe bot, whether or not the lead investigator — or whoever created the case — has linked their Slack account. Linked team members are invited automatically, and others are invited once they link. Previously a case whose lead had no linked Slack account got no channel at all, so a case opened by an unlinked account or through the API stayed without one.
- Create Channels and Post Without Linking: Creating a case's Slack channel and posting messages to it from DFIRe no longer require you to link your Slack account first. Messages you post go out from the DFIRe bot, signed with your name. Linking your account is still needed for Slack-side slash commands and interactive buttons.
Fixed
- Automation-Invited Members Reach the Slack Channel: An automation rule that adds investigators or viewers when a case opens now reliably invites them to the case's Slack channel. Previously they were added to the case team but could be left out of the channel, because the automation ran before the channel had finished being created; invites for people without a DFIRe account, such as Legal or Communications, could be missed the same way. The team is now invited when the channel is created, and Slack-only invitations are sent as soon as the channel is ready. If the channel could not be created, or Slack is not enabled, the rule's run history now records each Slack action as skipped with the reason, instead of leaving no trace.
- Team Edits No Longer Undo Automation: Saving the Manage Team dialog while an automation rule was adding members at the same time could silently remove the members the automation had just added, from both the case team and the Slack channel. The dialog now applies only the changes you made in it, so members added in the background are kept.
- Slack Channel Membership Follows the Team More Faithfully: Team changes are now mirrored to the Slack channel in the background, so saving a team edit no longer waits on Slack to respond. A member holding both investigator and viewer roles is no longer removed from the channel when only one of the roles is taken away, and rapid back-to-back team changes settle on the correct final channel membership.
- Webhook and Audit Log Deliveries Retry Properly: A delivery to an endpoint that is temporarily unavailable now retries after one, five, and thirty minutes as designed. Previously all retries fired immediately, so a brief outage at the receiving end exhausted every attempt within seconds and the delivery was lost.
- Invites Recover From an Archived Channel: If a case's Slack channel had been archived (for example after the case was closed and reopened), inviting people to it, whether by an automation rule or by adding them to the case team, failed. DFIRe now unarchives the channel and completes the invite, since an open case's channel should never stay archived.
- Automation Run History Explains Skips and Failures: The run history for an automation rule now shows the reason next to any action that did not cleanly succeed, for example a Slack invite that Slack itself rejected, so you can see what happened without reading server logs.
Security
- Deactivated Accounts Locked Out of Slack: A deactivated DFIRe account whose Slack link was still in place could keep acting on cases through Slack slash commands, shortcuts, and dialogs. Deactivated accounts are now rejected at every Slack entry point, matching the web login, and are no longer invited to new case channels. Removing a deactivated member from a team or channel still works.
1.5.2 — June 30, 2026
Added
- Paste a Timestamp into Date Fields: Every date and date-and-time field now has a paste helper (the clipboard icon beside it): paste a timestamp copied from a log and DFIRe recognises the format and fills the field, instead of typing it in by hand. It accepts common log and system formats, including ISO 8601 / RFC 3339, RFC 5424 and legacy RFC 3164 syslog, RFC 2822 / HTTP-date, Apache, MySQL, Windows, and Unix epoch. A timestamp that carries a timezone is converted to the timezone you are viewing in; one without is taken as written. See Timestamp Formats for the full list.
Changed
- Clearer Backup Database Connection: The Backup & Recovery settings page now shows both the connection DFIRe uses for everyday traffic and the separate connection used for backups and restores, so it is clear which database each one talks to. When the deployment provides a direct (non-pooled) database URL, DFIRe uses it for backups and restores automatically, with nothing extra to configure on the page.
Fixed
- Installer Respects Your Configured Database: The installer now makes the
database settings you enter take precedence over a
DATABASE_URLalready present in the host environment, for example the one DigitalOcean injects when you create a droplet with a managed database. Previously that inherited value could silently override your configuration and start the containers against the wrong database. - IOC Sharing Toggle No Longer Reverts: On the IOC Sharing settings page, turning the TAXII Server or MISP Feed toggle on and then creating a collection or API key before saving no longer flips the toggle back off. The unsaved change is kept until you save.
- Retry a Failed File Upload: An Encrypted Storage upload that fails part way, for example on a dropped connection, now shows a Retry button next to Dismiss, so you can re-run it with one click instead of re-selecting the file from disk.
- Repeat CLI Backup Restores: The
manage.py restore_backupcommand now reconciles its own backup records before restoring, so the same backup can be restored more than once from the command line without listing backups first. - Self-Service Password Change Succeeds Cleanly: Changing your own password from your profile no longer shows an error after the new password has been saved. The change now completes, signs you out, and returns you to the login screen as intended.
- Clearer Error When Creating a Key for an Invalid Account: Creating a User API key for an account given as an invalid value now returns a validation message instead of a server error.
- Complete DNS Enrichment for Domains: Enriching a domain indicator now returns the full advertised set of DNS records: mail (MX), text (TXT), name server (NS), authority (SOA), alias (CNAME), and certificate authority (CAA), in addition to address and reverse lookups. Previously only address and reverse records were returned.
- Faster IOC Extraction from Large Text: Extracting indicators from a very large block of text now completes quickly. Previously certain large inputs could make the indicator extraction take several minutes to respond and tie up a server process; the text scan is now efficient regardless of input size, within the existing one-megabyte limit.
Security
- Restore Keeps the New Server's Backup Connection: When a backup was restored onto a different server, for example to migrate to new hardware, the restored server inherited the original server's saved backup database connection. Its next backup or restore could then run against the original server's database instead of its own, risking data loss on a separate and possibly live system. A restore now preserves the backup connection settings of the server it is restored onto, so a migrated installation can only reach its own database.
- API Key Lifetime Cap Enforced on Edit: A User API key's expiry could be extended beyond the maximum lifetime an administrator had set by editing the key after it was created. The cap is now applied when a key is edited, not only when it is first created.
- Administratively Disabled Keys Stay Disabled: A user could re-enable one of their own API keys that an administrator had disabled. Re-enabling a key an administrator turned off now requires administrator rights; a user can still revoke their own keys.
- Single Sign-On Secrets Always Masked: A single sign-on secret stored at the top level of the SSO configuration could be returned in clear text when the settings were read back, instead of masked like other secrets. All SSO secrets are now masked on read.
- Provider Keys Kept Out of the Audit Trail: Saving system settings could record enrichment and AI provider API keys in clear text in the audit log's change history. These keys are now redacted from the audit trail, leaving only the name of the setting that changed.
- Token-Like Secrets Always Encrypted at Rest: A stored secret whose value happened to begin with the same prefix as an encryption token could be written to the database without being encrypted. Stored secrets are now verified and always encrypted at rest.
- MCP Tool Changes Roll Back if They Cannot Be Audited: A change made through the MCP Server's tools could be saved even if writing its audit-log entry failed, which would leave an unaudited change. A tool's change and its audit entry are now saved together, so a change that cannot be recorded in the audit trail is rolled back.
- Investigation Reports Require Write Access via MCP: A case viewer with read-only access could edit or submit an investigation report through the MCP Server's tools. Editing a report through these tools now requires write access to the case, matching the rest of the application.
- Compliance Timers Complete Exactly Once: Completing a compliance timer with two rapid or simultaneous clicks could mark it complete more than once, recording duplicate completion entries in the case timeline and audit log and overstating how a regulatory deadline was met. Completing a timer is now handled as a single locked operation, so only the first completion is recorded and any concurrent attempt is rejected.
1.5.1 — June 23, 2026
Added
- Markdown Preview for Reports: The CAN report and case description editors gain an Edit / Preview toggle in the editor header, rendering your Markdown as it will appear before you save.
- License Server Status Badge: License settings now show a live uptime badge for the DFIRe License Server, so an administrator troubleshooting a failed check-in can tell at a glance whether the server itself is down or the problem is local. The badge is hidden automatically on systems with no internet access.
Fixed
- Editors No Longer Close and Lose Input on a Stray Click: An editing dialog no longer closes and discards your work when a text selection that ends past the dialog edge releases on the area outside it. Long-form editors — CAN reports, case descriptions, notes, and timeline entries — additionally no longer close on a plain click outside, so they close only via Cancel, the close button, or Escape.
- Time Fields Keep the Cursor in Place: Editing a 24-hour time field mid-value no longer jumps the cursor to the end after each keystroke, so you can correct a time without retyping it.
Security
- Dependency Security Updates: litellm 1.84.0 (GHSA-4xpc-pv4p-pm3w), cryptography 48.0.1 (GHSA-537c-gmf6-5ccf), msgpack 1.2.1 (GHSA-6v7p-g79w-8964), daphne 4.2.2 (PYSEC-2026-213, PYSEC-2026-214), bleach 6.4.0 (GHSA-gj48-438w-jh9v, GHSA-8rfp-98v4-mmr6), and ujson 5.13.0 (GHSA-3j69-69wj-xqx2), plus a DOMPurify update on the frontend.
1.5.0 — June 14, 2026
Added
- Knowledge Base: A built-in documentation space for SOPs, site-specific instructions, and reference notes, available to every DFIRe user. Folders and Markdown pages with version history, inline images, drag & drop organizing, group-based visibility, and optional zero-knowledge password protection for sensitive content — a forgotten password is unrecoverable by design. Found behind the book icon in the top navigation. See Knowledge Base.
- Case Automation Engine: A new rules engine that automatically brings the right people into a case — and notifies external systems — when it opens or changes. Each rule pairs a trigger (case opened, escalated to incident, criticality raised or lowered, playbook or project changed) and optional filters (mode, criticality, playbook, project) with one or more actions: invite or remove a Slack user on the case channel, add or remove a DFIRe user on the case team as lead, investigator, or viewer, or fire a webhook. Slack invites reach people without a DFIRe account. Configured under Settings → Automation. See Automation.
- "Automation Rule Triggered" Webhook Event: A rule's "Fire a webhook" action emits this event with a trigger tag; subscribe an outgoing webhook to it and filter by tag. The same tag can drive a single webhook from both a runbook step and an automation rule. See Automation — Firing a webhook.
- Automatic Slack Account Linking: When Slack integration is configured, DFIRe links each single sign-on user to their Slack account automatically — matching the verified email from your identity provider on sign-in — so their Slack actions are attributed in the audit log and they are reachable in case channels without any manual step. On by default; configurable under System Settings → Slack Integration. See Integrations — Account linking.
- CSV & STIX Import: Bulk-import timeline events, notes (case, item, and action), and evidence items from CSV directly into a case — and indicators from CSV or STIX, both into a case and into the global registry. A two-stage preview-then-commit flow shows exactly which rows are new, which update an existing record, and which are rejected, before anything is written. Matching is by a stable, case-scoped identifier, so re-importing a previous export changes only what actually differs and never wipes fields left blank. The importers mirror DFIRe’s existing CSV/STIX exports and are reached from the Import button on the Timeline, Notes, Evidence, and IOC surfaces. Every import enforces the same write permission, case-team membership, write-protection, and audit rules as manual editing.
- Concurrent Session Management: My Profile now lists your recent sign-ins — browser, IP address, and last activity — flags the one you’re using, and lets you revoke any other session individually or all at once. Revoking a session signs that device out immediately.
- In-App @Mention Notifications: Mentioning a teammate with
@in a note now raises an in-app notification for them, and the notification bell updates in real time as events arrive rather than only on a manual refresh. - Offline License Continuity: If DFIRe cannot reach the license server, your installation now keeps full functionality for 90 days (previously 14) while showing escalating guidance on when to install your offline continuity license — a break-glass license that covers the remainder of your paid term with no dependency on the licensing service. A term that has genuinely expired, reported by a reachable server, still switches to read-only immediately; the 90 days never extend a paid term.
- Running Version in My Profile: The DFIRe version your installation is running now appears in My Profile, visible to every user rather than only to administrators.
Changed
- Unified Interface: A sweeping consistency pass across the application — buttons, form fields, selects, dialogs, the dashboard, the IOC and evidence views, and the report editor now share a single design language, for a more cohesive and predictable experience.
- Case Tabs Renamed: On the case page, the Collaboration tab is now Slack and the Attachments tab is now Files; the evidence-item Attachments tab is likewise Files. These are display labels only — links, deep-links, and the API are unchanged.
- Slack Channel Membership Follows Case Assignment, Not Permissions: With Slack enabled, a case’s channel is now created automatically only once the lead investigator has linked their Slack account, ending the empty private channels that used to appear when the lead had no link. Channel and team membership is no longer derived from tenant-wide “all cases” permissions — targeted invitations are the job of the automation engine.
- Report Editor: The investigation report editor gains Markdown syntax highlighting, single-field reference tokens that expand to plain text (evidence name, type, owner; attachment filename, hash, size; image description) for use in tables and verbatim values, and a toolbar aligned with the rest of the application.
- Indicator Page Polish: The indicator intelligence page hides the Enrichment and Respond tabs when nothing applies to that indicator, revoked indicators carry an explicit REVOKED badge, and the IOC list gains a Clear All Filters button.
- Runbook Progress at a Glance: Attached-runbook badges in the Actions tab are now tinted by progress — green when every step is done, blue while in progress, neutral when unstarted — and completed actions show an explicit Reset control.
- Storage Target Guidance: The “add storage target” picker now marks S3 as Recommended (uploads stream from the browser straight to the bucket) and SMB and SFTP as Slower (every byte streams through the DFIRe server), steering administrators toward the faster, more scalable option unless they specifically need an on-premise share. See Storage.
Removed
- Incoming Webhooks Deprecated: The incoming-webhook feature — which let external systems open cases by POSTing to a tokenized URL — has been deprecated, and its endpoints have been removed. Existing webhook configurations are retained in the database but no longer accept requests. To create cases programmatically, use a User API key with the Cases API.
Fixed
- IOC Trigger Webhook Variables Unavailable: When an IOC trigger was selected as
a webhook’s event, the payload editor dimmed every template variable — including the
ioc.*values the trigger actually provides — because the variable catalog did not list the dynamically-named trigger events. IOC trigger events now expose theirmeta.*,ioc.*, andsecret.*variables in the editor. - Zero-Duration Compliance Timer Halting Deadline Alerts: A compliance timer saved with a duration of zero hours caused the scheduled deadline-alert check to fail, silently stopping every threshold and breach alert across all cases until the bad timer was deleted. Timer durations must now be at least one hour, and the alert check isolates each timer so one misconfigured timer can no longer block alerts for the rest.
- Stuck Automatic Case Deletion: When automatic deletion of an archived case failed partway through, the case could be left with its evidence already removed while the case record itself remained, and the retention run would re-attempt it every hour without ever completing. Case deletion is now all-or-nothing — a failure leaves the case fully intact and retryable rather than partially deleted — and the cause of any failure is now recorded so it can be diagnosed.
- Deleting an Attachment Mid-Upload: Deleting an attachment while it was still uploading to a remote SMB, S3, or SFTP backend could fail with a server error, because the delete collided with the background upload finishing. The delete now retries automatically and completes cleanly.
- Slack Channel Unarchive Signal Double-Fire: Unarchiving a Slack channel externally no longer queues a redundant archive-sync task. The loop-prevention flag is now set before the case status save rather than after.
- Slack Reaction Removal Race Condition: Removing a reaction from a Slack message now uses database row locking, preventing concurrent reaction events from silently overwriting each other.
- urlscan.io Enrichment Restored: The urlscan.io enrichment failed for every indicator — even sites already scanned on urlscan.io — because urlscan.io now requires an API key to both submit scans and read results. The enrichment now uses a configured API key: it returns an existing scan immediately, or submits a new one and re-checks in the background until the result is ready, reporting a timeout with the scan ID if it never completes. URL indicators are scanned at their full path rather than collapsed to their domain. Add a key under Settings → IOC Enrichment.
- Large File Uploads Far More Resilient: The multi-gigabyte upload paths that Direct Storage exists for — disk images, memory dumps, packet captures — no longer fail on transient transport problems. A chunk whose response is lost behind an HTTP/3 proxy (which surfaced as “Invalid chunk order” and killed the whole upload) is now acknowledged idempotently; S3 Direct uploads that run past the one-hour presigned-URL lifetime re-sign their parts instead of discarding all progress; and SMB and SFTP Direct uploads survive backend worker recycling and mid-upload connection drops rather than stalling. See Storage.
- Stored-File Integrity on SMB and SFTP: Under a narrow condition — a large upload to an SMB or SFTP share that was interrupted and automatically retried mid-transfer — DFIRe could write incorrect data to the stored file, duplicating or dropping bytes, while still marking the file complete. The file then showed as available in the case but no longer matched what was uploaded, and because the recorded SHA-256 was computed from the source rather than the stored object, the mismatch was not obvious. This affected both Encrypted Storage and Direct Storage on the SMB and SFTP backends only; S3 storage was not affected, as its uploads cannot be written this way. Chunk writes are now positional and idempotent — a retried transfer overwrites the same bytes instead of doubling or truncating them — and the stored object’s size is verified against what was sent before the file is marked available. Re-downloading an affected Encrypted Storage file now fails its integrity check rather than returning altered bytes; Direct Storage files can be re-checked with the Re-verify / Calculate SHA-256 control. See Storage.
- Failed Uploads Clean Up After Themselves: A failed or cancelled upload now releases its server-side session and partial temporary file immediately, instead of counting against your concurrent-upload limit for days and leaving large temporary files on disk. A file whose hash fails server-side verification no longer shows a success message.
- A Dead Storage Peer No Longer Wedges the Backend: SMB connections now use TCP keepalive, so an unresponsive SMB server is detected and dropped within about a minute rather than tying up a worker process indefinitely (SFTP gained the equivalent earlier).
- Backup and Direct Upload Integrity Verified After Write: Backups and S3 Direct uploads now confirm that the stored object’s size matches what was sent before being marked complete, so a backend that silently truncated a write can no longer leave behind a backup that cannot be restored or an upload that looks verified but is short.
- Chain of Custody Visible in Item History: Custody transfers now appear in an evidence item’s History tab — along with the item’s attachments and notes — where they were previously missing.
- Manual Case Notes Reach Slack: A plain case note now posts to the linked Slack channel like any other note, matching the in-app notification. Previously only notes set to show on the timeline were forwarded to Slack.
- Publish Respects Unsaved Indicator Edits: Setting an indicator to TLP:RED and clicking Publish without saving first no longer publishes it. Publish is now blocked while the assessment panel has unsaved changes, closing a footgun that could disclose an indicator the user believed was gated.
- Slack Channel Creation Honors Write Protection: The Create Channel control is now disabled on closed and archived cases, matching the absolute write-protection applied everywhere else.
- Scheduler No Longer Replays Missed Tasks After a Restore: Following a database restore or extended downtime, scheduled tasks (license check-in, retention, compliance-timer alerts, and the rest) no longer fire once for every interval that elapsed while the system was down — behaviour that had been flooding the audit log.
- No Longer Logged Out Mid-Task: An active session — including a multi-hour
evidence upload — is no longer cut off exactly twelve hours after login. The session
timeout is now a sliding window that activity extends, so only twelve hours of genuine
inactivity expires a session (closing the browser still ends it immediately). Separately, a
stray transient
401seen behind some proxies is now re-verified against the server before it can log you out, so a spurious error no longer interrupts a valid session. - License Registration Recovery: An installation that lost its license-server registration key can now recover with a Re-register action in License settings, instead of requiring a full reinstall. License-server requests also identify themselves with a stable user-agent so content-delivery firewalls stop challenging them.
- Smaller fixes: the audit log’s Actions filter now lists every action type
rather than seven of them; the timeline’s “Case opened” divider renders in
both sort orders; case-note author avatars display reliably; the API-key usage example copies
the full
curlcommand; the storage health badge refreshes immediately after a connection test; the Report Editor opens in a new tab to match its icon; photo uploads no longer time out against a slow SMB share; and failed-upload remnants no longer inflate an evidence item’s file count.
Security
- Case Write Access Consistently Enforced: A member with read-only (viewer) access to a case could, through certain secondary actions, still modify case content — toggling evidence runbook steps, creating or assigning action items, recording chain-of-custody transfers, or invoking write tools through the MCP Server. These paths now apply the same case-team write rules as the rest of the application, so a read-only collaborator can no longer alter a case they should only be able to read.
- Role and User Editor Privilege-Escalation Guard: An administrator granted only delegated role-management or user-management rights could assign themselves or another account permissions — or a group carrying permissions — that they did not already hold, such as access to all cases or tenant administration, escalating toward full control. Non-superuser administrators can now grant only the sensitive permissions they hold themselves; everyday role administration is unaffected.
- Cross-Case Evidence Isolation: An investigator with access to two cases could attach an evidence item from one case as a child of an item in the other, exposing item details across the case boundary. An item's parent must now belong to the same case.
- Timeline Deletion Permission Enforced: Deleting a manual timeline event now requires the delete-timeline-event permission. A role granted only add and edit timeline rights (such as Standard user or Team Lead) can no longer remove timeline entries, protecting the forensic record.
- Storage Quota Check Restricted to Uploaders: The storage-quota pre-check endpoint now requires upload permission, so tenant-wide storage usage and quota figures are no longer exposed to users who cannot upload, including View-Only accounts.
- Slack File Download SSRF Protection: The Slack file download endpoint now validates URLs against a strict allowlist of Slack file-hosting domains and disables HTTP redirects, preventing SSRF attacks and bot-token leakage to arbitrary hosts.
- Slack Note Capture XSS Prevention: Messages captured as case notes via the
pushpin reaction or the message shortcut are now sanitized through
sanitize_markdown(), matching the protection already applied to notes created through the web UI and modals. - Slack Channel Join Permission Hardening: Auto-adding users to cases when they join a Slack channel now checks that the linked DFIRe account is active. Pushpin captures now require the reacting user to have write access (lead investigator, investigator, or edit_all_cases permission).
- AI Assistant Audit Fail-Closed: The Slack AI assistant now writes its audit log entry before posting the answer. If the audit write fails, the answer is withheld, aligning with the fail-closed audit policy enforced elsewhere in DFIRe.
- Login Brute-Force Limit No Longer Header-Bypassable: An unauthenticated
attacker could defeat the login rate limit entirely by changing the
X-Forwarded-Forheader on each attempt, because the throttle counted attempts per client-supplied header value rather than per real client. Login attempts are now counted against the trusted client address, so the five-attempts-per-minute limit holds regardless of forged headers. Deployments behind a reverse proxy should ensure it passes the real client address inX-Real-IP— the bundled configuration already does. - Slack Account Linking Restricted to Verified Identities: The web self-service
Slack linker, which let any signed-in user claim an arbitrary Slack member ID for their own
account, has been removed. Accounts now link only through single sign-on (using the identity
provider's verified email) or the
/dfire linkSlack command (using the Slack account's own verified email), and creating Slack mappings directly is restricted to administrators. This prevents a user from associating their DFIRe identity with someone else's Slack account. See Integrations — Account linking. - Webhook Secrets No Longer Exposed via Audit Log or API: Encrypted webhook secrets — auth passwords and tokens, signing secrets, and custom headers — were being recorded in cleartext inside audit-log change diffs (and therefore egressed to any configured SIEM), and custom headers were also returned in plaintext when reading a webhook back. Encrypted fields are now excluded from audit snapshots by field type rather than by name, closing the whole class at once, and secret headers are write-only.
- View-Only Users Can No Longer See Unassigned Cases: A View-Only account could open any case that had no assigned lead investigator. Visibility of unassigned cases now requires the same permission used to claim and lead a case, so a viewer sees only cases they are explicitly assigned to. Investigators, leads, and holders of the all-cases permissions are unaffected.
- Photo Uploads Never Spool Plaintext to Disk: Photos larger than 8 MB were briefly written to the container’s temporary directory in cleartext before being encrypted, because the upload size had outgrown the in-memory threshold. Photo uploads are now held entirely in memory, restoring the encryption-at-rest guarantee for every image.
- Dependency Security Updates: Django 6.0.6 (PYSEC-2026-197, PYSEC-2026-198, PYSEC-2026-199, PYSEC-2026-200, PYSEC-2026-201), PyJWT 2.13.0 (PYSEC-2026-175, PYSEC-2026-177, PYSEC-2026-178, PYSEC-2026-179), aiohttp 3.14.0 (CVE-2026-34993, CVE-2026-47265), esbuild 0.28.1 (GHSA-gv7w-rqvm-qjhr, GHSA-g7r4-m6w7-qqqr).
1.4.3 — May 20, 2026
Added
- Download Button on Image Attachments: The image grid on Case and Item attachment tabs now shows a Download button on each photo, matching the action already available on file rows. Visible by default so it remains reachable on touch and non-hover devices.
- "Unverified" Badge on Browser-Declared Hashes: Direct Storage rows whose SHA-256 was supplied by the uploader's browser are now marked with an amber Unverified badge, so investigators can see at a glance which hashes have been independently confirmed by DFIRe. The existing Re-verify button replaces the badge with a verified hash on success or a Disk mismatch badge on failure.
Fixed
- SFTP Storage Target — Silent Corruption on Large Direct Uploads: Uploading multi-gigabyte files via the SFTP Direct Storage route could drop bytes mid-file while the SFTP server reported success, leaving the on-disk file shorter than what was uploaded but still flagged as available in the case. The Direct Storage upload pipeline now writes synchronously to SFTP and verifies the on-disk file size against the client-reported size at finalize; mismatches fail the upload with an explicit error and delete the partial file from the SFTP host.
- Opening Encrypted Images Larger Than 8 MiB: Image attachments and Slack-captured files larger than 8 MiB were stored with an encryption layout the chunked decryption stream could not decode, so previewing or downloading them failed with an integrity error. New uploads use the chunked layout. Existing files uploaded before this release decode automatically through a transparent legacy fallback — no manual re-upload required.
Security
- OIDC Discovery URL SSRF Protection: The outgoing-URL validator that blocks loopback, link-local, and cloud-metadata targets is now applied to an OIDC provider’s discovery URL — both when validating it before save and on every sign-in — closing the last outgoing-HTTP path that bypassed the SSRF filter.
- Bumped idna to 3.15 to address CVE-2026-45409.
1.4.2 — May 18, 2026
Fixed
- Direct Archiving from Open: Cases can now be moved straight to Archived without first closing them. The previous lifecycle rule rejected the transition and forced users through Closed.
- Closing, Reopening, and Archiving from the Case Edit Dialog: Changing the status of an already closed or archived case from Edit Case used to fail with an error, leaving those cases stuck. Status changes from the dialog now work on closed and archived cases.
1.4.1 — May 16, 2026
Added
- Per-Provider SSO Access Control: Each OIDC provider now carries three optional gates — email-domain allow-list, "Allow new user creation" toggle, and required IdP group claim. See SSO — Access control.
- Unlink SSO Identity: Admin action on deactivated user accounts that detaches the OIDC identity and rewrites the email, so the next SSO sign-in provisions a fresh account. See User Management — Unlinking SSO identities.
Changed
- Adding an SSO provider now persists the client secret on submit, so navigating away cannot lose it.
- Saved SSO client secrets show as "Configured · Replace" rather than as a re-editable masked field, preventing accidental overwrite.
- Enabled SSO providers must have a default role assigned before they can be saved.
- The Users tab lists active accounts on top and a separate "Disabled accounts" list below.
Fixed
- OIDC Email-Fallback Linking Now Requires
email_verified=true: Without this gate, an attacker who could register asubwith a victim's email at an identity provider that does not enforce email ownership could take over the victim's local account on first SSO sign-in. - IOC Exports Under PgBouncer Transaction Pooling: Django's
QuerySet.iterator()defaults to a server-side cursor whose name does not survive PgBouncer's per-transaction connection checkout, so large IOC exports could fail or truncate mid-stream in production while passing in dev. The default database now disables server-side cursors. - CSV Case Exports Now Fail-Closed on Audit Failure: The CSV exports for timeline, items, notes, and actions previously swallowed audit-log failures and returned the export anyway, allowing an attacker (or DB outage) to suppress the audit trail of an export. They now mirror the JSON export and return HTTP 503 if the audit write fails, before any rows are emitted.
- Chunked Upload Row Lock Prevents Same-Index Race: Two concurrent
POSTs with the sameX-Chunk-Indexfrom a single session could both pass the expected-index check and both append their ciphertext to the temp file, corrupting the upload. The chunk-append path now wraps session lookup, validation, write, and state update intransaction.atomicwithselect_for_update, mirroring the existing complete-view pattern. - Playbook Designer Button Labels: The Workflow editor's "Action" and "Action with runbook" buttons now read "New Action" and "New Action with runbook," making it obvious that the workflow spawns a new action rather than referencing an existing one.
- Slack Channel Race No Longer Returns HTTP 500: Creating a Slack channel via the explicit endpoint could race with the auto-create signal and surface a database integrity error as a 500. The endpoint now catches the unique-constraint violation and returns 409 with the existing channel info.
- Backend Hangs After Aborted Slow Requests: A client that disconnected
mid-request on a slow endpoint could leave the request handler stuck; after a handful of such
aborted requests the backend would stop responding to new traffic. Adds a 240-second ceiling on
individual database queries and a process watchdog that automatically recovers the container if
it stops responding. When the query ceiling fires it is recorded as a
STATEMENT_TIMEOUTentry in the audit log, so administrators can diagnose customer-reported slowness from the audit feed without reproducing the workload. - The last active superuser can no longer deactivate themselves, preventing a full tenant lockout.
1.4.0 — May 13, 2026
Added
- New Storage Model — Targets and Roles: Configure multiple storage backends side by side and bind each role (Encrypted Storage, Direct Storage, Backup) to whichever target makes sense. Switching a binding doesn’t move existing files — they keep reading from the target that holds them. Each target shows a usage bar broken down by role and a connection-health badge. See Storage for the full picture.
- SFTP Storage Backend: SFTP is now a supported target type, usable for Encrypted Storage, Direct Storage, or Backup. Trust-on-first-use host-key handling (fingerprint captured on Test Connection, verified on every subsequent operation), password or private-key auth, and support for modern OpenSSH-format keys including 1Password exports.
- Direct Storage for Forensic-Scale Files: A new attachment pathway for multi-gigabyte disk images, memory dumps, and packet captures. S3 Direct uploads go straight from the browser to the bucket via presigned URLs; SMB and SFTP Direct stream through the backend. Admin opt-in, off by default. RBAC, audit trail, and a server-recorded SHA-256 apply to every Direct upload. Files land on the backend with their original filename so administrators browsing the bucket / share / SFTP host find the same name as in the case attachments tab.
- Verify SHA-256 on Direct Storage Files: Files placed in the bucket / share / SSH host out-of-band can be hashed on demand with a Calculate SHA-256 button — DFIRe streams the bytes back and hashes them itself, which is stronger provenance than relying on backend-provided checksums. Hash compute can be cancelled mid-run, DFIRe automatically flags a hash as stale if the underlying bytes change, and uploaded files can also be re-verified server-side at any time via a Re-verify button.
- Slack Channel Names — Templates and Configurable Length: The Slack
channel name for a new case is now driven by a template in System Settings → Integrations
→ Slack, with Python-style slicing on case fields (e.g.
inc-{case.severity[:4]}-{case.case_number}-{case.title}). Variables available: case number, title, mode, severity, playbook, ENISA category, project, external reference. The max channel length is configurable up to Slack’s 80-character hard limit (was effectively 30 before). A live preview on the settings page shows the exact name a mock case would get. If Slack rejects a name as already taken, DFIRe retries with-2,-3, … up to-9and writes an audit log entry plus a notification to the case lead if creation ultimately fails. - License Check-In Visibility: Every license-server check-in (scheduled or manual) now writes an audit log entry with status, duration, and any error string, so a silent ping failure is no longer invisible.
Changed
- “Secure Files” Renamed to “Encrypted Storage”: The storage role formerly called “Secure Files” in Settings is now “Encrypted Storage,” parallel to “Direct Storage” as the other tier. The rename is UI-only — existing API consumers and settings exports are unaffected.
- Attachments Tab Survives Tab Switching: Switching between Attachments, Notes, Evidence, Timeline, etc. on a case or item detail page no longer interrupts an in-progress upload — uploads keep running and the progress bar resumes when you return. Navigating away from the case entirely still aborts.
- Item Files No Longer Mirror to the Case Attachments List: Files uploaded to an evidence item now live exclusively on that item’s page. The Case → Evidence tab’s per-item navigation already provides discoverability; the mirror was duplicate noise.
- Clearer License-Server Connectivity Messaging: The license banner and Settings
detail text used to read “License validation unsuccessful — operating in grace
period” when a check-in couldn’t reach the license server, which sounded
like a billing issue. The messaging now reads “Cannot reach license server —
using cached license” and the expired-grace block points at the
qclustercontainer and DNS resolution rather than implying a billing problem.
Fixed
- Lead Investigator Stays on the Case Team When the Lead Changes: Reassigning a case’s lead investigator via the web or REST API used to silently drop the previous lead from the case — they lost visibility (the case filtered out of their list) and could be kicked from the linked Slack channel. The lead is now always also in the investigator list, and reassigning only adds the new lead; the previous lead remains as an investigator on the case unless explicitly removed. A data migration backfills existing cases.
- LLM Connection Test Works on Reasoning Models: The Test Connection button on the LLM provider settings used to fail against reasoning models (Gemini 2.5 Pro, Claude with thinking, OpenAI o-series) because their internal thinking consumed the entire response budget before any visible output. The budget is now large enough that non-reasoning and reasoning models both pass the test.
- Case Deletion No Longer Blocks on Storage Outages: Deleting a case when the underlying storage backend is unreachable used to fail with a 500. The database row now always goes away; unreachable backend objects are recorded in the audit log for operator follow-up.
Security
- SSRF Validator Reinstated on OIDC Profile Pictures and Audit Log Delivery: Two
callers of the outgoing-URL validator were discarding its return value, so URLs that should have
been blocked (loopback, cloud metadata, link-local) were being accepted — reachable from a
user-controlled
pictureclaim on OIDC sign-in, and from a misconfigured audit log delivery destination. Both callsites now fail closed. - SMB3 Encryption Enforced on All SMB Connections: One Encrypted SMB upload path was constructing its SMB session without requiring SMB3 encryption. It now routes through the shared session helper that every other SMB call uses, so every connection is required to negotiate SMB3 encryption.
- Settings Import Leaves Live Storage Untouched When the Payload Has No Storage
Block: A non-encrypted settings import with no
storagesection used to wipe the operator’s configured storage targets. The import now treats a missing storage block as “don’t touch” rather than “clear.” - Dependency Security Updates: Django 6.0.5 (CVE-2026-35192, CVE-2026-6907, CVE-2026-5766), paramiko 5.0.0 (CVE-2026-44405), Twisted 26.4.0rc2 (CVE-2026-42304), axios 1.15.2 (CVE-2026-42037 — CRLF injection), litellm 1.83.14 + python-dotenv override (CVE-2026-28684), urllib3 2.7.0 (CVE-2026-40217, CVE-2026-44431, CVE-2026-44432), fast-uri 3.1.2.
1.3.1 — April 21, 2026
Added
- MISP as an Enrichment Source: New MISP enrichment provider that looks up indicators against a configured MISP instance. Results are grouped per MISP Event with the event info, originating organisation, threat level, and tags for each matching attribute. Runs alongside VirusTotal, Spur, urlscan, AbuseIPDB, and the other existing providers — a natural fit when you already run a MISP instance as your CTI source of truth.
- “Apply Tags to IOC” on MISP Results: Each MISP Event card on the indicator detail page carries an Apply tags to IOC button that merges that event’s tags into the DFIRe indicator’s tag list (deduplicated, audit-logged). Different events carry different tags, so the choice is per event. Useful for promoting curated MISP tags onto the DFIRe record as a triage signal.
- Auto-Run Enrichments on New IOCs: Each enrichment provider has a “Run automatically when a compatible IOC is added” toggle on the settings page. Enabled providers fire in the background whenever a new indicator is created (manual add, import, auto-extraction, decomposition), so you land on the intel page with results already in place. Especially useful for local providers like MISP or DNS where lookups are cheap.
- urlscan.io API Key: The urlscan.io settings card now has an API key input alongside the test button. Supplying a key unlocks higher rate limits and private scan visibility. Works keyless when no key is configured.
- WHOIS for IP Addresses: The built-in WHOIS provider now resolves IPv4 and IPv6 addresses in addition to domains, querying the appropriate Regional Internet Registry and extracting NetName, CIDR/range, organisation, country, abuse email, and registration dates. Previously an IP lookup returned an empty record and the UI showed “No WHOIS data returned for this IP.”
- MISP Feed Organised Around Cases: Each DFIRe case that has at least one
published non-RED indicator now becomes its own MISP Event, with the case number (and optionally
the case title) in the Event
infofield. A single global Event covers published indicators that aren’t associated with any case. Every attribute carries its owntlp:*tag matching the indicator’s TLP, and the event’s distribution level is set to the strictest TLP present (one AMBER+STRICT attribute forces the whole event to organisation-internal sharing). Analysis state reflects the case status — open cases are ongoing, closed/archived cases are complete. Indicators that appear in multiple cases publish as distinct attributes in each case’s event so MISP’s correlation engine links them back together. - Split TAXII / MISP Scopes on API Keys: API keys now have two independent scope toggles — TAXII 2.1 server and MISP feed — instead of a single “Can access MISP feed” checkbox. A key can be scoped to one service, both, or neither (neither lets you temporarily suspend a key without deleting it). A warning shows in the edit modal and a “No access” pill on the key list when a key has no scopes.
- Global Enrichment Cache TTL: A single global debounce value (default 6 hours) replaces the per-provider cache TTL selector. It only gates the auto-run path — the manual Run and Refresh buttons always re-query the provider, so you can always force a fresh lookup when you need one.
- Publish & Auto-Revoke from Slack: The
/dfire ioc addand/dfire ioc updatemodals now include a “Publish to external consumers (TAXII / MISP feed)” checkbox and an “Auto-revoke date” picker, mirroring the web sidebar. Responders can create and publish an indicator in a single Slack action instead of bouncing to the web. TLP:RED and revoked indicators are hard-gated identically to the web, with the reason surfaced back in Slack. - Classification & Confidence in the MISP Feed: Indicators published to the
MISP feed now carry
classification:benign|suspicious|maliciousandconfidence:low|medium|hightags per attribute, so downstream MISP instances can search and filter DFIRe indicators by those values like any other tag. - Enrichment Summary in the Case IOC Tab: The IOC tab on a case now shows the same compact coloured enrichment heatmap as the global IOC registry — one block per provider that has looked at the indicator, so you can see at a glance which IOCs have been enriched and what the providers found without opening each one.
- Connection Overlay for Server Outages: When the backend becomes unreachable (container restart, network interruption, proxy downtime), DFIRe shows a single “No connection to server — trying to reconnect…” panel with a spinner instead of a flood of identical red toasts. It disappears automatically once the server is back. The panel shows the observed error category (HTTP 502, network error, request timed out) as a factual hint and surfaces a “contact the server administrator” line after a sustained outage.
- Legal Entities Surface in
/dfire search: The Slack search command used to miss legal entities entirely — searching for “cloudflare” on the web would find the Cloudflare Abuse Team entity, but the same query via/dfire search cloudflarewould say “No matches.” The Slack command now uses the same shared search service as the rest of the app, so legal entities and projects show up in results alongside cases, evidence items, case notes, and indicators. Case-access scoping is unchanged — you still only see content on cases you have permission to read. - Context-Coloured IOC Tags + Live Refresh on “Apply Tags”: Indicator
tags on the IOC detail page are no longer rendered in one low-contrast monochrome style.
maliciousreads red,benignreads green,suspiciousreads amber,tlp:*tags follow the standard TLP palette (clear / green / amber / amber+strict / red), andconfidence:*tags use blue shades — at-a-glance triage instead of squinting. Other tags keep a simple monochrome pill but with proper contrast in both light and dark themes. The Apply tags to IOC button in the MISP enrichment card now refreshes the indicator record inline, so newly applied tags appear in the sidebar immediately instead of requiring a hard page reload. The upper divider above the per-event tags in the MISP enrichment card is removed, tidying up the layout. - Richer MISP Attribute Output: Indicators published to the MISP feed now carry
two extra pieces of DFIRe-only context in the attribute
commentfield: a compact enrichment verdict summary (e.g. “Enriched: 2 malicious, 1 clean”) so downstream MISP consumers can triage on DFIRe’s prior enrichment work without re-querying the same providers, and a cross-case prevalence hint (e.g. “Seen in 4 DFIRe cases”) when the same indicator appears in multiple cases. Revoked or expired indicators now also set MISP’s canonicaldeleted: trueflag on the attribute rather than carrying a human-readable flag in the comment — consumer MISP instances soft-delete the attribute on the next feed fetch, removing it from correlation, IDS exports, and detection rules automatically, regardless of their feed configuration. - Upgrade note for MISP feed consumers: 1.3.0 published a handful of per-TLP
events; 1.3.1 publishes one event per case plus one unassociated-indicator event. Depending on
how many active cases you have, the feed can now produce many more events. If your consuming
MISP was set up before the upgrade, two long-latent MISP defaults can make the new multi-event
feed look broken: Fixed Event silently defaults to
trueon the MISP side when adding MISP-format feeds (collapsing everything into a single merged event), and MISP auto-blocklists any event UUID you delete from the UI (quietly skipping it on future fetches). See Indicators of Compromise — Troubleshooting the Consuming MISP for both workarounds. Neither affects DFIRe’s output; they’re consumer-side settings. - Separate Toggle for the Slack AI Assistant: System Settings → Integrations
→ Slack has a new AI Assistant card between Channel Settings and
Notifications. The toggle controls whether
/dfire assistantand/dfire askare available in Slack independently from whether an LLM provider is configured for the web app. Useful when your policy restricts AI features to the web app, or when the case channel is shared with people who should not be able to query case data via the assistant. When the toggle is off, the AI Assistant section is hidden from/dfire helpand/dfire help assistantfalls through to the overview, so the slash-command list only advertises commands the administrator has actually enabled. Defaults to on so existing 1.3.0 installs keep working on upgrade; turn it off if you want AI gated to the web only.
Fixed
- Audit Log on Indicator Edits: Editing an indicator’s classification, confidence, TLP, tags, notes, or expiration via the API now produces an audit log entry with the before/after diff. Previously these edits were not being audited at all. The log also captures the “TLP changed to RED → automatically unpublished” side effect in the same diff, so the auto-correction is visible on the audit trail as a distinct before/after rather than a silent state change.
- S3 IAM-Role Auth on ECS / EKS / EC2: S3 attachments stored under IAM-role authentication (ECS task role, EC2 instance profile, or EKS IRSA — no static access keys) were not accessible after upload. New uploads and the storage connection test worked, but any existing attachment failed to download or delete. IAM-role authentication now works for every attachment operation. Deployments using static access keys are unaffected.
- MISP Feed Rejected by MISP 2.5+: MISP 2.4.170 and later enforce a stricter feed
schema than earlier versions. DFIRe’s published events were missing the
protectedfield that MISP now requires on every feed event, and the tag objects were emitted in a minimal shape without thelocalandrelationship_typefields MISP’s validator expects. Newer MISP instances rejected affected events with “Could not parse event JSON from feed”, even though the JSON itself was syntactically valid. The feed output now matches PyMISP’s canonicalto_feed()shape —protected: falseis included, every tag carries the full canonical fields, and numeric values (timestamps, threat level, analysis state) are serialised as strings as MISP expects. Existing events re-publish in the compatible shape on the next feed pull. - Duplicate TLP / Classification Tags in MISP Feed After Enrichment Round-Trip:
An indicator that came back from a MISP enrichment via the Apply tags to IOC
button picks up whatever tags the MISP event carried — including its
tlp:*,classification:*, andconfidence:*tags. On the next publish DFIRe was emitting both the structural marker derived from the indicator’s actual TLP / classification / confidence fields and the back-synced user tag, producing two (possibly conflicting) markers per attribute. DFIRe’s structural values are now authoritative on publish: user tags with thetlp:,classification:, orconfidence:prefix are filtered out of the feed attribute’s tag list before the structural ones are appended. The tags remain on the indicator itself — the taxonomy lineage from MISP stays visible in the DFIRe UI, only the duplication on publish goes away. - Copy-Pasted Slack Images Silently Dropped: Images pasted into a Slack channel
always arrive with the generic filename
image.png. When a responder used the pushpin reaction to capture two such images into the same case, the second capture was silently dropped — the pin looked like it worked, but nothing showed up in the case. The web upload flow had the symmetric problem, rejecting the second upload with “File already exists.” DFIRe now auto-renames on filename collisions with OS-style numbering (image.png→image_2.png→image_3.png), scoped per case or per evidence item. On the web UI you see a toast confirming the rename; the pushpin confirmation in Slack reports the stored name (“📌 Image image_2.png saved to Photos”) so the message matches what lands in the case. The same Slack file re-pinned is still a no-op.
1.3.0 — April 16, 2026
Added
- Action Notes: Every action now has a dedicated note field separate from its description. Notes support markdown, keep a full edit history, and become read-only once the action is completed. Note changes appear on the case timeline and in the Slack channel, and can be edited inline from the Actions tab or when completing an action.
- Additional Details Field: Actions and runbook steps have a new Additional Details field for longer markdown context alongside the short description. Edit it in place by hovering over the action and clicking the pencil icon.
- Attach a Runbook to an Existing Action: You can now attach a runbook to an action you’ve already created, without having to delete and re-add it.
- Opt Out of Auto-Start on New Actions: When adding a new action, a “Start immediately” checkbox lets you create the action in a pending state instead of starting it right away. The checkbox is on by default, preserving the previous behaviour. The note field in the Add Action modal is also resizable now.
- Add Action in Slack Matches the Web Form: The Slack add-action dialog now includes the note, assignee, and runbook fields that are available in the web UI.
- Configurable Slack Notifications: You can now choose which case events post to Slack on a per-event-type basis. Action notes edited from the web now render in Slack with full markdown, and you can set an action’s note directly from Slack.
- Slack App Home and Shortcuts: The DFIRe app now has a Home tab in Slack that lists your linked account and recent activity, plus global and message shortcuts for creating a case and capturing a Slack message into a case. After upgrading, reinstall the app in Slack with the updated manifest so the new scopes are granted.
- @-Mention Autocomplete: Editors that forward content to Slack — case notes, action notes, and CAN reports — now offer an @-mention picker for any teammate whose DFIRe account is linked to Slack. Mentions render as real Slack pings in the channel.
- Channel Topic Mirrors the Case: The Slack channel topic stays in sync with the case’s phase, lead investigator, and status, so you can see at a glance where the case stands without opening DFIRe.
- Threaded Action Updates: Follow-up events for an action (notes, completion, reassignment) now thread under the original “Action Started” message in Slack, keeping the channel readable on busy cases.
- Quick Actions on Slack Cards: Action and timer messages in Slack now carry inline buttons for Mark done, Reassign, Skip, and Mark compliance met — one click from the channel, no need to open the web UI.
- New Slack Commands:
/dfire item note <n>pins a note to an evidence item,/dfire custodyrecords a chain-of-custody transfer,/dfire ioc enrichkicks off enrichment for an indicator, and/dfire search <query>searches across every case you can see (not just the channel’s case). Messages and files are still captured into the case by reacting with 📌 (:pushpin:). - Picker Modal for
/dfire assign: Running/dfire assignwith no arguments opens a combined picker so you can choose the action and the team member in one form. - Parent Item from Slack: The evidence add and edit modals in Slack now include a parent-item dropdown so you can nest evidence directly from the channel.
- Direct Message on Assignment: Assignees now receive a Slack DM the moment an action is assigned to them (whether from the web or a Slack command), with the action description, who assigned it, and a link back to DFIRe. The assignee can acknowledge by starting the action.
- AI Assistant in Slack: The AI assistant from the case detail page is now
available in the case channel via
/dfire assistant <question>(alias/dfire ask). Each call opens a new thread with the assistant’s answer; reply inside the thread to ask follow-up questions — the assistant picks them up automatically and keeps that thread’s context. Multiple assistant conversations can run in parallel in the same channel, each in its own thread with its own context and token counters./dfire assistant summary [topic]is a shorthand that opens a new thread with a preset case-summary prompt, optionally scoped to a topic./dfire assistant statuslists every thread you have open in the channel with a first-question excerpt, a click-through link, and per-thread token usage. Threads auto-expire an hour after their last message. The assistant works with whichever LLM provider is configured under System Settings → LLM (Anthropic, OpenAI, Gemini, or any other provider supported via LiteLLM); prompt caching is used where the provider supports it so follow-up questions in a warm conversation are cheaper — and because the cached prefix is the case data, switching between parallel threads on the same case carries no extra cost. The case data sent to the assistant is rebuilt from the live case state on every turn, so changes made to the case (new actions, new evidence, new reports) are immediately reflected. The assistant is read-only by design — it can answer and summarise, but cannot change the case. Multiple safety layers prevent runaway loops: bot messages and message edits are ignored, only linked DFIRe users with case access can ask follow-ups, a per-thread cooldown coalesces bursts, and a hard cap of 50 answers per thread prevents any conceivable feedback loop. Responses are rendered in Slack’s mrkdwn format so bold, links, bullets, and code blocks display correctly in the channel. Every Q/A is recorded in the audit log alongside the existing web-chat entries. - Hide Timeline Events Inline: The option to hide a timeline event from the case view is now available directly on each event via an icon, instead of being tucked inside the Edit dialog.
- Confirmation Before Skip or Reset: Skipping or resetting an action now asks for confirmation first, so a stray click can’t wipe out an in-progress action or its note.
- System Backup & Restore: Full encrypted database backup and disaster
recovery system accessible from System Settings. Backups use AES-256-GCM streaming encryption
with PBKDF2-HMAC-SHA256 key derivation (600,000 iterations), tied to the instance’s
SECRET_KEY. The backup is stored on the storage backend. Includes backup creation, download, upload, validation, and restore for superusers. - Scheduled Backups: Configurable automatic backup schedules with intervals from hourly to weekly. Schedule activates immediately on save. Next scheduled backup time displayed in the UI. Configurable retention policy automatically deletes old backups beyond the retention count.
- Deep Backup Validation: The Validate button decrypts every chunk of the backup file and verifies the SHA-256 checksum end-to-end. Displays the computed SHA-256 hash so administrators can compare it against a downloaded copy to verify integrity. Also checks migration compatibility and DFIRe version.
- Backup Upload & Sync: Upload encrypted backup files for disaster recovery. Sync from Storage button discovers backup files on the storage backend that aren’t yet tracked in the database (e.g., after a restore or manual file placement).
- Post-Restore Migration: After restoring an older backup on a newer DFIRe version, database migrations are automatically applied to bring the schema up to date. New tables and columns are created empty alongside the restored data.
Changed
- Action Description and Details Layout: In the Actions tab, the description and additional details now stack vertically (description on top, details below) instead of sitting side-by-side.
- Consistent Hidden-Event Design on the Timeline: Events that are hidden from the case report now look the same regardless of type — notes, actions, phase changes, and system events all get an amber “Hidden event” badge, a dashed border, an amber timeline dot, and a dimmed appearance. Previously some event types gave no visual indication they were hidden.
- Clearer Timeline Hover Controls: The View note, Edit, and Hide/Unhide controls on a timeline event are now separate icon buttons that don’t cover the event text, and they use distinct icons so the actions are easy to tell apart.
- PgBouncer Detection for Backups: The backup system now detects when the database is accessed through PgBouncer and uses a direct PostgreSQL connection URL when one is configured, so backup and restore work correctly in pooled deployments.
Fixed
- Workflow Decisions Lost When Spawning a Follow-Up Action: Completing a decision-tree action that spawns a follow-up action used to show “Action Completed” with just the question on the timeline, instead of “Workflow Completed” with the full decision path. Workflow answers are now persisted as you click through the tree, and the full decision tree is preserved in the completion event.
- TLP:AMBER+STRICT Downgraded to TLP:AMBER on Case IOCs: Creating an IOC from inside a case with classification TLP:AMBER+STRICT silently saved it as TLP:AMBER. The selected TLP level is now honored.
- Cannot Add Actions to Empty-Template Cases: Cases opened with a playbook that has no phases rejected new actions with an error. Actions can now be added to phaseless cases.
- Logo Preview Hid PNG Transparency: The organization logo preview in System Settings used to sit on a solid white background, so you couldn’t tell whether the uploaded PNG had transparency. The preview now shows a checkerboard pattern behind the logo, matching the convention used in image editors.
- Hidden Timeline Events Flickered on Unhide: After hiding an event, leaving the timeline, returning with “Show hidden events” enabled, and then unhiding the event, the just-unhidden event briefly reappeared as hidden until the page was refreshed. The timeline now refreshes all view variants together when an event is hidden or unhidden.
- Action Owner Showed as Plain Text: When an action was started, the “started by” field stored the user’s name as plain text instead of linking to the user record. This broke per-user filtering and reports. Newly started actions now correctly link to the user.
- Missing Migration on Upgrade: On some upgrade paths, a database migration introduced in this release was not picked up and the schema was left out of date. The migration is now applied correctly on upgrade.
- Recovery From Interrupted Upgrades: If a database migration is interrupted mid-run (for example, if the container is killed during an upgrade), DFIRe now recovers on the next startup instead of refusing to start.
- Action Note Rendering Glitch: Fixed a regression that could briefly show an empty workflow row before an action note finished saving.
Security
- Version Guard on Restore: Restoring a backup created on a newer DFIRe version than the running system is blocked. A backup from a newer version cannot be restored on a system running an older version, as the required migrations would not exist. The error message directs the administrator to upgrade first. Restores from older versions get migrations applied after restore to create missing tables.
- No Plaintext on Disk: Backup encryption and decryption use streaming 8MB chunks
— decrypted database content is never written to disk. Restore pipes decrypted data
directly to
pg_restorestdin. - Database Credentials in Environment: PostgreSQL passwords are passed to
pg_dump/pg_restorevia thePGPASSWORDenvironment variable instead of appearing in command-line arguments visible in/proc. - Concurrent Operation Guards: Only one backup creation and one restore operation can run at a time. Concurrent requests are rejected with 409 Conflict.
- Safe Settings Import on Startup: The default settings import that runs on container startup now uses retry logic with backoff when checking the database for an existing tenant configuration. Transient database connection errors (e.g., PgBouncer pool exhaustion or brief network interruption) are retried up to three times instead of being silently treated as a fresh install. If the database remains unreachable, the import is safely skipped and the server starts normally.
- Non-Destructive Settings Upsert: Settings import (groups, item flags, incident phases, investigation steps) now uses an upsert pattern instead of deleting all existing records and recreating them. Existing records that match by name are updated in place, preserving database primary keys and user-group membership associations. Only records absent from the import payload are removed.
- Tenant Cache Flush on Startup: The Redis tenant cache is cleared before the settings import check on container startup, preventing stale cached values from interfering with the tenant detection logic after database configuration changes.
- Backup-Restore Concurrency Guard: Scheduled automatic backups now check for
active restore operations before starting. If a database restore is queued or in progress, the
scheduled backup is skipped to prevent
pg_dumpfrom running against a database mid-restore. - XSS Sanitization on Action Notes and Details: Action notes and the new
additional_detailsfield are sanitized server-side viasanitize_markdown()on write, preventing stored XSS even if a malicious actor crafts a payload through a non-UI client.
1.2.10 — April 3, 2026
Added
- ENISA Incident Categories: New configurable incident classification based on the ENISA taxonomy. Cases can now be tagged with a category (e.g., Malicious Code, Intrusions, Availability) for standardized reporting and metrics. Seeded with 11 default categories; fully customizable in System Settings.
- Outcome Verdicts: Track case outcomes as True Positive, False Positive, Benign Positive, or Indeterminate. Configurable in System Settings with color-coded display. Dashboard statistics now include cases-by-category and cases-by-outcome breakdowns.
- Playbook Change: Change the playbook (case type) on an existing case via the
Edit Case modal, the REST API (
POST /api/cases/{id}/change-playbook/), or the MCPchange_playbooktool. Supports two modes: merge (keeps all existing actions, appends new ones) and replace (removes pending actions, keeps started/completed, adds new). Deduplicates actions by description. Restricted to the lead investigator or users with global write access. - Investigation Full Capabilities: Investigation-mode cases now have access to Timeline, Actions, Compliance tabs, and todo templates from playbooks — previously restricted to incident mode. An investigation phase gate restricts action modifications to the preparation phase until the case is escalated to an incident.
- New Relic Audit Log Output: Added a dedicated "New Relic" payload format option
for the audit log sender. Uses New Relic's proprietary Logs API structure with a
commonblock for shared batch attributes and alogsarray for individual entries, reducing payload size and enabling optimal ingestion. - Slack Commands for Investigations: Investigation-mode cases can now use action
management commands (
/dfire actions,done,take,assign,skip), timers, and event commands via Slack. The investigation phase gate is enforced — only preparation-phase actions can be modified until escalation.
Changed
-
Breaking Change — Audit Log Sender "JSON Batch"
Format:
The "JSON Batch" output format has changed. The previous format wrapped log entries in a
{"source": "dfire", "batch_id": "...", "sent_at": "...", "logs": [...]}envelope. The new format outputs a flat JSON array where batch metadata (batch_id,source) is injected into every individual log entry, and timestamps are epoch milliseconds instead of ISO-8601 strings. If you have a custom parser or SIEM integration consuming the JSON Batch format, you must update it to expect a flat array instead of a wrapper object. The NDJSON and Elasticsearch Bulk formats are unchanged.
Fixed
- Legal Entity Deletion Error: Deleting a legal entity referenced by custody transfers no longer returns a server error. The API now returns a clear error message explaining that the entity cannot be deleted while custody transfer records reference it.
- Collaboration Message Endpoint: Sending an empty or invalid POST request to the
collaboration messages endpoint no longer causes a server error. The endpoint now correctly
returns 405 Method Not Allowed, directing callers to use the
/send/action instead. - Notification Message Endpoint: Sending an empty or invalid POST request to the
notifications message endpoint no longer causes a server error. The endpoint now correctly
returns 405 Method Not Allowed, directing callers to use the
/toast/action instead. - Collaboration Sync Error Response: When a manual Slack channel sync fails due to an external service error, the API now returns 502 Bad Gateway instead of 500 Internal Server Error, correctly indicating that the failure originated in the upstream service.
Security
- Slack Phase Gate Enforcement: Slack command handlers (
done,take,assign,skip) now enforce the investigation phase gate, preventing modification of non-preparation-phase actions on investigation cases. Previously, these commands bypassed the gate that the REST API and MCP tools enforced. - XSS Sanitization: Added server-side
sanitize_markdown()to Case title, todo action descriptions, and IncidentCategory/OutcomeVerdict description fields. Previously, the case title relied solely on frontend escaping. - Input Validation: OutcomeVerdict color field now validates against a backend whitelist of allowed Tailwind color names.
1.2.9 — April 1, 2026
Added
- Webhook Triggers for Runbook Steps: Runbook steps can now optionally trigger
webhooks when marked complete. A new
trigger_tagfield on each step acts as a filterable identifier. A newrunbook_step_completedwebhook event type fires on step completion, and the existing content filter (regex) on webhook configurations matches against the trigger tag for selective triggering. Supports both case action runbooks and evidence item runbooks. - Trigger Tag Editor: Runbook step editor in System Settings now includes a collapsible “Add webhook trigger” link per step that expands into a tag input field. Default trigger tags are auto-generated as unique identifiers based on the runbook slug and step order.
- Webhook Variable Filtering: The webhook payload template editor now shows which template variables are available for the selected event type. Unavailable variable categories are visually dimmed in the cheat sheet.
- Trigger Tag Autocomplete: The webhook content filter input for
runbook_step_completedevents offers autocomplete suggestions from trigger tags defined across all runbooks. - Webhook Step Indicator: Runbook steps with a trigger tag now display a small webhook icon in both case action and evidence item views, with a tooltip showing the trigger tag value on hover.
Changed
- Webhook User Context: Webhook payloads now populate
user.*template variables with the actor who performed the action, rather than defaulting to the case lead investigator. Timeline events use the event actor, CAN reports use the report author, and runbook step completions use the user who toggled the step. - Content Filter Label: The webhook content filter field is labeled
“Trigger Tag (Regex)” when the
runbook_step_completedevent type is selected, clarifying what the filter matches against.
Fixed
- Stale Notification Links: Clicking a notification for a deleted evidence item no longer shows a bare “Item not found” dead end. The item detail page now shows a generic “Access Denied” message (matching the case detail convention) and auto-redirects to the dashboard after 3 seconds, with a “Return Immediately” button. The generic message avoids leaking whether the resource exists.
Security
- Package Age Cooldown: The build pipeline now enforces a 14-day cooldown on all dependency updates, protecting against supply chain attacks where a compromised maintainer publishes a malicious package version. Security patches for known CVEs are automatically exempted via OSV.dev lookup and applied immediately. Non-security updates must age for 14 days on the public registry before they can be included in a build.
- Hash-Verified Package Installs: Python packages are now installed with
--require-hashes --no-deps, enforcing SHA-256 hash verification from the lockfile. Previously, hashes were present in the lockfile but not verified at install time. - Pinned Base Images: All Docker base images are now pinned to SHA-256 digests instead of floating tags, preventing compromised upstream images from propagating into builds.
- Pinned GitHub Actions: All CI/CD Actions are now pinned to commit SHAs instead of version tags, preventing compromised Actions from injecting code into the pipeline.
- Automated Dependency Management: Renovate manages all dependency updates across Python, npm, GitHub Actions, and Docker. Non-security updates trail the latest release by 14 days. Security patches for known CVEs bypass the delay and are proposed immediately. A CI safety net script blocks manual dependency changes that violate the cooldown.
- AI Prompt Injection Hardening: All AI-powered report generation prompts (CAN reports, investigation report sections, and case chat) now include a data provenance warning instructing the LLM to treat case data as untrusted input. This mitigates prompt injection attacks where adversary-controlled content in case fields (IOC values, notes, timeline entries) could manipulate AI-generated output. The warning is enforced at the application level and cannot be removed via the prompt template editor.
Deprecated
- Incoming Webhooks: Creation of new incoming webhooks is now blocked. Existing
webhooks continue to function, but the feature will be removed in v1.3.0. Use
User API Keys with the standard Cases API (
POST /api/cases/) or the import endpoint (POST /api/cases/import/) instead. API keys provide proper RBAC, per-user audit trails, and granular permission control.
1.2.8 — March 27, 2026
Added
- Chain of Custody: Formal custody tracking for evidence items with four transfer types (intake, transfer, correction, released), chain continuity enforcement, and automatic location sync. Custody transfers are immutable records that cannot be edited or deleted. Each transfer records the from/to parties (legal entities or DFIRe users), location, timestamp, purpose, condition, and notes. Transfer and release types enforce chain continuity — the from party must match the current custodian. Corrections require explanatory notes.
- Custody Receipt: Printable chain of custody receipt accessible from the evidence Custody tab. Opens in a clean browser tab for printing with item details, all custody transfers in a two-row-per-entry table format, and a disclaimer that the electronic record in DFIRe is the authoritative document.
- Custody Timeline Events: Custody transfers automatically create
CUSTODY_TRANSFERtimeline events in the associated case, recording transfer type, parties, and location. - Custodian in Sidebar: Evidence item sidebar now shows the current custodian derived from the latest chain of custody entry. Shows “No record” when no custody chain exists, or “Released from custody” when the last transfer was a release. Custodian entities are clickable links to the entity detail.
- Item Runbooks: Evidence items can have procedural runbooks attached as step-by-step checklists. Runbooks are automatically attached based on evidence type defaults when items are created, and can be manually attached or detached from the Runbooks tab. Each attached runbook stores a snapshot of steps with per-step completion tracking.
- Evidence Type Default Runbooks: Evidence types can be configured with default runbooks that are auto-attached when new items of that type are created. Configured in System Settings > Evidence Types via a slug-based dropdown selector.
- 14 Default Runbooks: Comprehensive set of evidence handling and technical operation runbooks shipped as defaults: Hard Drive Acquisition & Handling, Flash Media Acquisition & Handling, Memory Image Verification & Processing, Disk Image Verification & Integrity, Mobile Device Intake & Preservation, Computer Intake & Preservation, Log File Integrity & Processing, Malware Sample Safe Handling, Network Capture Verification & Processing, Account Evidence Preservation, Cloud Resource Evidence Preservation, Endpoint Containment, Evidence Collection – Workstation, and Reset User Password and Sessions.
- Runbook Assignments on Actions: 12 case type actions across 5 case types now have runbooks attached for specific technical procedures (endpoint isolation, credential reset, device seizure, volatile memory capture, malware sample handling).
- Related Evidence: “Add Related Evidence” button on evidence item detail view to create parent or child items directly, with a relationship selector (parent/child) in the modal.
- Tab Count Badges: Evidence item tabs (Notes, Runbooks, Custody, Attachments) now show count badges matching the Case view design pattern, with blue highlighting on the active tab.
- Runbooks Documentation: New
runbooks.htmldocumentation page explaining runbook concepts, evidence type and case type integration, default runbooks, management procedures, and API/MCP access. Runbooks link added to sidebar on all documentation pages. - Message of the Day: Configurable MOTD displayed on the login page. Supports markdown formatting. Administrators can enable and edit the message in System Settings to communicate notices to users before login (e.g., access instructions, maintenance windows, demo credentials).
- Dependency Viewer: SBOM viewer in System Settings showing Python (requirements.txt) and Node.js (package-lock.json) dependency manifests with search filtering. Allows superusers to verify installed package versions and integrity hashes directly from the UI.
Changed
- EULA v1.2: Updated End User License Agreement. Trial period extended from 30 to 90 days. Public IP address added to collected data disclosure (Section 4.2). Liability exclusion and liability cap clauses made mutual (Sections 8.1, 8.2). Assignment clause made mutual with merger/acquisition exception (Section 11.8). Corrected business location from Espoo to Vantaa. EULA version constant bumped to 1.2, triggering re-acceptance on existing installations.
- Third-Party Licenses: Comprehensive update to the public third-party licenses page. Added 16 missing Python dependencies (drf-spectacular, django-cors-headers, django-filter, dj-database-url, channels_redis, gunicorn, django-redis, bleach, whitenoise, python-magic, jira, slack_bolt, litellm, python-whois, python-dotenv, PyYAML) and 4 missing frontend dependencies (PrismJS, react-simple-code-editor, rehype-sanitize, remark-gfm). Added new Integrations section for Jira, Slack Bolt, and LiteLLM. Reorganized transitive dependencies (Twisted, Autobahn, zope.interface, Pydantic, HTTPX) into a dedicated section with parent package attribution. Updated Redis server license from BSD-3-Clause to RSALv2/SSPLv1 (v7.4+). Added callout notes explaining LGPL, MPL-2.0, and Redis license terms for commercial use. Added HPND, BlueOak-1.0.0, and PostgreSQL License to the license summary table.
- Evidence Item Tabs: Tab bar now uses
flex-1styling to span full width evenly, matching the Case detail layout convention. - Ownership Labels: “Ownership & Custody” section in Add Evidence modal renamed to “Ownership & User Information”. “Select Custodian...” placeholder changed to “Select User...” to reflect the distinction between primary user and custodian.
- Add Evidence Modal Simplified: Removed the optional initial custody section from the Add Evidence modal. Custody is now recorded separately in the evidence Custody tab after item creation.
- Settings UI: Evidence Types and Runbooks management pages refactored from card layout to table layout for better information density.
- Evidence Type Editor: Modal narrowed, icon picker made collapsible, JSON editor uses syntax-highlighted editor with line numbers, runbook assignment uses slug-based dropdown.
- Evidence Documentation: Updated
evidence.htmlwith chain of custody section, runbooks tab documentation, custodian role explanation, and related evidence feature.
Fixed
- Sanitization Double-Escaping: Fixed
sanitize_markdown()double-escaping ampersands and other HTML entities in text fields (e.g., “Memory Image Verification & Processing” now correctly stores “Memory Image Verification & Processing”). - Settings Import/Export: Fixed runbooks not appearing in import preview and evidence type default runbook assignments not being exported or imported.
1.2.7 — March 22, 2026
Added
- Runbooks: New global, reusable procedural checklists that can be attached to
case actions. Each runbook has a name, description, and an ordered list of steps. When attached
to an action, a snapshot of the runbook steps is stored with per-step completion tracking.
Runbooks are managed in System Settings alongside case types and evidence types. API:
GET/POST /api/runbooks/,GET/PUT/PATCH/DELETE /api/runbooks/:id/. - Runbook Attachment on Actions: Actions can have a runbook attached via the
runbook_slugfield when creating or updating a todo item. Clicking a runbook-attached action opens a modal showing the step checklist. Steps can be individually toggled as complete. Runbooks work as passive checklists — completing all steps does not auto-complete the parent action. - Workflow Runbook Integration: Workflow decision trees now support an “Attach runbook” result type alongside “Spawn action”, “Complete workflow”, and “Follow-up question”. When a workflow resolves to a runbook-attached terminal, the spawned action automatically has the selected runbook initialized.
- Runbook Status in Timeline: When an action with an attached runbook is marked
as completed, the
TODO_COMPLETEDtimeline event includes runbook progress. Fully completed runbooks show “completed”, partial ones show “X out of Y steps completed”. The timeline renders a styled badge (green for complete, amber for partial) below the action description. - Playbook Designer: New full-screen visual editor for case type playbooks,
replacing the previous modal-based editor. Features a scrollspy phase index, inline workflow
tree editing with hierarchical connector lines, drag-and-drop action reordering, and a
Visual/JSON toggle with syntax-highlighted JSON editor supporting line numbers. The JSON editor
enables copy-paste workflows for LLM-assisted playbook drafting. Automatically resolves
phase_ordertophase_idwhen pasting JSON from settings exports. - Runbook JSON Editor: Runbook editing in System Settings now includes a Visual/JSON toggle, matching the playbook designer pattern. Enables bulk editing and LLM-generated runbook import via JSON.
- MCP: Runbook Tools: New
manage_runbook_stepsMCP tool for toggling runbook step completion. Theget_reference_datatool now supports therunbooksdata type. Workflow resolution viamanage_workflowhandles runbook-attached terminals. - Settings Export/Import: Runbooks are included in system settings export and import alongside case types, evidence types, and other configuration data.
- Spur.us Enrichment Provider: New IP intelligence enrichment provider (13th total). Spur specializes in unmasking anonymized infrastructure — residential proxy detection, VPN/Tor attribution (1000+ services), bot detection, and deep contextual IP data. Enrichment results are rendered in a structured key-value layout with risk indicators, tunnel details, client intelligence, and direct links to Spur.
- Enrichment History & Change Detection: Re-running enrichments now preserves historical snapshots when meaningful data changes are detected. Each provider defines which fields are transient (counters, timestamps) versus stable intelligence. When a re-enrichment produces different results, the previous data is saved as a snapshot. Investigators can browse revision dates per provider with inline change highlighting (amber left-border markers on changed fields). No history is stored when results are unchanged.
- IOC Search-on-Add: The Add IOC modal now performs a debounced background search as the investigator types. If the IOC already exists in the registry, an info banner shows the case count, classification, confidence, TLP, tags, and first seen date. The classification, confidence, TLP, and tag fields are locked to the existing global values (editable only from the IOC intelligence page). Expired indicators are shown with an expiration notice; revoked indicators are excluded from matches.
- Anonymized Cross-Case IOC Associations: The IOC intelligence page and sidebar
now show case associations the investigator cannot access. Restricted cases display only the
case number, status, and lead investigator name with a lock icon and “Contact for
details” prompt. This surfaces cross-case correlation signals while maintaining case-level
separation of duties. The MCP
get_correlated_indicatorstool also returns restricted case data.
Changed
- Case Types Renamed to Playbooks: The System Settings tab for case types is now labeled “Playbooks”. The edit button opens the full-screen Playbook Designer instead of the modal editor. The create button links to the Playbook Designer with the label “Create New Case Type Playbook”. Evidence types retain the existing modal editor.
- Report Editor — Copy Full Report: New “Copy Full Report” button in the report editor sidebar copies all non-excluded sections with content to the clipboard as a single Markdown document, enabling quick export to external platforms.
- Report Editor — QA Workflow Improvements: The “Ready for QA” button has been renamed to “Mark as Ready for QA” for clarity. Sections in the “Ready for QA” state now show a “Return to Draft” button, allowing investigators to revert without completing and then revoking QA.
Security
- Dependency Pinning with Hash Verification: All Python dependencies are now
managed via pip-tools with
--generate-hashes. The lockfile (requirements.txt) includes SHA256 hashes for every package, ensuring pip refuses to install packages whose content doesn’t match the verified hashes. This protects against supply-chain attacks where a malicious actor uploads a compromised package under an existing version number. - CI Vulnerability Scanning: Added
pip-auditjob to the CI pipeline. Docker image builds are now blocked if any Python dependency has a known vulnerability with an available fix. This runs automatically on every push and pull request to the main branch.
1.2.6 — March 18, 2026
Added
- Webhook: CAN Report Trigger: New
can_report_updatedwebhook event fires when a CAN (Conditions, Actions, Needs) report is created. Providescan.*template variables (conditions,actions,needs,version,created_by,created_at) for flexible payload formatting. - Webhook: User Notification Trigger: New
user_notificationwebhook event fires when an actionable in-app notification is created (case assignments, IOC correlations, timer warnings, etc.). Toast messages (UI feedback) are excluded. Providesmessage.*template variables (title,body,type,sender_name,target_model,target_id,case_id,created_at). Enables external alerting via email (Mailgun, SendGrid) or messaging (Slack) when users receive important notifications. - Webhook: User Context Variables: New
user.*template variables available across all webhook triggers. On case-scoped events,user.*is populated from the case's lead investigator. On user notification events, it's populated from the notification recipient. Includesid,username,email,first_name,last_name,phone_number,timezone,slack_user_id, andslack_username. - Webhook: Form Data Support: Webhooks can now send payloads as
application/x-www-form-urlencodedinstead of JSON. This enables direct integration with APIs that require form-encoded requests, such as Mailgun's email sending API. Configurable per webhook via a "Send as Form Data" toggle. - Case Import/Export: Full case data can be exported as JSON and imported into
the same or another DFIRe instance. Export via
GET /api/cases/<id>/export/with standard authentication and RBAC. Import viaPOST /api/cases/import/(create new case) orPUT /api/cases/<id>/import/(update existing). Includes indicator import for case-associated IOCs. Frontend import modal with file upload, diff preview, and create/update flow. Original case number preserved as a case note on import. - Case Description on Case Report Page: The case description field has been
elevated from the collapsed sidebar to the top of the Case Report tab, giving it a prominent
position as the opening paragraph for anyone reviewing a case. The description now renders full
Markdown (headings, bold, links, tables, code blocks, etc.) via the same
MarkdownDisplaycomponent used for case notes and CAN reports. - API Documentation Summaries: All REST API endpoints now include human-readable
summaryannotations in the OpenAPI schema, improving the ReDoc documentation at/api/docs/with clear, descriptive operation titles. - My Actions Filter: New “My Actions” filter button on the incident Actions tab shows only actions assigned to the current user. Displays a count of open assigned actions in the button label. Filter state is preserved in the URL for deep-linking.
- Open Actions Badge: Incident case cards on the dashboard now display a clickable “My actions” badge when the current user has open actions assigned. Clicking the badge navigates directly to the case’s Actions tab with the My Actions filter pre-selected.
- Server Time Clock: The application header now displays a live server time clock with timezone, visible across all views.
- Organization Logo: Administrators can upload a custom organization logo in Global Settings that replaces the default DFIRe logo in the application header. The same logo is used on printable report title pages. Falls back to the DFIRe logo when no custom logo is uploaded.
- Adversary Activity Timeline Events: Manual timeline entries can now be marked as adversary activity to distinguish attacker actions from IR team actions. Adversary events are visually distinct with a red dashed border, skull icon, and dark background on the timeline. The printable investigation report uses a red background with skull icon for adversary entries. A dedicated “Adversary Activity” filter option is available in the timeline filter dropdown. The adversary flag can be toggled when creating or editing manual entries, and is preserved through case export/import. MCP tool support included.
Improved
- Webhook: Parallel Delivery: Multiple webhooks listening for the same event are now delivered in parallel via separate background tasks, instead of serially. A slow or timed-out webhook no longer blocks delivery to others.
- Webhook: Default Payload Completeness: IOC data (
ioc.*) and compliance timer data (timer.*) are now included in the default payload when no custom template is configured. Previously these were silently dropped. - Webhook: Delivery Record Traceability: The
event_idfield on delivery records now falls back through all context ID types (case, timeline event, indicator, message, CAN report) instead of only case and timeline event. IOC and notification webhook deliveries are now traceable. - Webhook: Test Delivery User Context: The test delivery button now populates
user.*with the logged-in user's real data instead of dummy values, making test emails and messages more predictable. - Incoming Webhooks: Deprecated in favor of outgoing webhook triggers with the
new event types. Existing incoming webhook endpoints remain functional but display a deprecation
banner in the UI and return a
Deprecationresponse header. - Case Report Page Consistency: All three sections on the Case Report page (Case Description, CAN Report, Case Report) now have consistent amber icons in their headings, improving visual flow and navigation.
- Action Done Button Clarity: The “mark as done” button on in-progress actions now uses a pulsing ring animation instead of a spinning border (which looked like a loading indicator) and includes an explicit “Done” label below the icon.
- Action Completion Modal: The “Dismiss” button on the action completion note modal has been renamed to “Skip note” to clarify that clicking it skips the optional note rather than dismissing the completion.
- OpenAPI Schema: Case Indicators: The
POST /api/cases/{id}/indicators/endpoint now correctly documents the requiredvalueandstix_typefields in the request schema, along with all optional fields (classification,confidence,tlp,tags,context,source,decompose,valid_until,publish). - OpenAPI Schema: Compliance Timers: The
POST /api/cases/{id}/timers/endpoint now documents the requiredtimer_definition_idand optionalstart_timefields in the request schema. - OpenAPI Schema: Action Endpoints: The create, update, and assign action
endpoints now document their actual request fields instead of incorrectly showing the full
CaseSerializerschema. - Report Section Template: The “Conclusions and Recommendations” report section is now included in investigation-mode cases (was previously incident-only). Existing investigation reports will pick up the section automatically on next access.
- API Key Expiration: The API key expiration date picker now uses a date-only selector instead of datetime, with the time automatically set to 23:59. API key lifetime is measured in days.
- License Settings: The “Send usage data” toggle is now hidden when an offline license is active, since offline systems never contact the license server. Version upgrade release notes now render as Markdown instead of plain text.
- Tenant Settings: The Identity and Reporting sub-tabs have been consolidated into a single page. The report logo upload has been renamed to “Organization Logo” and is now also used in the application header.
Removed
- Legacy Case Export API: The standalone Case Export API key system
(
CaseExportApiKeymodel, dedicated endpoints, and settings UI) has been removed. Case export is now handled by the standard authenticated API at/api/cases/<id>/export/using User API Keys or session authentication with full RBAC enforcement.
Fixed
- Attachment Item Link: Fixed chunked upload silently dropping the
itemparameter when bothcaseanditemwere provided. The upload now correctly links the attachment to the specified evidence item. Additionally, theitemfield on attachments is now writable viaPATCH, with validation ensuring the item belongs to the same case. - Workflow Export/Import: Fixed case export flattening workflow actions to plain
todo items, losing the
workflow_definition(decision tree structure) andworkflow_statefields. Both export and import now preserve the full workflow JSON so decision trees survive round-trips between instances. - Webhook: Custom Headers Not Saving: Fixed custom headers being cleared on save
due to an asymmetry between how
EncryptedJSONFieldreads (decrypted dict) and writes (expects encrypted input). The serializer now correctly round-trips custom header values. - Webhook: Bulk Notifications Not Triggering: Notifications created via
bulk_create()(e.g., when a user is added to a case team) did not fire theuser_notificationwebhook because Django'spost_savesignal is not emitted for bulk operations. Added explicit webhook event queuing in the notification utility functions. - Case Detail: Current User ID: Fixed the current user ID not being resolved
correctly on the case detail page. The stored user object uses
user_idbut the code was readingid, causing user-specific features (action assignments, action filtering) to silently fail. - Backdated Timeline Event Phase: Fixed manual timeline entries always being tagged with the case’s current phase, even when backdated to a time when a different phase was active. Backdated events now resolve their phase by examining phase change history — if the event falls between two phase changes, it is assigned to the phase that was active at that time. Events predating all phase changes are assigned to the first configured phase.
1.2.5 — March 15, 2026
Added
- MCP Server: Built-in Model Context Protocol server that enables AI agents to act as virtual incident responders. Connect any MCP-compatible client (Claude Code, Google Antigravity, or other Streamable HTTP clients) to manage cases, track evidence, triage IOCs, and coordinate incident response through natural language. 48 tools across 9 groups (cases, items, notes, actions, indicators, timeline, timers, reports, search) with full RBAC enforcement, audit logging, and per-group enable/disable controls. See MCP Server documentation.
- MCP Resources: Contextual documentation resources served via MCP for case workflows, IOC management, incident phases, actions & workflows, compliance timers, and reports. Dynamic configuration resources for case types and item types with live schema data.
- MCP Prompt Templates: Pre-built workflow prompts for incident response, IOC triage, and case handoff that MCP clients can use as starting points for common tasks.
- MCP Settings UI: Administration page under Settings > Integrations > MCP Server for enabling/disabling the server and toggling individual tool groups. Displays endpoint URL and connection instructions.
- MCP Server Documentation: New documentation page covering tool groups, resources, prompts, client configuration, authentication, security model, and protocol details.
Improved
- Investigation Report Layout: Sidebar and report key-value layouts changed from two-column to stacked label-above-value to prevent overflow with long values (URLs, hashes).
- Report Status Indicators: Report version and Draft/Final status now displayed on the title page cover. Report sections that have not passed QA review show [DRAFT] or [REVIEW] indicators with background tinting.
- Report Title Page: Lead investigator added to the investigation team list. Fixed tenant organization name not displaying. Removed redundant page break from case details section.
- Print Preview: Added visible page break indicators in browser preview (hidden in print output).
Security
- SSRF Redirect Protection: Disabled HTTP redirects
(
allow_redirects=False) on IOC webhook triggers and SIEM log sender to prevent redirect-based SSRF. Added SSRF validation on SIEM sender endpoint URLs and OIDC profile picture URLs. - RBAC Hardening: Enrichment configuration now requires superuser access (was
dfireRolePermission). Case export views enforce Tier 1 capability check (core.view_case). CaseNote creation scopes case lookup viaCase.objects.for_user(). - Timeline Write Protection: Removed admin bypass on timeline events for CLOSED/ARCHIVED cases. Write protection is now absolute regardless of permission level.
- Audit Logging Expansion: API key authentication failures now logged to AuditLog
with key prefix, IP, and attempt count. Permission denials create
SECURITY_VIOLATIONaudit entries. Webhook, TAXII, timer, and SIEM sender mutations now audit-logged. System settings audit is fail-closed. - WebSocket Connection Limits: Concurrent WebSocket connections limited to 20 per user using atomic cache counters.
- IOC Extraction Rate Limiting: IOC text extraction endpoint rate-limited to 30 requests per minute.
- API Key Brute-Force Race Safety: Brute-force counter uses atomic
cache.incr()to prevent race conditions under concurrent requests. - Case Export Timing Normalization: Case export API key authentication uses constant-time dummy comparison on hash miss to prevent timing side-channel attacks.
- MCP Security Hardening: Tool error messages no longer expose exception details to clients. MCP registry sanitizes arguments to only schema-declared keys. Prompt arguments validated as numeric to prevent injection. Tool execution enforces permissions via registry before execution.
- XSS Prevention: Applied
sanitize_markdown()to all user-writable text fields across MCP tools (title, name, location, external_id, public_notes, context) to prevent stored XSS. - Case Update Write Protection Fix: Fixed a gap where field updates combined with status changes could bypass write protection. Field updates now always occur while the case is in OPEN state.
1.2.4 — March 14, 2026
Added
- User API Keys: Per-user API keys for programmatic access to the DFIRe REST API.
Keys use Bearer token authentication (
Authorization: Bearer dfire_ak_...) and inherit the user's full RBAC permissions. Raw keys are shown once at creation and stored as SHA-256 hashes. Includes enable/disable, regeneration, expiration enforcement, and per-key usage tracking (last used timestamp, IP address, total requests). - Service Accounts: Dedicated user accounts for automated integrations. Service accounts authenticate exclusively via API key — password login and SSO are blocked. Hidden from non-admin user listings.
- API Key Management UI: New API Keys tab in user settings for creating, viewing, enabling/disabling, regenerating, and deleting keys. Administrators can manage any user's keys from the user detail view.
- Admin Key Revocation on Password Change: When an administrator changes another user's password, all of that user's enabled API keys are automatically disabled as a security measure.
- API Key Tenant Policy: Configurable limits in Global Settings for maximum keys per user (default 3) and maximum key lifetime (default 365 days).
- Built-in API Documentation: Interactive API reference at
/api/docs/(ReDoc) and downloadable OpenAPI 3.0 schema at/api/docs/schema/, powered by drf-spectacular. Both endpoints require authentication. Links available in Global Settings. - API Access Documentation: New documentation page covering API key creation, service accounts, authentication examples, and security best practices.
Improved
- OpenAPI Schema Annotations: Added
@extend_schemaannotations to ~70 endpoints including binary downloads, CSV exports, SSE streaming, chunked uploads, IOC bulk operations, search, and statistics for accurate auto-generated API documentation. - Global Settings UI: Added API Key Policy section (max keys per user, max lifetime) and API Documentation links to the tenant settings page.
- Configurable LLM API Endpoints: All LLM providers (OpenAI, Anthropic, Gemini, Azure OpenAI, GitHub Models) now expose an optional API Base URL field in the settings UI. This enables connecting to any OpenAI API-compatible service (e.g. Together AI, Groq, Mistral, DeepSeek, Fireworks, Ollama, vLLM, LM Studio) by setting a custom base URL on the OpenAI provider, or routing through organizational API proxies. Each provider shows the default endpoint as placeholder text and contextual help. All custom URLs are validated against SSRF rules.
Security
- API Key Brute-Force Protection: Cache-based per-IP rate limiting on API key authentication failures. After 10 failed attempts within 5 minutes, further authentication is blocked for 10 minutes. Successful authentication resets the counter.
- Timing Attack Normalization: API key hash comparison uses
hmac.compare_digest()to prevent timing side-channel attacks. Hash miss path performs a dummy comparison to normalize response time.
1.2.3 — March 9, 2026
Added
- Slack IOC Commands: Three new
/dfireslash commands for managing Indicators of Compromise directly from Slack case channels:/dfire ioc— List all IOCs linked to the case with type, value, classification, confidence, TLP, tags, and context notes. Each entry links to the IOC intelligence page in the web UI./dfire ioc add [value]— Open a modal form to add a new IOC to the case. Supports STIX type selection, classification, confidence, TLP, context notes, and comma-separated tags. The value field can be pre-filled from the command argument. UsesIndicatorService.add_to_case()with full auto-decomposition and cross-case correlation./dfire ioc update <n>— Open a modal form to edit an existing IOC's classification, confidence, TLP, tags, and case-private context note. The IOC number corresponds to the list order from/dfire ioc.
Fixed
- Settings Test Connection Field Clearing: Fixed a bug where clicking "Test
Connection" in system settings (Slack, LLM, Storage, etc.) would clear all configuration fields,
forcing re-entry. Root cause was an unstable React context value in
ToastProviderthat triggered unnecessary re-renders and data re-fetches on every toast notification. Resolved by memoizing the context value. - Slack Enable Toggle Missing: Restored the missing Enable/Disable toggle on the
Slack Integration settings page. The
enabledfield existed in state but had no UI control, making it impossible to turn the integration on.
1.2.2 — March 6, 2026
Added
- LLM Backend Configuration: LLM integration with support for OpenAI, Anthropic, Google Gemini, Azure OpenAI, and GitHub Models. Configurable model, API key, base URL, temperature, and max tokens from the Settings UI. Connection testing from settings with real-time status indicator.
- Case Data JSON Export: New
/api/cases/{id}/export/json/endpoint for exporting structured case data as JSON, authenticated via API key. Intended for external integrations and LLM context feeding. - AI-Powered CAN Report Generation: Generate Conditions, Actions, and Needs (CAN) reports using the configured LLM provider. Case data is automatically minified for token efficiency, and the AI returns structured JSON with Markdown content for each section.
- AI-Powered Report Section Generation: Generate content for individual
investigation report sections using AI. Each section template can have its own AI prompt with
support for
{case_data},{section_title}, and{writing_guide}template variables. - AI Prompt Transparency: CAN report settings expose both the built-in system message (read-only) and the user-editable prompt, so administrators can understand exactly what is sent to the LLM. Additional free-text instructions can be provided per-generation.
- Default Section AI Prompt: Built-in default prompt template for report section AI generation, available via a "Use Default Prompt" button in section template settings. Provides a starting point that administrators can customize per section.
- Case Data Minification for LLM: Post-processing pipeline that optimizes case data before sending to the LLM: strips empty/null values, removes internal UUIDs, filters inactive todo items, simplifies indicator data to analytical essentials (classification, confidence, enrichment conclusions), limits CAN report history, and removes UI-only flags.
Improved
- Report Section Templates UI: Refactored the Report Section Templates settings page from a table-and-modal layout to an expandable card layout. Multiple cards can be open simultaneously for easy comparison. Collapsed cards show a summary of configuration (order, title, type, case modes, page break, AI status). Inline editing with larger text areas for writing guides, default content, and AI prompts.
- LLM Settings UI: Free-text model input (replacing dropdown) for flexibility with any LiteLLM-supported model string, temperature and max tokens controls, and a clear API key button.
Security
- Case Export Fail-Closed Audit: The case data JSON export endpoint follows the project's fail-closed audit pattern — if the audit log write fails, the export is blocked with a 503 response. This ensures every export is traceable, especially for API key-authenticated requests where the audit trail is the primary accountability mechanism.
- Case Export & LLM Rate Limiting: Scoped rate throttles on the case export endpoint (60 req/min) and AI report generation endpoints (10 req/min) to prevent bulk data exfiltration via compromised API keys and limit LLM provider cost exposure from rapid-fire generation requests.
- LLM Endpoint SSRF Validation: Custom LLM
api_baseURLs are validated against the same SSRF rules used for outgoing webhooks, blocking loopback (127.0.0.0/8), link-local (169.254.0.0/16, including cloud metadata at 169.254.169.254), and self-referential addresses. Applied on both configuration save and connection test. - LLM Configuration Audit Logging: All changes to LLM configuration (provider
enable/disable, model changes, API key rotations, base URL changes) are recorded in the audit
log with field-level detail. API key values are excluded from the audit entry; only a boolean
api_key_changedflag is logged. - Scoped Enrichment Data Export: Case data JSON export includes only enrichment metadata (provider, severity, timestamp) rather than raw provider response payloads, reducing the data surface area and preventing leakage of full threat intelligence reports through the export API.
- Markdown Sanitization Protocol Allowlist: The
sanitize_markdown()function now restricts linkhrefvalues tohttp,https, andmailtoprotocols, blockingjavascript:URIs. This hardens all Markdown output paths including LLM-generated report content. - AI Instruction Length Limit: Free-text
additional_instructionson AI generation requests are capped at 10,000 characters to bound token usage and prevent cost amplification through oversized prompts.
1.2.1 — March 2, 2026
Security
- TLP:RED Enforcement: MISP feed and TAXII collection queries now hard-filter
TLP:RED indicators at the database layer, preventing accidental publication regardless of
is_publishedstate - OIDC Issuer Validation: Added
issclaim verification in OIDC token validation using PyJWT'sissuerparameter to prevent token substitution from rogue identity providers - Dead Token Code Removal: Removed unused JWT token generation code
(
generate_token/decode_token) that referenced a hardcoded secret key - PKCE Support: OIDC authentication now generates and validates PKCE code challenges (RFC 7636) stored in the session, with graceful fallback for providers that don't support it
- Azure AD Regex Fix: Tightened OIDC issuer URL regex to
^https://login\.microsoftonline\.com/[a-f0-9-]{36}/v2\.0$, preventing open-redirect-style issuer spoofing - Jira SSRF Validation: Added
validate_webhook_url()SSRF check and Jira Cloud URL enforcement (*.atlassian.net) to Jira instance URL validation - IDOR Fixes: Scoped collaboration view and audit log item_context lookups
through
Case.objects.for_user(user)to prevent unauthorized access via direct object IDs - WebSocket Protocol Fix: Rate-limited connections now set a
scope['rate_limited']flag and close after ASGI accept, fixing a protocol violation that sentwebsocket.closebefore handshake - WebSocket Message Validation: Added pre-parse size limit (10KB), JSON depth check (max 5), and message type enumeration to all WebSocket consumers
- WebSocket Per-Message Rate Limiting: Added sliding-window rate limiter (30 msg/s) with auto-disconnect after 5 consecutive violations
- WebSocket Permission Re-validation:
report_presenceandediting_lockhandlers now re-check case permissions before processing - Nginx Host Header: Replaced hardcoded
proxy_set_header Host localhostwithproxy_set_header Host $hostacross all proxy locations - Jira Inbound Sanitization: Applied
sanitize_markdown()to inbound Jira summary and assignee display names to prevent stored XSS - Webhook Payload Storage: Webhook delivery logs now store payload hash and size instead of full masked payload to reduce database bloat
- Webhook Regex Safety: Content filter regex execution uses Python 3.12
re.TIMEOUTwhen available, with input truncation fallback (64KB max) - IOC Enrichment Rate Limiting: Added per-provider rate limiting (30 req/min default) via Django cache to prevent API key exhaustion
- Session Key Validation: Added
request.session.save()aftercycle_key()in login and OIDC callback to ensure the new session key is persisted - Profile Picture Size Limit: Profile picture downloads now use streaming with a 32MB hard limit to prevent memory exhaustion
- CORS/CSRF Production Hardening: Production deployments without
CORS_ALLOWED_ORIGINSlog a warning and reject cross-origin requests instead of falling back to localhost.CSRF_TRUSTED_ORIGINSauto-derives fromCORS_ALLOWED_ORIGINSwhen not explicitly set. Non-HTTP services (qcluster, slack-socket) no longer require CORS/CSRF configuration to start - Docker Image Pinning: Added CI/CD digest pinning comments to all
FROMdirectives in both backend and frontend Dockerfiles - Docker File Permissions: Added
chmod 750on/app/mediaand/app/staticfilesin the backend production image - Log Sanitization: Added
SanitizeFilterto the logging pipeline that masks Authorization, Cookie, X-CSRFToken, and X-API-Key header values in log output - sessionStorage Migration: User profile cache moved from
localStoragetosessionStorageto scope data to the browser tab session - Frontend WebSocket Validation: Added type guard for incoming WebSocket messages
(validates
typeof message.type === 'string') before dispatch - RBAC Hardening:
GroupViewSetandPermissionViewSetnow usedfireRolePermissioninstead ofDjangoModelPermissions, with a lockout prevention guard that blocks removingchange_groupfrom the last group that has it
Fixed
- CI Key Length: CI environment
SECRET_KEYandCREDENTIAL_ENCRYPTION_KEYvalues lengthened to meet the new 32-character minimum, andALLOWED_HOSTS,CORS_ALLOWED_ORIGINS,CSRF_TRUSTED_ORIGINSadded to CI test environment - Non-HTTP Service Startup:
qclusterandslack-socketservices no longer crash on startup whenCORS_ALLOWED_ORIGINSandCSRF_TRUSTED_ORIGINSare not set, since these services do not serve HTTP requests
1.2.0 — February 26, 2026
Added
- IOC Registry: Full Indicator of Compromise management subsystem for tracking,
enriching, and correlating threat intelligence across cases.
- Global tenant-level indicator registry with 17 STIX 2.1 SCO types (IPv4, IPv6, domain, URL, email, file hash, MAC address, AS number, and more)
- Classification (unknown, benign, suspicious, malicious) and confidence (low, medium, high) tracking per indicator
- Automatic deduplication via normalized values with unique constraint on
(value_normalized, stix_type) - Hierarchical decomposition: URLs decompose into domain and apex domain, emails into domain, subdomains into parent domain, IPs into containing CIDR ranges
- Retroactive parent-child adoption when new indicators are added
- PostgreSQL full-text search with GIN index across indicator values, types, notes, and tags
- Tag-based organization with JSON array tags per indicator
- Case-scoped associations with private context notes visible only to the case team
- Cross-case correlation notifications when an IOC appears in multiple cases
- IOC included in global full-text search results
- Custom permissions:
manage_indicators,export_indicators,import_indicators
- IOC Enrichment: Multi-provider threat intelligence enrichment framework with 12
providers.
- Built-in providers (no API key required): DNS lookup, WHOIS lookup
- Threat intelligence providers: VirusTotal, AbuseIPDB, Shodan, GreyNoise, AlienVault OTX, URLScan.io
- Abuse.ch providers (shared API key group): URLhaus, MalwareBazaar, ThreatFox
- Reputation providers: Google Safe Browsing
- Per-provider enable/disable, API key management, and configurable TTL for cache staleness
- Provider connectivity test from settings UI
- Finding severity classification (clean, suspicious, malicious) per enrichment result
- Background enrichment via Django-Q2 with TTL-based re-enrichment
- IOC Import/Export: Multiple format support for bulk IOC management.
- CSV import and export (global and per-case)
- STIX 2.1 bundle import and export with SCO and SDO objects
- Plaintext import with automatic IOC extraction
- IOC extraction from free text using regex patterns for IPv4/IPv6, domains, URLs, emails, file hashes, MAC addresses, and CVE identifiers
- Extraction review modal for selecting which candidates to add
- IOC Frontend: Complete React UI for IOC management.
- Global IOC Dashboard with chained filters (STIX type, classification, confidence, tags, search) and pagination
- Intelligence Page per indicator with sidebar and tabbed layout (Details, Relations, Enrichment, Respond)
- Enrichment panel with multi-provider verdict banners and auto-poll during active enrichment
- Hierarchy tree visualization for IOC decomposition
- Case IOC tab with association management and private context notes
- 6 modals for adding, importing, extracting, and reviewing IOCs
- IOC Enrichment settings panel under System Settings > Integrations
- IOC count shown on dashboard case cards and case detail header
- Automatic STIX type detection from pasted values
- IOC Webhooks: 6 new webhook event types for IOC lifecycle events.
ioc_added,ioc_classification_changed,ioc_classified_malicious,ioc_classified_suspicious,ioc_classified_benign,ioc_correlation- Full IOC context in webhook payloads including STIX 2.1 SCO/SDO export objects for MISP integration
- Webhook Trigger Execution model for manual trigger button tracking with generic scope design (ioc, case, entity)
- Dynamic trigger event types configurable from enrichment settings
- IOC WebSocket Events: Real-time
ioc_added,ioc_removed,ioc_updatedevents on case channels. - IOC Timeline Events:
IOC_ADDEDandIOC_CLASSIFICATION_CHANGEDevent types with full metadata. - IOC Correlation Requests: Workflow for cross-case IOC sharing with pending/accepted/declined/expired states and context messages.
- Webhook Secrets in Custom Headers: Custom header values now support
{{secret.name}}template syntax for referencing webhook secrets, enabling secure header-based authentication (e.g., custom API keys). - Webhook Performance: Signal-level cache check avoids per-model-save database query when no webhooks are configured (60s TTL).
- Webhook Queryset Optimization: Webhook list endpoint now uses annotated delivery counts and prefetched recent deliveries, eliminating 3 separate queries per webhook.
- Incoming Webhook Lead Investigator: Incoming webhook payloads can now include
lead_investigator_idto override the default lead investigator when creating cases. - Timer Breach History: Timer resets now preserve a complete history of previous
breaches in an append-only
breach_historyJSON field. Each entry records the breach timestamp, duration, who reset it, and when. - Incoming Webhook Payload Reference: Settings UI now documents all accepted JSON fields with example curl command.
Changed
- Case Queryset Optimization: Case list endpoint now annotates
indicator_countandtotal_attachment_countto avoid N+1 queries. - Search Optimization: Global search uses lazy QuerySet for visible cases instead of materialized ID list for better database query plans.
- EncryptedJSONField Wildcard:
EncryptedJSONFieldnow supports'*'wildcard inencrypted_keysto encrypt all string values in a dict.
Security
- Adversarial Security Review: 14 findings addressed from a comprehensive
second-pass security audit.
- (VULN-001) Report ViewSet permission bypass:
InvestigationReportViewSetextendedviewsets.ViewSet(notModelViewSet), causing the Tier 1 capability check to be skipped entirely. Fixed by addingqueryset = InvestigationReport.objects.none()for model discovery. - (VULN-002) Archived case access via nested routes: Nested route
permission checks (e.g.,
/api/cases/<id>/timers/) did not verifyview_archived_casespermission for archived cases. Added explicit gate before standard access check. - (VULN-003) todo_checklist direct write:
todo_checklistwas writable via case PATCH, bypassingTodoServicevalidation and audit logging. Added toread_only_fields. - (VULN-004) Timer breach history loss on reset: Resetting a breached
timer cleared the
timer_breachedflag with no record of the breach. Timer reset now records breach events in an append-only history field before clearing. - (VULN-005) Timer state fields writable via API:
start_time,completed_time,is_completed,timer_breached, andalerts_sentwere writable via PATCH. Added toread_only_fields. - (VULN-007) Webhook SSRF via HTTP redirect: Webhook delivery followed
HTTP 307/308 redirects, allowing SSRF to bypass URL validation done at config time.
Added
allow_redirects=Falseto all webhook HTTP requests. - (VULN-009) Webhook content filter ReDoS: Admin-supplied regex for webhook content filtering had no timeout or length limit, allowing catastrophic backtracking to hang the Q-worker. Added serializer-level regex validation (500 char limit), thread-based 2-second timeout, and 10KB input cap.
- (VULN-010) Webhook custom headers stored unencrypted: Custom header
values (which may contain API keys) were stored in plaintext. Changed
EncryptedJSONFieldto use wildcard encryption for all values. - (VULN-011) Deprecated file_key persisted in database: The
file_keycolumn inChunkedUploadSessioncontained derived encryption key material. Removed column via data migration (null-out then drop) and replaced with on-demand HKDF derivation. - (VULN-012) Filename injection in Content-Disposition: Upload filenames
were not sanitized, allowing path traversal and HTTP header injection. Added
sanitize_filename()applied at upload init, photo upload, and download. - (VULN-013) Hash corruption on decryption failure:
_calculate_file_hash()silently swallowed decryption errors, producing a hash over incomplete data that was stored as correct. Removed the try/except so decryption failures propagate and mark the upload as failed. - (VULN-015) Statistics aggregate data leak:
StatisticsService.calculate()used unscopedCase.objects.filter(), exposing aggregate counts of all cases to any user withview_statisticspermission. Querysets are now scoped throughCase.objects.for_user(user). - (VULN-016) Azure AD multi-tenant token acceptance: Multi-tenant OIDC
configuration accepted tokens from any Azure AD tenant. Added tenant ID allowlist
validation on the token's
tidclaim. - (VULN-017) OIDC nonce bypass: Tokens missing the nonce claim were silently accepted when DFIRe sent one. Now rejected with a warning log.
- (VULN-001) Report ViewSet permission bypass:
- Cloud metadata SSRF protection: Added
169.254.0.0/16(link-local) to blocked webhook URL ranges, preventing SSRF to AWS/GCP/Azure instance metadata endpoints. - Incoming webhook rate limiting: Redis-based IP rate limiting (30/min, 5/sec burst) added to incoming webhook endpoint, checked before any database work.
- WebSocket session re-validation: WebSocket consumers now re-verify session validity (active account, non-expired session) on each periodic ping.
- WebSocket middleware ordering: Auth middleware now runs before rate limiting so the rate limiter can identify users by ID for per-user limits.
- WebSocket deactivated user blocking: Deactivated users are now rejected during WebSocket authentication.
- Jira comment sanitization: Jira comment author and body are sanitized via
sanitize_markdown()before storage. - Entity and timeline XSS prevention: Added
sanitize_markdown()validation toLegalEntitySerializer(description, contact_info, address) and timeline serializers (subject, details). - SSO config secret masking:
sso_configsecrets (client_secret,private_key,signing_key) are masked with***in API responses. - Startup key validation:
SECRET_KEYandCREDENTIAL_ENCRYPTION_KEYmust each be >= 32 characters and must differ. Validated at startup withValueError. - ngrok production guard:
ALLOW_NGROK=truenow requiresDEBUG=True; ignored in production with a warning log.
1.1.0 — February 18, 2026
Added
- Jira Cloud Integration: Full bidirectional integration with Jira Cloud for case
and action management.
- Export cases as Jira Epics with rich metadata (severity, case type, lead investigator, backlink to DFIRe)
- Export actions as configurable Jira issue types (Task, Story, Bug, etc.) linked to parent Epic
- Export evidence items as Jira Tasks
- Bulk export multiple actions in one operation
- Bidirectional status sync for both actions and Epics (case status)
- Bidirectional assignee sync with automatic user mapping
- Bidirectional phase label sync (incident phases as Jira labels)
- Automatic ticket discovery — new tickets created in Jira under a linked Epic are auto-imported as DFIRe actions
- Jira comments fetched and included in closing notes when actions are completed
- Conflict detection with DFIRe-wins resolution when both sides change between syncs
- Circuit breaker pattern prevents hammering Jira when unreachable
- Rate limiting with exponential backoff for Jira API calls
- Batch sync operations for efficient polling
- Jira Automation: Configurable automation options to reduce manual export work.
- Auto-create Jira Epic on case creation (triggered from both REST API and Slack)
- Auto-export action to Jira when started, with automatic In Progress transition push
- Orphan gathering: existing Jira tasks are automatically linked to Epic when it is created
- Jira Status Mapping: Three-tier priority system for DFIRe-to-Jira status
mapping.
- Explicit
to_jiraoverrides (highest priority) for admin control - Auto-derived reverse mapping from the Jira-to-DFIRe configuration
- Hardcoded defaults as fallback (including
ignored->Rejected) - Editable Jira-to-DFIRe dropdowns with read-only reverse preview in Settings UI
- Explicit
- Jira User Mapping: Automatic and manual mapping between DFIRe and Jira
accounts.
- Auto-map by email address with normalized full name fallback (handles diacritics, word order)
- Hourly polling for new user matches
- Manual mapping via admin UI with Jira user search
- Jira Settings UI: Full admin configuration panel in System Settings.
- Credentials, project key, issue type selection with Discover
- Sync interval, frontend URL for backlinks
- Automation toggles with dependency warnings
- Status mapping editor
- User mappings table with auto-map button
- Slack-Jira Integration: Jira awareness in Slack slash commands and modals.
/dfire jira show— display all Jira items linked to the case/dfire jira create case— create Jira Epic for the case/dfire jira create <n>— create Jira ticket for an action- Jira tags on action lines in
/dfire actions(clickable link to Jira issue) - Jira sync triggers on
/dfire take,/dfire done,/dfire skip,/dfire assign,/dfire unassign - Auto-create Epic when cases are created via Slack modal
- Conditional Jira section in
/dfire help(only shown when Jira is enabled)
- Jira Case Lifecycle Hooks: Jira Epic status mirrors case lifecycle changes.
- Case closed: closure comment added to Epic, Done transition pushed
- Case archived: all Jira links marked stale (sync stops), archive comment added
- Case reopened: stale links reactivated, In Progress transition pushed
- Feedback loop prevention via
source='jira_sync'parameter
- Jira REST API: 7 new endpoints under
/api/jira/for configuration, user mappings, and case operations. - Jira Periodic Tasks: Configurable polling interval (default 15 minutes) for status sync and ticket discovery, plus hourly user auto-mapping.
- Jira WebSocket Events: Real-time
jira_link_updatedevents broadcast to case viewers when Jira links are created, synced, or deleted — frontend auto-refreshes Jira badge state without polling. - Jira Link in Sidebar: Incident Info / Investigation Info sidebar now shows a clickable link to the linked Jira Epic (with external link icon) when Jira integration is enabled.
- Action Reassignment via UI: Clicking the assigned name on an in-progress action now opens the assignment modal for direct reassignment, removing the need to unassign and reassign via Slack commands or action reset.
- User Detail Drawer: Clicking a user row in User Accounts now opens a slide-out detail panel showing account details, active sessions (with browser and IP), recent authentication activity (login/logout/failed events with timestamps), Slack and Jira integration status, and avatar management.
- User Detail API: New
GET /api/users/{id}/detail/endpoint returns comprehensive user data including active sessions, recent auth events, and integration profiles in a single request. Queryset optimized withselect_relatedto avoid N+1 queries. - Admin Avatar Management: New
POST/DELETE /api/users/{id}/profile-picture/endpoint allows admins to upload or remove profile pictures for any user, with PIL image processing (validation, JPEG conversion, 256x256 resize). - Enhanced User List Table: User Accounts table now shows Last Login (relative
time), Integrations (Jira/Slack badges), and clickable rows. User list API extended with
date_joined,last_login, andjira_linkedfields. - Settings Sidebar Reorganization: System Settings sidebar tabs reorganized into three categories (System, Integrations, Case Properties) with section headers and dividers. Tabs renamed for clarity: Tenant→Global Settings, Collaboration→Slack Integration, Jira→Jira Integration, Log Sender→Log Integration, Retention→Retention Policy, Workflow→Evidence Workflow, Lifecycle→Incident Lifecycle, Report Sections→Reporting, Flags→Triage Flags.
- Audit Log Sender: Forward audit logs to external log aggregation services (ELK,
OpenSearch, Splunk, etc.).
- Multi-format payload support: JSON Batch, NDJSON, and Elasticsearch Bulk API
- HTTP Basic Authentication for endpoint credentials
- Custom HTTP headers for Bearer tokens and other authentication schemes
- Test Connection button with live response preview (status code, headers, body)
- Clear Settings to reset all sender configuration
- Circuit breaker with manual reset for fault tolerance
- Delivery history tracking with batch metadata
- Privacy notice warning about audit log data sensitivity
- Configurable batch size and timeout
- System Heartbeat: Periodic health check entries written to the audit log and
forwarded to external log destinations.
- Dead man's switch pattern — distinguishes "system idle" from "system down"
- Business metrics: cases by status, evidence items, total and active users (24h)
- License metrics: status, days remaining, trial/grace period state (enables license expiry alerting)
- Database metrics: PostgreSQL size, query latency, audit log count, pending log count
- Storage metrics: file count, total size, quota usage percentage
- Health checks: Redis connectivity and latency, Django-Q2 task queue status (pending, success, failed)
- System info: application version, process uptime
- Configurable interval (5, 15, 30, or 60 minutes, default 15)
- Enable/disable toggle in Log Integration settings
- Resilient collection — individual metric failures don't block other sections
- Testing: 192 Jira tests across 36 test classes, 20 Slack-Jira integration tests, 17 security regression tests, 55 audit log sender tests, and 31 heartbeat tests (1002 total backend tests).
- Documentation: Comprehensive
docs/JIRA_INTEGRATION.mdtechnical reference covering all Jira features.
Fixed
- Modal overlay alignment: Fixed all modal and drawer backdrop overlays starting
at the wrong vertical position. The global CSS rule used
top: 2rem(32px) but the header ish-16(64px). Also fixed overlays inheritingmargin-topfrom parentspace-y-*containers, which added an additional 24px offset. Allbg-black/*opacity variants are now covered by the selector.
Security
- WebSocket information disclosure (SEC-006): Dashboard WebSocket broadcasts no
longer contain full serialized case data.
notify_case_updatedandnotify_case_creatednow send only the case ID to the dashboard channel — the frontend refetches via the permission-filtered REST API. Previously, all authenticated users on the dashboard could see titles, descriptions, and team details of cases they did not have access to. - CORS wildcard with credentials (SEC-007): Removed
CORS_ALLOW_ALL_ORIGINS = Truefallback that was active whenDEBUG=Trueand noCORS_ALLOWED_ORIGINSwas set. Even in development, CORS now requires an explicit origin allowlist. The previous configuration combined withCORS_ALLOW_CREDENTIALS = Trueallowed any origin to send credentialed requests. - Case status transition bypass (SEC-008): Added server-side validation for case
status transitions in
CaseSerializer. Cases must follow the OPEN → CLOSED → ARCHIVED lifecycle — direct OPEN → ARCHIVED transitions are now rejected with a descriptive error. Previously, any valid status string was accepted regardless of the current state. - Encryption strict mode audit warning (SEC-009):
ENCRYPTION_STRICT_MODE=Falsenow emits a startup warning to thedfire.securitylogger. This makes the non-strict configuration visible in production logs and prevents accidental deployment with silenced decryption failures. - Signal handler race condition (SEC-010): Replaced module-level
_case_previous_statedictionary with instance-level_previous_statusattribute for case pre-save state tracking. The shared dictionary was not thread-safe and could mix up concurrent case updates under load. - API token masking (SEC-011): Jira API token in the config GET response no
longer leaks the first 8 characters. Now shows
****...{last 4}instead of{first 8}...{last 4}. - Photo upload write protection:
photo_uploadendpoint now usescase.is_write_protectedinstead of hardcoded status string comparison, ensuring consistency with the centralized write protection logic.
Changed
- Action labels: "Assign" and "Jira" action links renamed to "Assign to team member" and "Create Jira item" for clarity.
- Jira badge sizing: Jira issue badge in the case header now matches the height and padding of the status and severity badges.
- Dashboard WebSocket handler:
handleCaseUpdatednow handles both full case data (from case-specific channel) and minimalcase_idpayloads (from dashboard channel), refetching via REST API for the latter.
Fixed
- Jira issue type not respected in link metadata:
export_todo_as_task(),export_item_as_task(), andexport_case_as_epic()hardcodedjira_issue_type='Task'/'Epic'in theJiraIssueLinkrecord regardless of the configured issue type. Now reads the actual type name fromdiscovered_issue_typesvia newresolve_action_issue_type_name()andresolve_case_issue_type_name()helpers infield_mapping.py. Discovery filter insync.pyalso refactored to use the shared helper. - Slack action unassignment Jira sync:
/dfire action unassignnow calls_sync_todo_to_jira()after resetting the action status, correctly transitioning the linked Jira ticket from "In Progress" back to "To Do". Previously, unassigning an action via Slack reset the DFIRe status to pending but left the Jira ticket stuck in "In Progress".
1.0.8 — February 15, 2026
Added
- Slack: New
/dfire action add [description]command to create workflow actions from Slack with modal form for description and phase selection. - Slack: Workflow action support in
/dfire action take <n>— workflow actions now open a multi-step decision tree modal instead of simple assignment. - Slack: Actions with workflow definitions are now tagged with
[workflow]in action listings (/dfire actions). - Slack: Auto-invite for cases created via
/dfire create— creator and users with global permissions (edit_all_cases,view_all_cases) are now automatically invited to the case channel and added to the case team with appropriate roles. - Slack: Bidirectional archive sync — archiving a case in DFIRe now archives the linked Slack channel, and archiving a Slack channel archives the linked case. Unarchiving (changing status from ARCHIVED to OPEN or CLOSED) unarchives the Slack channel.
- Slack: Bidirectional team membership sync — joining a case Slack channel
adds you to the case team (as investigator if you have
change_casepermission, otherwise as viewer), and leaving the channel removes you from the team. Adding/removing team members in DFIRe invites/kicks them from the Slack channel. - Slack: Lead investigator protection — lead investigators cannot leave the
case channel. If they try to leave, they are automatically re-invited with an explanation
message. To leave, they must first assign a new lead using
/dfire case. - Slack: Note modal now includes "Save to" dropdown allowing notes to be saved to specific evidence items instead of just the case. Dropdown only appears when evidence items exist.
- Slack: New
/dfire archivecommand to archive cases directly from Slack with confirmation modal. Archives both the case and the linked Slack channel. - Slack: Case creation modal (
/dfire create) now includes Severity dropdown (defaults to Medium) and optional External Reference field for ticket IDs. - Slack: Channel intro message and
/dfire statusnow display Severity (with color-coded emoji) and External Reference when set. - Slack: New
/dfire casecommand to edit case information including title, description, severity, external reference, lead investigator, and dynamic case type attributes. - Slack: New
/dfire evidence update <n>command to edit evidence items via modal form — supports name, location, investigation stage, tags, and dynamic item type attributes. - Slack: Evidence listings (
/dfire evidence) now show sequential numbers for easier reference with update command. - Slack: New
/dfire action assign <n> @usersyntax to assign actions directly to tagged Slack users without opening a modal. Also supports/dfire action assign <n> meto assign to yourself. - Testing: Added 20 new unit tests for Slack features: member left channel handling, lead investigator protection, action assign command with @mentions, signal handlers for team sync, and connector remove_user method.
Changed
- Settings: Default command channel name changed from
dfire-commandstodfire. - Slack:
/dfire helpnow shows mode-appropriate commands — investigation channels show a limited subset (evidence, notes, case management) while incident channels show the full command list. - Slack: Incident-only commands (actions, phases, timers, events) are now blocked
in investigation mode with a message suggesting
/dfire escalate. - Slack:
/dfire action take <n>now allows reassigning actions that are already in progress — no need to unassign first. Shows "reassigned from X" in the response. - Slack: Workflow actions can no longer be assigned via
/dfire action assign— they must be taken via/dfire action taketo trigger the workflow modal. - Slack: Help text now shows
/dfire status [update]to clarify the optional update parameter for CAN reports. - Slack: Case update notifications now show detailed field changes (e.g., "Severity: High", "Lead Investigator: John Smith") instead of just "Case updated".
- Slack: When lead investigator is changed, the previous lead is automatically added to investigators to preserve their edit access.
- Slack: Viewers cannot be assigned actions — attempting to assign to a viewer now shows a clear error message instead of silently failing.
Fixed
- Settings: "Clear Settings" button in Collaboration Settings now actually saves the cleared configuration to the backend, properly disabling the Slack integration and disconnecting Socket Mode.
- Slack: Prevented direct completion of workflow actions via
/dfire action done <n>— users must use/dfire action take <n>to navigate the workflow decision tree. - Slack: Fixed workflow definitions not being copied when creating cases via
/dfire createor escalating investigations — workflows were incorrectly shown as regular actions. - Slack: Fixed
AttributeError: module 'django.utils.timezone' has no attribute 'utc'when starting compliance timers via Slack modal. - Slack: Fixed multi-stage workflow modals failing silently due to metadata exceeding Slack's 3000 character limit — workflow definition is now retrieved from the case instead of stored in modal metadata.
- Slack: Fixed deep workflow decision trees (3+ levels) failing due to Slack's
3-view modal stack limit — workflow modals now use
updateinstead ofpushto stay within limits. - Slack: Fixed malformed Slack user mentions (e.g.,
<@>) causing errors in action assignment — now shows helpful error message. - Slack: Fixed
_find_team_membernot finding viewers for action assignment — now correctly validates that only investigators can be assigned actions.
1.0.7 — February 12, 2026
Added
- Slack: Enhanced "Case Closed" notifications now include detailed status reports, incident statistics, and the final CAN report.
- Slack: Automatic channel invitation for active users with global access
(
edit_all_casesorview_all_cases) when a new case is created. - UX: Added "Access Denied" page with automatic redirect to dashboard for 403/404 errors in Case view to prevent infinite error loops.
- UX: Added warning and automatic redirect in "Edit Case" modal when archiving a
case without
view_archived_casespermission.
Changed
- Slack: Made "Case Type" mandatory in
/dfire createmodal. - Slack: Made "Storage Location" mandatory in
/dfire evidence addmodal. - Performance: Implemented TTL caching (5 minutes) for collaboration connectors to reduce database/initialization overhead.
- Backend: Added startup identity check for Slack bot to verify authentication status early.
- Settings: Removed "Auto-create channels" toggle from Collaboration Settings UI (redundant with per-case checkbox).
Fixed
- Slack: Fixed race condition where "Case Closed" notifications were skipped because the collaboration channel was deactivated before the message could be sent.
- Slack: Fixed issue where channel creation failed for Slack-initiated cases due to stale connector tokens.
- Slack: Fixed auto-invite for global users by reordering query filters (moved
is_active=Truebefore permission checks to prevent Django ORM SQL generation issues).
Removed
- Settings: Removed redundant "Auto-create channels" global setting from backend
and frontend. Channel creation is now controlled by the "Create Slack channel" checkbox when
creating cases via web UI, and is always enabled for Slack-initiated cases
(
/dfire create).
1.0.6 — February 10, 2026
Added
- Slack Socket Mode: Complete migration from HTTP webhooks to Socket Mode for Slack integration
- Slack message edit/delete sync: Edits and deletions in Slack are now reflected
in DFIRe
- Edited messages show "(edited)" label in the workspace tab
- Deleted messages show "[This message was deleted]" placeholder
- Real-time WebSocket notifications for both edit and delete events
- Slack user info caching: User lookups cached in Redis for 5 minutes, reducing redundant Slack API calls
- Auto-add investigators toggle: New setting to control whether users are automatically added as investigators when they join a case Slack channel (defaults to enabled for backward compatibility)
- Multi-file message support: Messages with multiple files now show "+N more
files" indicator instead of silently dropping extra files;
file_countfield tracks total files per message - Compose experience improvements:
- Insert Link modal replaces browser
prompt()dialogs with a proper modal (URL + optional display text) - Emoji picker with search/filter using the existing Slack emoji map
- @mention autocomplete dropdown for team members with linked Slack accounts (filters by
name/username, inserts
<@SLACK_USER_ID>format)
- Insert Link modal replaces browser
- Collaboration test coverage: 24 tests covering notifier logic, message edit/delete handlers, API permissions, user caching, and auto-add investigator config
- Block Kit formatting for all
/dfirecommands: All slash command responses now use Slack Block Kit with headers, sections, field layouts, dividers, and context blocks — with plain-text fallback for accessibility/dfire statusshows case details, team, progress, CAN report, and compliance timers in structured fields/dfire show actionsrenders per-phase action lists with progress percentages and status emojis/dfire evidenceshows full evidence detail: type, short UUID, status, location, owner, primary user, flags, and key attributes/dfire recentshows full event content (description, subject, details) with timestamps, actors, and phase context- All action commands (
take,done,skip,assign,unassign) show progress counters
- External select options handler: Added
@app.optionshandler for Slack Bolt to serve dynamic dropdown options in modals (evidence types, legal entities, case types, projects) with search filtering - Compose write-through: Messages sent from the DFIRe Compose box now immediately
create a
CollaborationMessagerecord and broadcast via WebSocket, fixing the bug where compose messages appeared in Slack but not in the DFIRe UI - Compliance timer timeline events: Timer lifecycle now creates timeline events:
TIMER_STARTEDwhen a timer is started (via web UI, Slack command, or Slack modal)TIMER_COMPLETEDwhen a timer is completed (shows breach status)TIMER_WARNINGat 50%, 25%, and 10% threshold crossings (created by scheduler)TIMER_BREACHEDwhen compliance deadline is exceeded- All timer events are broadcast to linked Slack channels with Block Kit formatting
- Block Kit formatting for all timeline notifications: All event notifications
posted to Slack channels now use Block Kit with headers, section fields, context blocks, and
links — replacing the previous plain-text format
- Covers: case lifecycle, phase changes, lead investigator changes, evidence, actions/workflows, notes, attachments, and all timer events
- Lead investigator changes (
LEAD_INVESTIGATOR_CHANGED) now broadcast to Slack (previously silent) - Timer breaches (
TIMER_BREACHED) are always broadcast (critical event)
- Slack timer modal date/time picker: Timer start modal now includes optional date and time pickers for backdating timer start (matching web UI capabilities)
- Slack message attribution: Messages sent from DFIRe Compose box include an italic attribution suffix in Slack (— Name via DFIRe) for auditability
Refactored
- WorkspaceTab component split: Decomposed 1,080-line monolithic component into 7
focused files:
MessageBubble.tsx— Memo'd message rendering with recursive thread supportChannelHeader.tsx— Channel header bar with sync controlsWorkspaceToolbar.tsx— Compose/search toggle panelWorkspaceEmptyStates.tsx— No-connector and no-channel empty statestypes.ts— Shared TypeScript interfacesworkspaceUtils.ts— Pure utility functionsWorkspaceTab.tsxreduced to ~400 lines (state + data fetching + composition)
Fixed
- Slack connection status: Status indicator now works correctly across Docker containers using Redis heartbeat (was stuck on "disconnected" because in-memory state couldn't cross container boundaries)
- Status view bug:
CollaborationStatusViewwas passing the full status dict instead of theconnectedboolean to the serializer - Compose messages not appearing in UI: Messages sent from the Compose box posted
to Slack as the bot but were then filtered out by the
bot_messagesubtype skip — fixed with write-through record creation on send - Bot message display: Bot-originated messages now display as bot messages with bot name and icon, not as user messages
- Bot message grouping: Consecutive bot messages are now grouped correctly in the message list
- Thread reply refresh: Thread replies sent from the Compose box now trigger an incremental fetch so they appear immediately
- Command visibility:
/dfirecommand responses now correctly use ephemeral (private) or in-channel posting depending on command type - Socket Mode view handler: Fixed regex pattern matching for Slack view submission/closed handlers
- Evidence add notification format: Changed from
"{type} added: {name} by {user}"to"Evidence added: {type} — {name}"with actor on a new line for clarity - CAN report layout in
/dfire status: Changed Conditions/Actions/Needs from two-column field layout to full-width single-column sections for better readability of long text - Add Evidence modal: Fixed
block_suggestionunhandled request error when opening evidence type dropdown — added missing@app.optionshandler forexternal_selectelements - Encryption test: Retargeted signing secret encryption test to app token field (signing secret removed in Socket Mode migration)
Changed
- Slack integration now requires App-Level Token (
xapp-...) instead of Signing Secret- Generate in Slack app settings: Basic Information → App-Level Tokens →
Generate (with
connections:writescope)
- Generate in Slack app settings: Basic Information → App-Level Tokens →
Generate (with
- Updated Slack app manifest template for Socket Mode (removed webhook URLs, enabled
socket_mode_enabled) - Frontend Collaboration Settings updated with Socket Mode setup instructions
- Bot user now shows as "always online" in Slack
BlockBuilderextended withadd_section_fields()for side-by-side key-value field layouts in Block Kit messages- Evidence add timeline notification format improved: now shows
"Evidence added: {type} — {name}"instead of"{type} added: {name}"
Removed
- HTTP webhook endpoints deprecated (return helpful error messages for misconfiguration diagnosis)
- Signing secret no longer required (Socket Mode connections are pre-authenticated)
- Webhook URL configuration removed from setup instructions
Migration Notes
- Existing Slack apps must be reconfigured:
- Enable Socket Mode in Slack app settings (Settings → Socket Mode → Enable)
- Generate an App-Level Token (Basic Information → App-Level Tokens →
Generate with
connections:write) - Update DFIRe Collaboration Settings with the new App-Level Token
- Ensure the
slack-socketservice is running in your Docker deployment
- Existing bot tokens (
xoxb-...) remain valid and do not need to be regenerated
1.0.5 — February 5, 2026
Added
- Comprehensive case type taxonomy overhaul with 15 incident response case types:
- Consolidated from 16 to 15 types (merged General Forensic Investigation + General Incident Response)
- Renamed case types for clarity (e.g., "DDoS Attack" → "Distributed Denial of Service Attack")
- Added consistent schema fields across all types:
sharing_permissions(renamed fromtlp),affected_department,nis2_essential_service_impact - Added 4-8 case-specific schema fields per type
- Expanded todo templates to 20-40 actions following NIST SP 800-61 phases
- Fixed workflow anti-patterns (max 3-4 options, investigation actions before decision workflows)
- Added EU regulatory workflows (GDPR 72h notification, NIS2 24h early warning)
- Consumer-focused perspective (responding to vulnerabilities in software we use)
- Visual workflow editor for case type todo templates in System Settings:
- Recursive editor supporting nested follow-up questions at any depth
- Three outcome types: spawn new action, mark as completed, or follow-up question
- Expandable workflow preview in todo template list showing full decision tree hierarchy
- Graphical confirmation modal for destructive actions (removing workflows)
- Timeline 3-tier visual hierarchy system for clearer event presentation:
- Tier 1 (Milestone): Phase changes, case lifecycle events — highest prominence with colored borders and large timeline dots
- Tier 2 (Activity): Manual entries, action start/complete — medium prominence with subtle borders and smaller dots
- Tier 3 (System): Evidence, attachments, notes — lowest prominence, inline display without timeline dots
- Expandable/collapsible content for notes and workflow decisions:
- Notes >200 characters show collapsed with "Show more" button
- Workflow completion events show decision tree with expand/collapse for long content
- Clickable resources in timeline events:
- Evidence items link directly to item detail pages
- Case attachments link to attachments tab via hash navigation
- Item attachments link to parent item page
- Workflow decision tree formatting using nested markdown lists for clear hierarchy
Changed
- Widened Edit Case Type modal (max-w-5xl) for better workflow editing experience
- Workflow editor uses multi-line textareas for answer options, spawn actions, and follow-up questions
- New workflow actions no longer auto-open the editor, allowing users to set the question first
- Timeline hover actions now more visible with colored buttons (blue "View", slate "Edit") instead of subtle icons
- Workflow completion events now show formatted decision path with arrows and nested indentation
- Attachment events no longer show redundant filename in both title and description
Fixed
- Compliance timer linebreaks now render correctly in manual timeline events (added
whitespace-pre-wrap) - Workflow decision tree no longer duplicates conclusion in multi-level workflows
- Printable report timeline now renders workflow decision trees with proper markdown formatting
- Printable report timeline now preserves linebreaks in event descriptions
(
whitespace-pre-wrap) - Added visual emphasis styling to CASE_CREATED and MANUAL events in printable report timeline
1.0.4 — February 1, 2026
Security
- Fixed information disclosure via browsable API form dropdowns — case titles were visible to unauthorized users in HTML form select elements when using the DRF browsable API
- Added RBAC enforcement to audit log endpoints (
AuditLogViewSetnow requiresdfireRolePermission) - Added database constraint (
attachment_must_have_parent) preventing orphan attachments — attachments must have a case OR item association for RBAC checks to function correctly
Added
- New
core/common/fields.pymodule with reusable RBAC-aware serializer fields:UserFilteredCasePKField— filters case dropdowns by user permissionsUserFilteredItemPKField— filters item dropdowns by user's case permissions
Changed
- Refactored serializers to use custom RBAC-aware
PrimaryKeyRelatedFieldsubclasses instead of__init__queryset filtering (which doesn't work for DRF form rendering):ItemSerializer.casenow usesUserFilteredCasePKFieldItemNoteSerializer.itemnow usesUserFilteredItemPKFieldCaseNoteSerializer.casenow usesUserFilteredCasePKFieldCaseTimerSerializer.casenow usesUserFilteredCasePKField
Fixed
- Improved disabled user account handling in team management:
- Disabled accounts hidden from team assignment dropdowns (prevents new assignments)
- Admins still see all users (including disabled) in User Accounts management
- Disabled users already assigned to cases are shown in team modal with visual indicator
- Existing disabled team members can be removed but cannot be assigned new roles
- Lead investigators remain assigned even when disabled (prevents case exposure)
- Backend validation prevents NEW assignments of disabled users while allowing existing members
1.0.3 — January 31, 2026
Added
- Case retention policy: configurable auto-archive and auto-delete for closed/archived cases
- New "Retention" tab in System Settings (superuser only) for policy configuration
- Daily scheduled task to process retention policy at midnight
archived_attimestamp on Case model to track when cases are archivedAUTO_ARCHIVEandAUTO_DELETEaudit log action types for retention actions- Retention settings included in settings export/import and defaults.json
- Dashboard statistics summary bar showing open/closed/archived counts, case mode split, severity breakdown (donut chart), and MTTR
- Dashboard API endpoint (
/api/cases/dashboard-stats/) for aggregated case statistics - Retention countdown display on case cards showing days until auto-archive or auto-delete
- Team members count (+N) shown on case cards with tooltip listing all team members
- Severity filter in dashboard filter bar for filtering cases by severity/priority level
Changed
- Refactored case deletion logic into
CaseService.delete_case()for code reuse - Completely redesigned case cards with improved visual hierarchy:
- Clear top bar with severity indicator (color + text label for accessibility), case number, and status
- Horizontal progress bar replacing circular progress indicator
- Organized metrics row with lead investigator, progress, items, attachments, and timers
- Footer with phase info (incidents) and retention countdown
- Left border color-coded by severity for quick visual scanning
- Dashboard filter bar now more compact with flexible layout to accommodate severity filter
Fixed
- Report images now render at correct size (small/medium/large) in printable reports instead of all appearing the same size
- Fixed
case.uuidreference error in retention policy (Case model usesid, notuuid) - Fixed tenant info API endpoint URL in dashboard hook (was
tenant/info/, nowtenant-info/) - Fixed dashboard pagination calculating wrong page count (was using 10 items per page instead of 20)
Tests
- Added 24 unit tests for case retention policy covering:
CaseService.delete_case()cascade deletion of cases, items, and attachmentsarchived_attimestamp handling inCaseService.change_status()process_retention_policy()scheduled task for auto-archive and auto-delete
1.0.2 — January 29, 2026
Added
- CSV export endpoints for case data: timeline, evidence items, notes, and actions
- CSV export buttons in UI (Timeline, Evidence, Notes, Actions tabs) with download icon
started_attimestamp for action items (to-do checklist) — records when work began- Offline license time stacking: remaining days from current license are added when renewing early
- Audit logging for license state changes (activation, offline enable/disable)
- Audit logging for failed login attempts (invalid credentials, SSO-only accounts)
- Audit logging for OIDC/SSO logins
- Audit logging for SSO configuration changes (with sensitive field masking)
- Audit logging for case team changes (investigators/viewers added/removed)
- Audit logging for storage configuration changes (S3, SMB settings)
- Audit logging for settings import/export operations
- Audit logging for profile picture changes (upload, refresh from OIDC, delete)
- Database trigger to protect
registration_datefrom modification (prevents trial manipulation) - CI: TypeScript build check for frontend (catches errors before Docker build)
- CAN report duplicate save prevention — warns user and disables save when content matches previous version
Changed
- Notes CSV export now includes detailed evidence item info: type, name, and UUID prefix
- Unified button sizes across Timeline, Evidence, Notes, Actions, and Compliance tabs
- CAN report editor now prepopulates with both ongoing AND completed actions from checklist
Fixed
- Grace period calculation now uses accurate time comparison instead of truncated days
- Grace period banner message now distinguishes between offline license expiration and online license server issues
- CAN report actions now prepopulate correctly on first report creation (restored useEffect-based prop handling)
- Case notes "Send" button renamed to "Add Note" for consistency with evidence item notes
1.0.1 — January 28, 2026
Added
- Update notification system: displays available updates in License & Updates settings page
- Red dot indicator on License & Updates tab when updates are available
- Link to update documentation in update notification
Changed
- Consolidated VERSION file to
dfire_api/VERSION(removed separate mount point) - Renamed "License" settings tab to "License & Updates"
Fixed
- Fixed TypeScript build error in ItemsOverTimeChart formatter type
- Removed unused
formatBreachTimefunction from ComplianceTab - Skip license server pings when offline license mode is enabled
1.0.0 — January 27, 2026
Added
- Custom start time option for compliance timers — allows backdating timer start
- "Evidence over time" chart in Analytics view
- Maximum file size display in Attachments tabs (Case and Evidence views)
Changed
- Renamed "Workspace" tab to "Collaboration" for clarity
- Changed "Evidence Items" to "Evidence" in Analytics
- Changed "Photos" to "Images" throughout the UI for accuracy
- Increased maximum upload size from 100MB to 4GB in nginx configuration
- Improved dark mode styling in Analytics date range selector (colors and fonts)
- Date fields in case creation now use proper date picker
Fixed
- Removed duplicate case type display from report title page
- Empty team members now shows "No team members assigned" message
- "Add to timeline" checkbox in Notes tab now only appears for Incident mode cases
- Required field validation now enforced for case type schema fields (except booleans)
- Write protection now properly enforced on attachments for closed cases
Removed
- Deleted unused CaseSidebar.tsx component (dead code cleanup)