{"record":{"id":"c80c2e9283ee2964","repo":"thedotmack/claude-mem","slug":"input-source-is-forbidden-from-tool-use-claude-mem-hard","errorCode":null,"errorMessage":"${input.source} is forbidden from tool use (claude-mem hard lockdown).","messagePattern":"(.+?) is forbidden from tool use \\(claude-mem hard lockdown\\)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/sdk/hardened-options.ts","lineNumber":145,"sourceCode":"  const canUseTool: Options['canUseTool'] = async (toolName, toolInput) => {\n    recordObserverToolAttempt({\n      source: input.source,\n      sessionDbId: input.sessionDbId,\n      contentSessionId: input.contentSessionId,\n      project: input.project,\n      tool_name: toolName,\n      tool_input: toolInput,\n      result: 'denied',\n    });\n    // Real-time visibility for the persistent audit trail. The append-only log\n    // (recordObserverToolAttempt above) is the authoritative record; this WARN\n    // surfaces the attempt in the live worker log for incident detection.\n    logger.warn('SECURITY', `Blocked tool use by ${input.source}: ${toolName}`, {\n      sessionId: input.sessionDbId,\n      source: input.source,\n      tool_name: toolName,\n    });\n    return {\n      behavior: 'deny',\n      message: `${input.source} is forbidden from tool use (claude-mem hard lockdown).`,\n    };\n  };\n\n  return {\n    model: input.model,\n    cwd: input.cwd ?? OBSERVER_SESSIONS_DIR,\n    env: input.env,\n    pathToClaudeCodeExecutable: input.pathToClaudeCodeExecutable,\n    ...(input.abortController ? { abortController: input.abortController } : {}),\n    ...(input.resume ? { resume: input.resume } : {}),\n    ...(input.spawnClaudeCodeProcess ? { spawnClaudeCodeProcess: input.spawnClaudeCodeProcess } : {}),\n    // Observer thinking is behavior-only and does not participate in the lockdown boundary.\n    ...(input.source === 'Observer' ? { thinkingConfig: { type: 'disabled' as const } } : {}),\n\n    // === Tool lockdown (defense-in-depth) ===\n    tools: [],                                        // belt: disable ALL built-in tools","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/sdk/hardened-options.ts#L127-L163","documentation":"This is the deny message returned by the hardened SDK canUseTool hook. claude-mem's Observer and KnowledgeAgent sessions are deliberately built with a hard lockdown: every tool use is denied and logged, because these agent sessions must only observe/compress, never act. The message is informational-by-design, not a bug — it records that a tool-use attempt was blocked.","triggerScenarios":"Any Observer or KnowledgeAgent SDK session (built via buildHardenedSdkOptions) attempts to call ANY tool (Bash, Write, WebFetch, etc.), triggering the canUseTool callback which unconditionally returns behavior:'deny'.","commonSituations":"Model spontaniously tries to run Bash or edit a file during an observation session; a prompt injection in watched content convinces the observer to call a tool; misconfigured session that was meant to be an interactive Claude session got built with hardened options.","solutions":["If you are a user seeing this in logs: no action needed — the security boundary worked; check the audit log via recordObserverToolAttempt for what was attempted","If you expected real tool use: do not route that workload through buildHardenedSdkOptions/Observer sessions; use a normal interactive session","If you are developing: confirm the call site legitimately should be locked down; do not weaken the deny — adjust the session type instead"],"exampleFix":"// before: observer tries to use tools and gets denied\nconst options = buildHardenedSdkOptions({ source: 'Observer', ... });\n// after: use a non-hardened path only when tool use is intentional\nconst options = buildSdkOptionsForInteractiveAgent({ ... }); // if tool use is expected","handlingStrategy":"validation","validationCode":null,"typeGuard":"function isHardenedSource(s: string): s is 'Observer' | 'KnowledgeAgent' {\n  return s === 'Observer' || s === 'KnowledgeAgent';\n}","tryCatchPattern":"if (result.behavior === 'deny') {\n  logger.warn('Tool use denied by hard lockdown:', result.message);\n  // continue without executing the tool; do not retry\n}","preventionTips":["Never route workloads that need tools through buildHardenedSdkOptions","Treat this deny message in logs as expected security behavior, not a fault","Review recordObserverToolAttempt audit entries if you see frequent denials","Keep tool-requiring agents on separate, non-hardened session construction"],"tags":["security","sdk","tool-use","deny"],"backgroundTag":"permission-denied","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}