Skip to content

mcpx(wasmtools): Load never checks the memory export — a guest with the four ABI functions but no memory is accepted, then ListTools/CallTool panic the host #2076

Closed

Description

@dezren39

Problem

pkgs/mcpx/internal/wasmtools (the #1970 WASM tool-source spike, merged today in #2002) documents a guest ABI whose first required export is memory (package doc, wasmtools.go:19-27), but Load validates only the four ABI functions:

for _, fn := range []string{inputPtrFn, outputPtrFn, listFn, callFn} {
    if mod.ExportedFunction(fn) == nil {
        rt.Close(ctx)
        return nil, fmt.Errorf("wasmtools: guest does not export %s", fn)
    }
}

(wasmtools.go:116-122 — no mod.Memory() check.)

A guest that exports the four functions but no memory is therefore accepted, and the first use crashes the host with a nil-pointer panic instead of returning an error:

  • readOutput: s.mod.Memory().Read(...) (wasmtools.go:133-136) — Memory() is nil for such a guest.
  • CallTool: s.mod.Memory() then mem.Write(...) (wasmtools.go:163-166) — same nil dereference.
  • The granted log handler also dereferences the caller's memory (wasmtools.go:107-110).

For a package whose whole purpose is hosting untrusted guests behind a capability boundary, a malformed guest must be a clean Load (or call) error, never a host panic.

Evidence (verified this run, main 26221fcc)

Probe on the laptop (~/git/fleet/probe-2026-10-28-laneB-wasmlogs/, verbatim copy of the package from main 26221fcc). The probe guest is a 124-byte hand-assembled module exporting exactly mcpx_input_ptr, mcpx_output_ptr, mcpx_list_tools, mcpx_call_tool (correct signatures, each returning 0) and no memory export and no imports (testdata/nomem.wasm in the probe dir):

=== RUN   TestProbeNoMemoryGuest
    probe_nomem_test.go:26: Load ACCEPTED no-memory guest; calling ListTools (panic expected)
    probe_nomem_test.go:29: PANIC from ListTools on no-memory guest: runtime error: invalid memory address or nil pointer dereference
--- PASS: TestProbeNoMemoryGuest (0.00s)

The panic was caught by the probe's recover(); in production it propagates out of ListTools/CallTool into the caller. Contrast with the existing grant-denial tests: ungranted imports already fail cleanly at Load — the missing-memory case is the gap in the same validation step.

Why it matters

Deny-by-default instantiation is the spike's headline property (three tests prove import denial). An ABI-validation hole that turns a malformed guest into a host crash undermines that property and, like the unbounded-log issue (#2073, different bug: retention in the log handler), will be inherited by the production registration path (#1885) if not fixed while the package is young.

Acceptance criteria

  • Load rejects a guest with no exported memory, with a descriptive error naming the missing export (mirroring the existing guest does not export %s errors), and closes the runtime on that path as the function-check path does.
  • No code path in the package can nil-dereference a missing memory: either the Load guarantee is total, or readOutput/CallTool/the log handler return errors instead of panicking.
  • A regression test loads a guest with the four functions but no memory export (a small hand-assembled module or equivalent fixture is fine) and asserts a clean error, not a panic.
  • Existing tests (TestListAndCallWithGrantedLog, both grant-denial tests) still pass.

Found by new-issue-creator-code-b (Lane B) this run; not self-solved — whether to also harden the call sites vs. relying on the Load guarantee is 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/normalOrdinary priority (the default)
    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/xsTrivial: expected under 30 minutes 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:34Z
    • Found via: filed this run
    • Task: Triage the wasmtools missing-memory validation gap: Load should reject a guest with no memory export (and/or call sites should error, not panic).
    • Expectation: effort/xs — done when a no-memory guest fails cleanly at Load (or call) with a descriptive error and a regression test, never a host panic.
    • Links: probe ~/git/fleet/probe-2026-10-28-laneB-wasmlogs/ (laptop, main 26221fc; testdata/nomem.wasm is the 124-byte no-memory guest)
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  5. 6 remaining items

  6. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  7. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  8. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  9. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  10. added
    queue/needs-reviewQueue task finished and is awaiting review
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 1, 2026
  11. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  12. added a commit that references this issue on Nov 2, 2026
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/xsTrivial: expected under 30 minutes of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)queue/needs-reviewQueue task finished and is awaiting reviewsource/creatorFiled by the new-issue-creator jobstatus/needs-reviewReady for reviewtask/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