Skip to content

review: fix defects from a full code review, rebuild remaining tool views - #43

Merged
AffluentMods merged 7 commits into
mainfrom
review/full-pass
Nov 12, 2026
Merged

AffluentMods merged 7 commits into
mainfrom
review/full-pass

Conversation

@AffluentMods

@AffluentMods AffluentMods commented Nov 12, 2026 •

Copy link
Copy Markdown
Owner

Summary

A full review of the codebase and the UI, with the confirmed defects fixed and every remaining tool view rebuilt on one layout. Each fix has a regression test where the logic can be tested: the .NET suite goes from 269 to 1,488 tests and the Python sidecar suite from 2 to 164. Details are in the CHANGELOG entry; the main points:

Evidence integrity

  • E01: images with more than 64 MiB in one sectors section failed to open (including Cinder's own output); EnCase-style size-0 next / done sections were rejected; all-zero digests counted as recorded hashes.
  • Imager: a failing source produced endless zeros. It now stops and keeps an explicitly incomplete .partial; cancel deletes partial output; sector padding is hashed so E01 / VHD / VHDX verify; damaged source chunks are reported.
  • AFF4: stored chunks were decompressed, and unlocatable map targets read as zeros.
  • $LogFile restart-area fields were read from the wrong offsets; the USN parser could hang or stop early; FAT times were shifted by the examiner's time zone.
  • Custody: entries went to whichever case was active when work finished; a signature from an unknown key reported as verified; cinder custody verify verified nothing.

Wrong or silently incomplete results

  • YARA / IOC: long case-insensitive strings never searched, shared literals lost, conditions not evaluated.
  • Hex search folded case on hex patterns; invalid patterns reported "no matches".
  • Search: unparseable query reported "0 hits"; second index build failed.
  • ShimCache, Amcache, Linux logs, LNK times, UserAssist and several truncation flags.
  • Hard limits (Strings, YARA, Carver, Gallery, Search) are now stated when hit.

Stability and security

  • Opening an in-use file, or a slow regex in the Find dialog, exited the app.
  • Report HTML carried evidence text unescaped; the plugin trust files lived in the plugin folder; the Windows mount command interpolated the image path into PowerShell.
  • Settings and recents writes are atomic and never overwrite an unreadable file.

Interface

  • 19 tool views rebuilt (shared toolbar / empty state / footer, export everywhere, Stop buttons).
  • Cases now activates the case; Workflows can run; Hash sets can create a database; Custody checks the open case; Search is one flow.
  • Settings shows only settings that do something, and Theme is applied.
  • Hex shortcuts act only while the Hex Viewer is on screen; inspector toggle is Ctrl+Shift+B.

Second round

  • Hex Viewer: find pages through large result sets (F3 / Shift+F3 keep going past the first 1,000), the data inspector decodes from the start of the selection, and the toolbar holds together at 1366 px.
  • Filesystem browser: the record number column is filled in for NTFS (MFT record and sequence) and ext (inode).
  • Search index: rebuilding updates documents in place, and an unparseable query is reported as one.
  • The rail remembers which sections are open and scrolls to the selected tool.
  • README screenshots are captures of the real window on synthetic data; docs/screenshots.md and tools/screenshots/Capture-Window.ps1 reproduce them.
  • End-to-end tests drive the Imager, Convert, Carver and Chain of custody tools the way their screens do.

Things that change for existing data

  • Some parser columns were renamed, which changes CSV headers and keys in new bookmarks.
  • Plugins trusted through the old in-folder files must be trusted again in the Plugins tool.
  • Custody signatures from another workstation show "unknown key" until that key is trusted.
  • Encrypted case bundles are written as format version 2 (version 1 still opens).
  • Multi-volume AFF4 containers now refuse to open rather than reading as zeros.

Not verified here

Listed in LIMITATIONS.md under "Known gaps left by the full review pass": the $LogFile fix against a real log, the Hex Viewer control beyond its extracted arithmetic, real-device imaging, Volatility process handling, and most of the Python sidecar's C# wrappers.

Test plan

  • dotnet test -c Release (1,488 tests) and python -m pytest in parsers/ (164)
  • Open, create and switch cases from Home, the title bar and the Cases tool; bookmarks follow the active case
  • Image a file to E01, Verify it, Convert it to raw; cancel one mid-run and confirm nothing is left at the output path
  • Hex Viewer: find in each mode, selection backwards with Shift+Left, click in the text column, open a file that another program holds open
  • YARA with a rule that has a condition and one with an unsupported feature
  • Each rebuilt tool view in dark and light

…d Map, Graph, Search, Hash sets, VirusTotal, Shadow copies

- EmptyState control, toolbar/sub-bar/footer styles, ExportButton, ToolExport helper, AppNavigator
- DataGrid headers no longer clip in narrow columns (sort-arrow reserve 32 -> 14 px)
- Map: real photo time (GPS fix / camera clock / file time, labelled), range validation, stop, CSV/JSON/KML export
- Graph: no invented timestamps, Cc and folded MBOX headers, pick a person to filter, export
- Search: one flow (index a folder, then search), re-index updates in place, bad query is an error not 0 hits,
  second index build no longer fails on the write lock, double-click opens the hit in the Hex Viewer
- Hash sets: New vs Open (an open dialog cannot create), digest length check
- VirusTotal: only a well-formed hash is sent, status and errors are shown, lookup logged to custody; not a shell
…s; rebuild remaining tool views

Five reviewers read the whole codebase; the defects they confirmed are fixed here, each with a
test where the logic is testable. Test count 269 -> 1127 (.NET) plus 163 Python.

Evidence integrity
- E01: 64 MiB section ceiling no longer applied to sectors sections (real images failed to open);
  next/done with size 0 accepted; overlapping tables bounded; all-zero digests read as not recorded
- Imager: failing source no longer produces endless zeros (aborts, keeps an INCOMPLETE .partial and log);
  cancel deletes partial output; sector padding is hashed so E01/VHD/VHDX verify; damaged source chunks reported
- AFF4: stored chunks returned raw; unresolvable map targets are an error, not zeros; writer follows the
  chunk-size convention other readers rely on
- $LogFile restart-area fields read from the documented offsets; USN no longer hangs on a truncated tail
  or aborts on a short V3 record; FAT times no longer shifted by the examiner's time zone
- Carver: no int overflow on large extents, validates before extracting, streams output
- Custody: entries logged to the case the work started under; attestations from an unknown key are not
  reported as verified; bookmark delete scoped by case; CLI custody verify actually verifies

False negatives and wrong results
- YARA/IOC: case-insensitive strings of any length, shared literals, tagged rules, conditions evaluated
  (unsupported features skip the rule with a reason)
- Hex search: hex patterns never case-folded; invalid regex/hex reported as invalid, not 'no matches'
- Search index: a bad query is an error; re-indexing updates in place; second build no longer fails
- ShimCache decoder, Amcache SHA-1, Linux log timestamps, LNK target times, UserAssist filter,
  timeline source filter, SRUM/browser truncation flags

Stability and security
- Opening an in-use file no longer exits the app; Find dialog regex timeout handled; settings/recents/layout
  written atomically and never over an unreadable file; documents capped and extracted off the UI thread
- Report HTML: raw HTML disabled, fields encoded, CSP added, exhibit text escaped; PDF path cannot load files
- Plugins: trust moved to a per-user store, each plugin and its dependencies checked by hash;
  Windows mount no longer interpolates the path into PowerShell; Linux write blocker checks blockdev
- Python sidecar: UTF-8 I/O, serialised writes, inactivity timeout, imager seek/retry, parser hardening

UI
- All remaining tool views rebuilt on the shared layout; Cases tool now activates the case; Workflows can run;
  Settings dialog shows only settings that do something and Theme is applied; hex shortcuts only act while the
  Hex Viewer is on screen; rail scrolls to the selected tool
- Imager / Convert / Carver show damaged-source, padding and incomplete-image results; Stop buttons
- Plugins tool: turn plugins on, trust or revoke a specific file (trust lives in the user profile)
- Custody: a valid signature from an unknown key is reported as such, with how to trust a colleague's key
- Strings: one scan at a time; the 50,000-string limit is stated with how far the scan got
- Graph uses the shared MBOX header reader; report exhibits escape evidence text
- Filesystem: FAT times shown as the device's local clock, not UTC
- Custody entries are logged to the case the work started under in every tool
- Settings dialog stays open when a save fails; palette and help copy
- Tests: search index, Map KML and validation, Graph filter (1,141 .NET tests)
- CHANGELOG, LIMITATIONS, FEATURES, SECURITY updated to match
…parator; apply dotnet format

Path.GetFileName splits on the current platform's separators only, so a Windows path recorded on
Linux kept its whole path (caught by the Linux CI job).
Imaging
- Refuse to overwrite an existing image, E01 chain or leftover .partial unless asked (ImageJob.Overwrite);
  reader ignores foreign later segments and reports an incomplete chain; Verify shows both
- Linux loop mounter detaches on failure and picks read-only options per file system;
  EvidenceOpener no longer leaks its stream when detection throws

Hex
- Find pages past 1,000 hits (HexSearch.FindNext / FindPrevious) instead of wrapping at the cap
- Data inspector decodes from the start of a selection; toolbar adapts to the window width
- HexViewer is tested headlessly (Avalonia.Headless): selection, clicks, scroll clamp, empty and >4 GiB buffers

Tools
- Filesystem: live entries carry their real MFT record number / inode; empty and constant columns removed
- YARA and IOC report damaged chunks in the source; IOC logs the scanned folder as evidence, clears stale rows, can stop
- Network names the missing capture library; SRUM / compressed Prefetch say they need Windows;
  folder walks include hidden and system entries and count unreadable subfolders
- Carver: GIF and PDF carved to their real end
- Mount can unmount; Verify can be stopped; wording of verify results in plain words

Shell
- Custody write failures are surfaced; fatal errors are shown on Linux and macOS
- New palette commands: Hash a file…, Check for updates (manual only)
- Sidebar groups are remembered with the window layout; clearing the filter restores them
- Watermarks no longer read as values; one primary button per empty state
- Removed unused CrashRecovery and PythonBootstrap

Sidecar
- C# wrappers use paging, progress and error fields; new tests/Cinder.Sidecar.Tests (114)

Dev
- Screenshot harness can seed a synthetic case, bookmarks and recents, render at 2x and render dialogs

1,474 .NET tests, 164 Python.
…assumption; tab accent

- assets/screenshots: home, hex, filesystem, report. Captured from the running window at 150 % scale and
  downscaled to 1600 wide. Synthetic NTFS volume and demo case only; no real paths or account names.
- docs/screenshots.md: how they are produced (--shot ... --hold + tools/screenshots/Capture-Window.ps1)
- Harness: --hold keeps the window on screen for a capture; review renders now run off-screen
  instead of flashing a window over the desktop
- IOC summary: file names are taken under either path separator (failed on Linux CI)
- Active tab accent is a child element rather than an inset shadow (off-screen renders at other scales lost the tab's content)
- Inspector label shortened so it fits beside the LE / BE switch
…d to end

Fourteen tests that set the fields a screen sets, run the command and read the
status: imaging to Raw, E01 and AFF4; refusing to replace an existing image;
the E01 padding note; Convert's output and source checks; carving an embedded
PNG; refusing to carve beside the evidence; and the custody tool reporting an
intact log, naming an altered entry, and verifying a signature.

Test count in the changelog and feature list updated to 1,488.
@AffluentMods
AffluentMods merged commit 12f4387 into main Nov 12, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant