{"record":{"id":"718e9f47e19b28bc","repo":"rohitg00/agentmemory","slug":"refusing-to-read-image-outside-managed-store-da","errorCode":null,"errorMessage":"Refusing to read image outside managed store: ${data.raw.imageData}","messagePattern":"Refusing to read image outside managed store: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/functions/compress.ts","lineNumber":91,"sourceCode":"  sdk.registerFunction(\"mem::compress\", \n    async (data: {\n      observationId: string;\n      sessionId: string;\n      raw: RawObservation;\n    }) => {\n      const startMs = Date.now();\n\n      let imageDescription: string | undefined;\n      const hasImage = data.raw.modality === \"image\" || data.raw.modality === \"mixed\";\n\n      if (hasImage && data.raw.imageData && provider.describeImage) {\n        try {\n          let base64Data = data.raw.imageData;\n          let mimeType = \"image/png\";\n\n          if (!data.raw.imageData.startsWith(\"/9j/\") && !data.raw.imageData.startsWith(\"iVBOR\")) {\n            if (!isManagedImagePath(data.raw.imageData)) {\n              throw new Error(`Refusing to read image outside managed store: ${data.raw.imageData}`);\n            }\n            const fileBuffer = readFileSync(data.raw.imageData);\n            base64Data = fileBuffer.toString(\"base64\");\n            if (data.raw.imageData.endsWith(\".jpg\") || data.raw.imageData.endsWith(\".jpeg\")) mimeType = \"image/jpeg\";\n            else if (data.raw.imageData.endsWith(\".webp\")) mimeType = \"image/webp\";\n            else if (data.raw.imageData.endsWith(\".gif\")) mimeType = \"image/gif\";\n          }\n\n          imageDescription = await provider.describeImage(base64Data, mimeType, VISION_DESCRIPTION_PROMPT);\n          logger.info(\"Image described by vision model\", { obsId: data.observationId });\n        } catch (err) {\n          const msg = err instanceof Error ? err.message : String(err);\n          logger.warn(\"Vision model call failed, falling back to text-only compression\", {\n            obsId: data.observationId,\n            error: msg,\n          });\n        }\n      }","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/rohitg00/agentmemory/blob/e04ba88819c365c9acf9d6661ea802143e728bd6/src/functions/compress.ts#L73-L109","documentation":"The compress function can accept either inline base64 image data or a path to an image previously stored in agentmemory's managed store. For security, arbitrary filesystem paths are refused unless isManagedImagePath() confirms the path lives inside the managed store. This prevents the function from being used to read arbitrary files and encode them as base64.","triggerScenarios":"Calling mem::compress with raw.imageData set to a filesystem path (e.g. /home/user/photo.png, or a relative path) that is not inside the managed image store, and whose content does not begin with JPEG ('/9j/') or PNG ('iVBOR') base64 magic prefixes.","commonSituations":"Passing a local screenshot path instead of reading the file yourself; hardcoding an absolute path that worked before the managed-store restriction was added (version change); moving/renaming the data directory so the path is no longer recognized as managed.","solutions":["Read the file yourself and pass its base64 content in raw.imageData instead of a path.","Store the image through the managed image write path first, then pass the returned managed path.","Verify the path is inside the configured managed store directory (check isManagedImagePath logic / data dir).","Ensure you're on a consistent agentmemory version so the managed store location matches."],"exampleFix":"// before\nawait trigger({ function_id: 'mem::compress', payload: { raw: { imageData: '/tmp/shot.png' } } });\n// after\nconst b64 = readFileSync('/tmp/shot.png').toString('base64');\nawait trigger({ function_id: 'mem::compress', payload: { raw: { imageData: b64 } } });","handlingStrategy":"validation","validationCode":"function isInlineBase64Image(s: string): boolean {\n  return s.startsWith('/9j/') || s.startsWith('iVBOR');\n}\nfunction toPayload(raw: string) {\n  if (isInlineBase64Image(raw)) return { imageData: raw };\n  const b64 = readFileSync(resolveManagedPath(raw)).toString('base64');\n  return { imageData: b64 };\n}","typeGuard":"function isInlineImageData(v: unknown): v is string {\n  return typeof v === 'string' && (v.startsWith('/9j/') || v.startsWith('iVBOR'));\n}","tryCatchPattern":"try {\n  return await trigger({ function_id: 'mem::compress', payload: { raw } });\n} catch (e) {\n  if (String(e.message).includes('Refusing to read image outside managed store')) {\n    return await compressViaBase64(raw);\n  }\n  throw e;\n}","preventionTips":["Default to passing base64 content, never filesystem paths.","Only use paths returned by agentmemory's managed image write API.","Document that ad-hoc absolute paths are blocked by design.","Keep the daemon and its data directory stationary so managed paths stay valid."],"tags":["security","validation","path-traversal","images"],"backgroundTag":"path-outside-managed-store","analyzedSha":"e04ba88819c365c9acf9d6661ea802143e728bd6","analyzedAt":"2026-08-30T01:07:40.754Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}