Skip to content

Attachments: three-way MIME classification + cap raise + dangerous filename gate - #178

Merged
Awakehsh merged 1 commit into
mainfrom
feat/attachment-mime-classification
May 12, 2026
Merged

Attachments: three-way MIME classification + cap raise + dangerous filename gate#178
Awakehsh merged 1 commit into
mainfrom
feat/attachment-mime-classification

Conversation

@Awakehsh

@Awakehsh Awakehsh commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Tighten the gateway's attachment validation layer: split the previous binary MIME check into an explicit three-way classifier, add a filename-based dangerous-extension gate, and raise the inline/URL-ref size caps to align with what modern multimodal models accept.

What changes

MIME classification — internal/attachments/mime.go

Splits the binary IsSupportedMediaType into three predicates so different gates can make different decisions:

  • IsDangerous(mime) — executables / installers / scripts (application/x-msdownload, application/x-msi, application/x-sh, application/x-bat, ...). Always rejected at every boundary.
  • IsExtractable(mime) — formats with extractable text or transcodable images: PDF, the Office family (DOCX/XLSX/PPTX), CSV/TXT/JSON/HTML, OpenDocument, RTF/EPUB, plus the native image subtypes (jpeg/png/gif/webp) and HEIC/HEIF/AVIF/TIFF/BMP. The inline-base64 path requires this.
  • IsPassthrough(mime) — non-extractable but not dangerous (archives, audio/video, octet-stream). URL-only refs allowed; the agent's local tools (bash, archive_extract, etc.) handle them.

New IsDangerousFilename(name) filename-extension denylist catches the common pattern where a hostile upload arrives as application/octet-stream + a meaningful extension (.exe / .bat / .sh / .msi / .ps1 / .lnk / ...). MIME-only checks miss this — gateway callers should run both.

IsSupportedMediaType is retained as a thin deprecated wrapper (IsExtractable || IsPassthrough) so existing callers keep type-checking; new code should call the explicit predicates.

Size caps — internal/attachments/consts.go

  • MaxMultimodalBodyBytes: 30 → 40 MB (room below Anthropic's 32 MB request limit after base64 encoding + JSON overhead)
  • MaxDecodedAttachmentBytes: 20 → 25 MB (sum of inline-decoded attachments per request)
  • New MaxFileRefSizeBytes = 500 MB (per-file ceiling for URL-based refs, matches claude.ai)
  • New MaxInlineSingleFile = 25 MB (single-file ceiling for inline base64)

Gateway gates — cmd/gateway/internal/{handlers,openai}/

  • task.go + openai/content.go — switch the inline-attachment gate from IsSupportedMediaType to the explicit IsDangerous + IsExtractable pair. Dangerous types are rejected at every entry point; non-dangerous unsupported types fall back to URL-only refs instead of being rejected outright.

Tests

  • mime_test.go — three-way no-overlap matrix + 30-case IsDangerousFilename denylist (case-insensitive, multi-dot extensions, hidden files) + backward-compat for the deprecated wrapper.
  • consts_test.go — cross-cap invariants (MaxInlineSingleFile <= MaxDecodedAttachmentBytes, MaxFileRefSizeBytes > MaxMultimodalBodyBytes, ...).
  • content_test.go — size-limit assertion adjusted from 21 MB → 26 MB to match the new cap.

Backward compatibility

  • IsSupportedMediaType retained as a deprecated wrapper — existing external callers continue to compile.
  • All cap changes are upward — clients sending payloads that were valid before remain valid.
  • No new required fields; no schema changes outside the validation layer.

Test plan

  • go build ./... clean
  • go test ./internal/attachments/ ./cmd/gateway/internal/openai/ -count=1 — green
  • Manual: IsSupportedMediaType callers still compile (wrapper retained)

…ous filename gate

Tighten the gateway's attachment validation layer.

mime.go:
- Split IsSupportedMediaType into IsDangerous / IsExtractable /
  IsPassthrough so different code paths can make different decisions.
  IsSupportedMediaType retained as a deprecated wrapper for existing
  callers.
- New IsDangerousFilename helper catches the application/octet-stream +
  meaningful-extension pattern (.exe / .bat / .sh / .msi / .ps1 / ...)
  that pure-MIME checks miss. Gateway callers should run both.

consts.go:
- MaxMultimodalBodyBytes 30 -> 40 MB (room under Anthropic's 32 MB
  request limit after base64 + JSON overhead).
- MaxDecodedAttachmentBytes 20 -> 25 MB (inline-decoded sum per
  request).
- New MaxFileRefSizeBytes = 500 MB (URL-ref per-file ceiling).
- New MaxInlineSingleFile = 25 MB (single-file inline ceiling).

cmd/gateway:
- task.go + openai/content.go switch the inline-attachment gate from
  IsSupportedMediaType to the explicit IsDangerous + IsExtractable
  pair. Dangerous types are rejected at every entry point; non-
  dangerous unsupported types fall back to URL-only refs instead of
  being rejected outright.

tests:
- mime_test.go pins the three-way no-overlap invariant + 30-case
  IsDangerousFilename denylist (case-insensitive, multi-dot
  extensions, hidden files).
- consts_test.go pins cross-cap invariants.
- content_test.go size-limit data updated 21 MB -> 26 MB.
@Awakehsh
Awakehsh force-pushed the feat/attachment-mime-classification branch from c719fa2 to c10ac70 Compare May 12, 2026 07:41
@Awakehsh
Awakehsh merged commit b785eb8 into main May 12, 2026
6 checks passed
@Awakehsh
Awakehsh deleted the feat/attachment-mime-classification branch June 8, 2026 03:32
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