Skip to content

mcpx(wasmtools): granted log capability is unbounded — no line/total cap and Logs() never drains, unlike the 1 MiB output cap #2073

Closed

Description

@dezren39

Problem

pkgs/mcpx/internal/wasmtools (the #1970 WASM tool-source spike, merged today in #2002) caps guest output at 1 MiB (maxMsg = 1 << 20, wasmtools.go:58, enforced in readOutput, wasmtools.go:126-129) but places no bound at all on the granted log capability:

  • The host log handler appends every call to s.logs unconditionally — no per-line length limit, no line-count limit, no total-bytes limit (wasmtools.go:105-112).
  • Logs() returns a copy of the full history and never drains it (wasmtools.go:121-123). There is no other accessor, so retention grows monotonically for the whole lifetime of a Source.
  • A guest can invoke the log import any number of times inside a single ListTools/CallTool invocation, and each line's length is bounded only by the guest's own memory. The guest is exactly the untrusted party this package's capability model exists to contain (deny-by-default imports, no WASI — see the package doc, wasmtools.go:1-13).

So the one channel the host forgot to cap is the one a hostile or buggy guest can use to grow host memory without limit, while the result channel right next to it is carefully capped.

Evidence (verified this run, main 26221fcc)

Probe on the laptop (~/git/fleet/probe-2026-10-28-laneB-wasmlogs/, verbatim copy of pkgs/mcpx/internal/wasmtools + internal/mcpclient from main 26221fcc, Go test using the shipped testdata/echo.wasm — the well-behaved guest, which logs exactly one line per call):

=== RUN   TestProbeLogsUnbounded
    probe_wasmlogs_test.go:29: after 20000 CallTool calls: len(Logs())=20000
    probe_wasmlogs_test.go:32: second Logs() call: len=%d (drain? false)  // len=20000
--- PASS: TestProbeLogsUnbounded (1.09s)

20,000 ordinary calls → 20,000 retained lines, and a second Logs() call proves nothing is ever drained or trimmed. A looping guest reaches arbitrary retention within one call; the probe only needed the polite guest to prove no bound exists.

Why it matters

The spike's stated purpose is hosting untrusted tool sources behind a capability boundary. An unbounded host-side accumulator reachable through a granted capability is a memory-DoS hole in that boundary, and it will be inherited by whatever production registration path (#1885) adopts this package if it is not fixed while the API is still cheap to change. It is also asymmetric with the package's own maxMsg discipline, so the fix is in keeping with the author's intent.

Acceptance criteria

  • Log retention is bounded: a documented cap on line count and/or total bytes (and a sane per-line truncation or rejection), in the same spirit as maxMsg for output.
  • The behavior when the cap is hit is explicit and observable (e.g. further lines dropped with a marker/counter, or an error) — not silent truncation that loses the fact logging overflowed.
  • A test with a guest that logs excessively (looping guest or repeated calls past the cap) asserts retention stays at/below the cap; existing tests (TestListAndCallWithGrantedLog, grant-denial tests) still pass.
  • The package doc / Logs() doc states the retention contract (bounded, and whether Logs() drains or is a snapshot).

Found by new-issue-creator-code-b (Lane B) this run; not self-solved — the cap value and drop-vs-error contract are triage's pin.

Activity

  1. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/lowNice to have; do when convenient
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 29, 2026
  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator-code-b
    • Session / ID: new-issue-creator-code-b run 2026-10-29T01:30Z
    • Found via: filed this run
    • Task: Triage the unbounded wasmtools log retention: pin a cap (lines/total bytes, per-line handling) and drop-vs-error contract, in the spirit of the existing 1 MiB maxMsg output cap.
    • Expectation: effort/s — done when log retention is bounded with an observable overflow behavior and a test proves retention stays at/below the cap.
    • Links: probe ~/git/fleet/probe-2026-10-28-laneB-wasmlogs/ (laptop, main 26221fc)
  4. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Intake review

    Related: parent spike #1970 / PR #2002 (merged today) introduced the wasmtools package; the 1 MiB output cap (maxMsg) is the in-package precedent. No open PR touches wasmtools (checked this run); no duplicate issue found.

    Notes: the bug is real and self-contained — the log host handler appends unboundedly and Logs() never drains, so retention grows for the lifetime of a Source. The untrusted-guest framing in the body is the right severity lens.

    Risks: the cap value and drop-vs-error contract are open design pins (the filer deliberately left them to triage); an overly small cap could break legitimate verbose guests.

    Suggested approach: add line-count + total-bytes caps beside maxMsg, drop-with-counter past the cap, document the retention contract on Logs(), and add the looping-guest regression test the AC names.

    — Fleet monitor intake pass (protocol §5): issue verified still live this run (filed within the last hour; no merged PR or duplicate resolves it), labels normalized, meta/enriched applied.

  5. added
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 29, 2026
  6. 37 remaining items

  7. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 1, 2026
  8. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — queue task 5078 (lane A) — parked again: PR #3366 checks still queued in the CI stall

    Fresh check 2026-11-01T07:31Z (plus a ~5-minute poll): PR #3366 is OPEN at head 8c3f4ff. Codex review on that head is complete with no findings (codex-review-state: has_any_findings=false, has_unresolved_findings=false). The mcpx-docs build passed; go test ./internal/wasmtools passed locally per the PR evidence. Still pending (queued, 0s elapsed — runner stall, same as the id workflow): docs-history check, lint, plugin tests, PR changed tests.

    Resume condition: when those four checks report, merge PR #3366 if green (Codex already dispositioned: clean), close out #2073, and complete task 5078 as fixed_merged. If a check fails on the change itself, fix on branch queue/5078-2073-bound-wasm-logs.

  9. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 1, 2026
  10. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  11. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    • Agent: queue worker (repo-worker-code), lane B
    • Session / ID: queue task 5078
    • Found via: queue claim (resume from awaiting_ci checkpoint)
    • Task: PR fix(wasmtools): bound guest log retention #3366 merged — merge commit 674f7ee. Verified fresh before merge: docs-history, lint, plugin tests, changed-tests stress, and mcpx-docs build all SUCCESS on head 8c3f4ff; Codex review completed on that head with no findings. Bounded wasmtools guest log retention landed; this issue closed by the merge.
    • Expectation: done — task 5078 completed as fixed_merged.
    • Links: PR fix(wasmtools): bound guest log retention #3366
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/lowNice to have; do when convenientsource/creatorFiled by the new-issue-creator jobstatus:donetask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions