fix(run): harden input-file staging per gadfly #18 validation pass
executus CI / test (pull_request) Successful in 48s

Second-pass findings on the security fix:

- Mime sanitized ONCE and passed to BOTH StageInputFile and the descriptor (was
  passing raw f.MimeType to the host store while only the descriptor sanitized) —
  3 models.
- sanitizeField now also strips Unicode format chars (category Cf, incl. the bidi
  overrides U+202A–U+202E that can reorder how the descriptor renders); IsControl
  already covers \n\r\t so the explicit checks are dropped.
- fileID is sanitized before inlining + an empty file_id drops the file (defense
  vs a misbehaving stager).
- humanizeBytes clamps the prefix index so an absurd size (≥1024^6) can't index
  past "KMGTPE" and panic — a no-panic guarantee independent of the per-file cap.
- Docs sync: README Ports list gains InputFiles; tool.InputFile.Name doc now says
  the executor reduces an untrusted name to a safe base name (was claiming the
  field is already safe).

Tests: bidi/control stripping; mime sanitized in staged value + descriptor; empty
file_id drop; humanizeBytes no-panic across sizes up to 1<<62. Suite green (-race).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 14:08:57 -04:00
parent 1e65f4b6e5
commit df4033f42e
4 changed files with 83 additions and 12 deletions
+4 -3
View File
@@ -154,9 +154,10 @@ type ContinuationContext struct {
// InputFile is a non-image file the user supplied with a run (audio,
// etc.). The executor stages it into the file store under run scope and
// surfaces its file_id to the agent. Name is a safe base name (no path
// separators) suitable for /workspace/<name>; MimeType is the resolved
// content type; Data is the raw bytes.
// surfaces its file_id to the agent. Name may be an untrusted attachment
// filename — the executor reduces it to a safe base name (stripping path
// separators + control chars) before staging or exposing it as
// /workspace/<name>; MimeType is the resolved content type; Data is the raw bytes.
type InputFile struct {
Name string
MimeType string