Skip to content

fix(tools): bound and harden the shared /v4/profile request - #1667

Open
therahul-yo wants to merge 1 commit into
supermemoryai:mainfrom
therahul-yo:claude/repo-fork-audit-pr-jrk5hc
Open

therahul-yo wants to merge 1 commit into
supermemoryai:mainfrom
therahul-yo:claude/repo-fork-audit-pr-jrk5hc

Conversation

@therahul-yo

Copy link
Copy Markdown

supermemoryProfileSearch in shared/memory-client.ts is the only Supermemory HTTP call in this package with neither a request timeout nor redirect handling. The identical /v4/profile call in openai/middleware.ts sets both, and /v4/conversations (conversations-client.ts) and /v4/memories (shared/forget-memory.ts) each set a 30s budget.

Two consequences:

  • Unbounded request. A timeout only applied when the caller supplied a signal. withSupermemory passes one (5s), but buildMemoriesText is called with no signal by the Mastra processor and the VoltAgent middleware, and by the exported buildMemoriesText / addSystemPrompt helpers. fetch has no default deadline, so a stalled connection blocks the agent turn indefinitely — the failure both integrations' surrounding try/catch is written to absorb, but which never surfaces as an error.
  • Redirects followed. The request carries Authorization: Bearer <apiKey>; a 3xx from a misconfigured or attacker-influenced baseUrl was followed silently rather than refused.

Apply a 30s PROFILE_REQUEST_TIMEOUT_MS unconditionally and set redirect: "error". A caller signal is composed with the timeout via AbortSignal.any rather than replacing it, so a caller-side budget can only shorten the request, never leave it unbounded — the wrapper is kept separate so the composition is stated once rather than re-derived at the call site.

src/shared/memory-client.test.ts existed but was absent from the test:unit file list CI runs, so its assertions never ran on a pull request; add it alongside the new coverage.

Claude-Session: https://claude.ai/code/session_01L7GkmUn6skD6dCzKtcHDbe

`supermemoryProfileSearch` in `shared/memory-client.ts` is the only
Supermemory HTTP call in this package with neither a request timeout nor
redirect handling. The identical `/v4/profile` call in
`openai/middleware.ts` sets both, and `/v4/conversations`
(`conversations-client.ts`) and `/v4/memories` (`shared/forget-memory.ts`)
each set a 30s budget.

Two consequences:

- **Unbounded request.** A timeout only applied when the caller supplied a
  signal. `withSupermemory` passes one (5s), but `buildMemoriesText` is
  called with no signal by the Mastra processor and the VoltAgent
  middleware, and by the exported `buildMemoriesText` / `addSystemPrompt`
  helpers. `fetch` has no default deadline, so a stalled connection blocks
  the agent turn indefinitely — the failure both integrations' surrounding
  try/catch is written to absorb, but which never surfaces as an error.
- **Redirects followed.** The request carries `Authorization: Bearer
  <apiKey>`; a 3xx from a misconfigured or attacker-influenced `baseUrl`
  was followed silently rather than refused.

Apply a 30s `PROFILE_REQUEST_TIMEOUT_MS` unconditionally and set
`redirect: "error"`. A caller signal is composed with the timeout via
`AbortSignal.any` rather than replacing it, so a caller-side budget can
only shorten the request, never leave it unbounded — the wrapper is kept
separate so the composition is stated once rather than re-derived at the
call site.

`src/shared/memory-client.test.ts` existed but was absent from the
`test:unit` file list CI runs, so its assertions never ran on a pull
request; add it alongside the new coverage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L7GkmUn6skD6dCzKtcHDbe
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