Changelog

All notable changes to DFIRe, organized by version. The project follows Semantic Versioning.

1.2.8 — 2026-03-27

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_TRANSFER timeline 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.html documentation 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-1 styling 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.html with 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_slug field 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_COMPLETED timeline 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_order to phase_id when 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_steps MCP tool for toggling runbook step completion. The get_reference_data tool now supports the runbooks data type. Workflow resolution via manage_workflow handles 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_indicators tool 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-audit job 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_updated webhook event fires when a CAN (Conditions, Actions, Needs) report is created. Provides can.* template variables (conditions, actions, needs, version, created_by, created_at) for flexible payload formatting.
  • Webhook: User Notification Trigger: New user_notification webhook event fires when an actionable in-app notification is created (case assignments, IOC correlations, timer warnings, etc.). Toast messages (UI feedback) are excluded. Provides message.* 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. Includes id, username, email, first_name, last_name, phone_number, timezone, slack_user_id, and slack_username.
  • Webhook: Form Data Support: Webhooks can now send payloads as application/x-www-form-urlencoded instead 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 via POST /api/cases/import/ (create new case) or PUT /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 MarkdownDisplay component used for case notes and CAN reports.
  • API Documentation Summaries: All REST API endpoints now include human-readable summary annotations 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_id field 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 Deprecation response 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 required value and stix_type fields 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 required timer_definition_id and optional start_time fields 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 CaseSerializer schema.
  • 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 (CaseExportApiKey model, 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 item parameter when both case and item were provided. The upload now correctly links the attachment to the specified evidence item. Additionally, the item field on attachments is now writable via PATCH, 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) and workflow_state fields. 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 EncryptedJSONField reads (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 the user_notification webhook because Django's post_save signal 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_id but the code was reading id, 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 via Case.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_VIOLATION audit 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_schema annotations 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 /dfire slash 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. Uses IndicatorService.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 ToastProvider that 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 enabled field 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_base URLs 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_changed flag 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 link href values to http, https, and mailto protocols, blocking javascript: URIs. This hardens all Markdown output paths including LLM-generated report content.
  • AI Instruction Length Limit: Free-text additional_instructions on 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_published state
  • OIDC Issuer Validation: Added iss claim verification in OIDC token validation using PyJWT's issuer parameter 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 sent websocket.close before 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_presence and editing_lock handlers now re-check case permissions before processing
  • Nginx Host Header: Replaced hardcoded proxy_set_header Host localhost with proxy_set_header Host $host across 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.TIMEOUT when 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() after cycle_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_ORIGINS log a warning and reject cross-origin requests instead of falling back to localhost. CSRF_TRUSTED_ORIGINS auto-derives from CORS_ALLOWED_ORIGINS when 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 FROM directives in both backend and frontend Dockerfiles
  • Docker File Permissions: Added chmod 750 on /app/media and /app/staticfiles in the backend production image
  • Log Sanitization: Added SanitizeFilter to 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 localStorage to sessionStorage to 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: GroupViewSet and PermissionViewSet now use dfireRolePermission instead of DjangoModelPermissions, with a lockout prevention guard that blocks removing change_group from the last group that has it

Fixed

  • CI Key Length: CI environment SECRET_KEY and CREDENTIAL_ENCRYPTION_KEY values lengthened to meet the new 32-character minimum, and ALLOWED_HOSTS, CORS_ALLOWED_ORIGINS, CSRF_TRUSTED_ORIGINS added to CI test environment
  • Non-HTTP Service Startup: qcluster and slack-socket services no longer crash on startup when CORS_ALLOWED_ORIGINS and CSRF_TRUSTED_ORIGINS are 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_updated events on case channels.
  • IOC Timeline Events: IOC_ADDED and IOC_CLASSIFICATION_CHANGED event 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_id to 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_history JSON 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_count and total_attachment_count to 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: EncryptedJSONField now supports '*' wildcard in encrypted_keys to 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: InvestigationReportViewSet extended viewsets.ViewSet (not ModelViewSet), causing the Tier 1 capability check to be skipped entirely. Fixed by adding queryset = 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 verify view_archived_cases permission for archived cases. Added explicit gate before standard access check.
    • (VULN-003) todo_checklist direct write: todo_checklist was writable via case PATCH, bypassing TodoService validation and audit logging. Added to read_only_fields.
    • (VULN-004) Timer breach history loss on reset: Resetting a breached timer cleared the timer_breached flag 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, and alerts_sent were writable via PATCH. Added to read_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=False to 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 EncryptedJSONField to use wildcard encryption for all values.
    • (VULN-011) Deprecated file_key persisted in database: The file_key column in ChunkedUploadSession contained 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 unscoped Case.objects.filter(), exposing aggregate counts of all cases to any user with view_statistics permission. Querysets are now scoped through Case.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 tid claim.
    • (VULN-017) OIDC nonce bypass: Tokens missing the nonce claim were silently accepted when DFIRe sent one. Now rejected with a warning log.
  • 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 to LegalEntitySerializer (description, contact_info, address) and timeline serializers (subject, details).
  • SSO config secret masking: sso_config secrets (client_secret, private_key, signing_key) are masked with *** in API responses.
  • Startup key validation: SECRET_KEY and CREDENTIAL_ENCRYPTION_KEY must each be >= 32 characters and must differ. Validated at startup with ValueError.
  • ngrok production guard: ALLOW_NGROK=true now requires DEBUG=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_jira overrides (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
  • 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_updated events 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 with select_related to 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, and jira_linked fields.
  • 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.md technical 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 is h-16 (64px). Also fixed overlays inheriting margin-top from parent space-y-* containers, which added an additional 24px offset. All bg-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_updated and notify_case_created now 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 = True fallback that was active when DEBUG=True and no CORS_ALLOWED_ORIGINS was set. Even in development, CORS now requires an explicit origin allowlist. The previous configuration combined with CORS_ALLOW_CREDENTIALS = True allowed 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=False now emits a startup warning to the dfire.security logger. 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_state dictionary with instance-level _previous_status attribute 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_upload endpoint now uses case.is_write_protected instead 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: handleCaseUpdated now handles both full case data (from case-specific channel) and minimal case_id payloads (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(), and export_case_as_epic() hardcoded jira_issue_type='Task'/'Epic' in the JiraIssueLink record regardless of the configured issue type. Now reads the actual type name from discovered_issue_types via new resolve_action_issue_type_name() and resolve_case_issue_type_name() helpers in field_mapping.py. Discovery filter in sync.py also refactored to use the shared helper.
  • Slack action unassignment Jira sync: /dfire action unassign now 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_case permission, 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 archive command 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 status now display Severity (with color-coded emoji) and External Reference when set.
  • Slack: New /dfire case command 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> @user syntax to assign actions directly to tagged Slack users without opening a modal. Also supports /dfire action assign <n> me to 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-commands to dfire.
  • Slack: /dfire help now 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 take to 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 create or 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 update instead of push to 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_member not 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_cases or view_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_cases permission.

Changed

  • Slack: Made "Case Type" mandatory in /dfire create modal.
  • Slack: Made "Storage Location" mandatory in /dfire evidence add modal.
  • 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=True before 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_count field 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)
  • 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 /dfire commands: 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 status shows case details, team, progress, CAN report, and compliance timers in structured fields
    • /dfire show actions renders per-phase action lists with progress percentages and status emojis
    • /dfire evidence shows full evidence detail: type, short UUID, status, location, owner, primary user, flags, and key attributes
    • /dfire recent shows 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.options handler 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 CollaborationMessage record 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_STARTED when a timer is started (via web UI, Slack command, or Slack modal)
    • TIMER_COMPLETED when a timer is completed (shows breach status)
    • TIMER_WARNING at 50%, 25%, and 10% threshold crossings (created by scheduler)
    • TIMER_BREACHED when 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 support
    • ChannelHeader.tsx — Channel header bar with sync controls
    • WorkspaceToolbar.tsx — Compose/search toggle panel
    • WorkspaceEmptyStates.tsx — No-connector and no-channel empty states
    • types.ts — Shared TypeScript interfaces
    • workspaceUtils.ts — Pure utility functions
    • WorkspaceTab.tsx reduced 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: CollaborationStatusView was passing the full status dict instead of the connected boolean 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_message subtype 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: /dfire command 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_suggestion unhandled request error when opening evidence type dropdown — added missing @app.options handler for external_select elements
  • 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:write scope)
  • 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
  • BlockBuilder extended with add_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:
    1. Enable Socket Mode in Slack app settings (Settings → Socket Mode → Enable)
    2. Generate an App-Level Token (Basic Information → App-Level Tokens → Generate with connections:write)
    3. Update DFIRe Collaboration Settings with the new App-Level Token
    4. Ensure the slack-socket service 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 from tlp), 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 (AuditLogViewSet now requires dfireRolePermission)
  • 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.py module with reusable RBAC-aware serializer fields:
    • UserFilteredCasePKField — filters case dropdowns by user permissions
    • UserFilteredItemPKField — filters item dropdowns by user's case permissions

Changed

  • Refactored serializers to use custom RBAC-aware PrimaryKeyRelatedField subclasses instead of __init__ queryset filtering (which doesn't work for DRF form rendering):
    • ItemSerializer.case now uses UserFilteredCasePKField
    • ItemNoteSerializer.item now uses UserFilteredItemPKField
    • CaseNoteSerializer.case now uses UserFilteredCasePKField
    • CaseTimerSerializer.case now uses UserFilteredCasePKField

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_at timestamp on Case model to track when cases are archived
  • AUTO_ARCHIVE and AUTO_DELETE audit 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.uuid reference error in retention policy (Case model uses id, not uuid)
  • Fixed tenant info API endpoint URL in dashboard hook (was tenant/info/, now tenant-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 attachments
    • archived_at timestamp handling in CaseService.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_at timestamp 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_date from 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 formatBreachTime function 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)