diff --git a/backend/council.js b/backend/council.js index 70afcd42..baffc6df 100644 --- a/backend/council.js +++ b/backend/council.js @@ -153,7 +153,8 @@ async function ensureVectorIndex() { vectorIndexReady = true; } catch (err) { // eslint-disable-next-line no-console - console.warn(`[council] ensureIndex failed: ${err?.message || err}`); + // SECURITY: Only log error message to prevent stack trace/system path exposure + console.warn(`[council] ensureIndex failed: ${err?.message || 'unknown error'}`); } } @@ -205,7 +206,8 @@ async function captureMemoryEntry({ text, agent, role, tags = [], meta = {}, rou await vectorMemory.upsertDocs([doc]); } catch (err) { // eslint-disable-next-line no-console - console.warn(`[council] memory upsert failed: ${err?.message || err}`); + // SECURITY: Only log error message to prevent stack trace/system path exposure + console.warn(`[council] memory upsert failed: ${err?.message || 'unknown error'}`); } return; } @@ -216,7 +218,8 @@ async function captureMemoryEntry({ text, agent, role, tags = [], meta = {}, rou noteMemory.add(body, tagList, MEMORY_SOURCE, baseMeta); } catch (err) { // eslint-disable-next-line no-console - console.warn(`[council] note memory add failed: ${err?.message || err}`); + // SECURITY: Only log error message to prevent stack trace/system path exposure + console.warn(`[council] note memory add failed: ${err?.message || 'unknown error'}`); } } } @@ -248,7 +251,8 @@ async function recallMemoryEntries({ agent, role = "agent_response", query } = { .filter(Boolean); } catch (err) { // eslint-disable-next-line no-console - console.warn(`[council] memory recall failed: ${err?.message || err}`); + // SECURITY: Only log error message to prevent stack trace/system path exposure + console.warn(`[council] memory recall failed: ${err?.message || 'unknown error'}`); } } else if (noteMemory && typeof noteMemory.recall === "function") { try { @@ -266,7 +270,8 @@ async function recallMemoryEntries({ agent, role = "agent_response", query } = { .filter(Boolean); } catch (err) { // eslint-disable-next-line no-console - console.warn(`[council] note memory recall failed: ${err?.message || err}`); + // SECURITY: Only log error message to prevent stack trace/system path exposure + console.warn(`[council] note memory recall failed: ${err?.message || 'unknown error'}`); } } return []; @@ -595,10 +600,11 @@ async function runWithCouncil(raw){ } } } catch (googleErr) { - console.warn(`[council] Google ${id} route failed:`, googleErr.message || googleErr); + // SECURITY: Only log error message to prevent exposing API credentials or system internals + console.warn(`[council] Google ${id} route failed:`, googleErr.message || 'unknown error'); return { agent: id, - output: `Google ${id} error: ${googleErr.message || googleErr}`, + output: `Google ${id} error: ${googleErr.message || 'An error occurred'}`, meta: { error: true, routed: "google" } }; } @@ -631,7 +637,8 @@ async function runWithCouncil(raw){ } } } catch (toolErr) { - console.warn(`[council] ${id} tool route failed, using Claude fallback:`, toolErr.message || toolErr); + // SECURITY: Only log error message to prevent exposing API credentials or system internals + console.warn(`[council] ${id} tool route failed, using Claude fallback:`, toolErr.message || 'unknown error'); } } @@ -709,7 +716,8 @@ async function runWithCouncil(raw){ }); } } catch (perplexityErr) { - const message = perplexityErr?.message || String(perplexityErr); + // SECURITY: Only extract error message to prevent exposing API keys or system internals + const message = perplexityErr?.message || 'Unknown Perplexity error'; console.warn(`[council] Perplexity call failed:`, message); perplexityMeta = { tool: toolName, @@ -808,7 +816,12 @@ async function runWithCouncil(raw){ // Log issues if any (but don't fail the request) if (!result.passed && result.totalIssues.length > 0) { - console.log(`[council] Lens issues for @${id}:`, result.totalIssues.slice(0, 3)); + // SECURITY: Only log issue count and types to prevent exposing user data or LLM response content + const issueSummary = result.totalIssues.slice(0, 3).map(issue => ({ + lens: issue.lens || 'unknown', + type: issue.type || issue.severity || 'issue' + })); + console.log(`[council] Lens issues for @${id} (${result.totalIssues.length} total):`, issueSummary); } // Capture response with lens metadata @@ -828,7 +841,8 @@ async function runWithCouncil(raw){ } }); } catch (lensErr) { - console.warn(`[council] lens framework failed:`, lensErr.message || lensErr); + // SECURITY: Only log error message to prevent stack trace/system path exposure + console.warn(`[council] lens framework failed:`, lensErr.message || 'unknown error'); // Still capture response even if lenses fail await captureMemoryEntry({ text: finalOutput,