Skip to content

fix(security): prevent MagicByteValidator type poisoning from dropping Slack images#345

Merged
Aaronontheweb merged 3 commits into
devfrom
claude-wt-missing-slack-images
Mar 21, 2026
Merged

fix(security): prevent MagicByteValidator type poisoning from dropping Slack images#345
Aaronontheweb merged 3 commits into
devfrom
claude-wt-missing-slack-images

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Collaborator

Summary

  • Root cause: MagicByteValidator's Lazy<IContentInspector> static field referenced MimeDetective types. A transient loading failure during the static constructor permanently poisoned the type via cached TypeInitializationException, causing ALL image content scans to fail silently for the process lifetime.
  • Fix: Moved MimeDetective inspector initialization out of static fields into a lazily-initialized method with try-catch. Core magic byte validation (PNG/JPEG/GIF/WebP headers, executable detection) uses direct byte comparison and never needed MimeDetective.
  • Error handling: SlackThreadBindingActor now distinguishes scanner crashes (ContentScanError.ScanFailure) from policy rejections — scanner failures allow the file through with an error log instead of silently dropping valid images.
  • Test coverage: Added integration tests using the production MagicByteContentScanner and a FailingContentScanner to prevent regressions. All 216 tests pass.

Test plan

  • dotnet test src/Netclaw.Security.Tests/ — 49 tests pass (including new resilience test)
  • dotnet test src/Netclaw.Actors.Tests/ --filter SlackFileFlow — 12 tests pass (including 2 new integration tests)
  • dotnet test — full suite 216/216 green
  • dotnet slopwatch analyze — 0 violations

…y dropping Slack images

MagicByteValidator's Lazy<IContentInspector> static field captured a delegate
referencing MimeDetective types. If MimeDetective failed to load during the
static constructor (transient resource contention, assembly load timing), .NET
cached the TypeInitializationException permanently, making ALL image validation
fail for the process lifetime. The MagicByteContentScanner then converted
these crashes into "file rejected" results, and SlackThreadBindingActor
silently dropped the images — users sent images that the LLM never received.

Changes:
- Move MimeDetective inspector out of static field initialization into a
  lazily-initialized method (GetOrCreateInspector) with try-catch, so a
  MimeDetective failure can't poison the type. Core magic byte validation
  (PNG/JPEG/GIF/WebP headers, executable detection) uses direct byte
  comparison and doesn't need MimeDetective at all.
- Distinguish scanner failures from policy rejections in
  SlackThreadBindingActor: ScanFailure errors now allow the file through
  with an error log, instead of silently dropping valid images.
- Add integration test with production MagicByteContentScanner to catch
  scanner-related regressions.
- Add integration test verifying broken scanners don't silently drop images.
- Add unit test verifying core validation works even when MimeDetective
  is unavailable.
@Aaronontheweb Aaronontheweb enabled auto-merge (squash) March 21, 2026 01:51
…Validator

Assign null to s_inspector in the catch block and catch Exception explicitly
to satisfy slopwatch's empty catch block detection.
@Aaronontheweb Aaronontheweb merged commit de3ba12 into dev Mar 21, 2026
3 checks passed
@Aaronontheweb Aaronontheweb deleted the claude-wt-missing-slack-images branch March 21, 2026 02:00
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