Mostly safe — a couple of notes worth reading.
Scanned 5/1/2026, 7:56:56 AM·Cached result·Fast Scan·45 rules·View source ↗·How we decide ↗
AIVSS Score
Low
Severity Breakdown
0
critical
0
high
30
medium
27
low
MCP Server Information
Findings
This package has a **B security grade** and a **low safety score of 59/100**, indicating moderate risk. While it has no critical or high-severity issues, it contains **30 medium and 27 low-severity findings**, mostly around **readiness gaps, ANSI escape injection risks, and resource exhaustion vulnerabilities**, which could lead to stability or minor security issues if unaddressed. The lack of top findings suggests no immediate showstoppers, but the volume of medium-risk issues warrants caution before installation.
No known CVEs found for this package or its dependencies.
Scan Details
Want deeper analysis?
Fast scan found 57 findings using rule-based analysis. Upgrade for LLM consensus across 5 judges, AI-generated remediation, and cross-file taint analysis.
Building your own MCP server?
Same rules, same LLM judges, same grade. Private scans stay isolated to your account and never appear in the public registry. Required for code your team hasn’t shipped yet.
Showing 1–30 of 57 findings
57 findings
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 349 | const last = _deprecationLogLastAt.get(key) || 0; |
| 350 | if (now - last < DEPRECATION_LOG_INTERVAL_MS) continue; |
| 351 | _deprecationLogLastAt.set(key, now); |
| 352 | console.warn(`[awareness_recall] [deprecated param used] ${key} — migrate to single-parameter \`query\` (F-053)`); |
| 353 | } |
| 354 | } |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 94 | if (hit) results.byCategory[category].hits++; |
| 95 | |
| 96 | const status = hit ? '✅' : '❌'; |
| 97 | console.log(` ${status} [${category}] "${query}"`); |
| 98 | if (!hit) { |
| 99 | console.log(` Expected: ${expectedTitles.join(', ')}`); |
| 100 | console.log(` Got top-5: ${titles.join(' | ') || '(none)'}`); |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 76 | jsonResponse(res, { error: 'Not Found' }, 404); |
| 77 | } catch (err) { |
| 78 | console.error('[awareness-local] request error:', err.message); |
| 79 | track('error_occurred', { error_code: err.code || 'unknown', component: 'api' }); |
| 80 | jsonResponse(res, { error: 'Internal Server Error' }, 500); |
| 81 | } |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 544 | } |
| 545 | } catch { |
| 546 | console.log(`Awareness Local: running (PID ${pid})`); |
| 547 | console.log(` Raw response: ${resp.body}`); |
| 548 | } |
| 549 | } |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 208 | ).all(); |
| 209 | } catch (err) { |
| 210 | // Skills table may not exist in older DBs — don't silently pretend 0. |
| 211 | console.warn(`[card-quality-report] skills query failed: ${err.message}`); |
| 212 | } |
| 213 | |
| 214 | // --------------------------------------------------------------------------- |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 452 | ORDER BY created_at ASC` |
| 453 | ).all(); |
| 454 | } catch (err) { |
| 455 | console.warn(`${LOG_PREFIX} _pushCardsV2 query failed:`, err.message); |
| 456 | return { synced: 0, errors: 0, conflicts: 0 }; |
| 457 | } |
| 458 | if (!cards.length) return { synced: 0, errors: 0, conflicts: 0 }; |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 262 | ); |
| 263 | process.exit(0); |
| 264 | } |
| 265 | console.error( |
| 266 | `[awareness-local] Port ${port} is held by another process but workspace switch failed:\n` + |
| 267 | ` ${switchRes ? `HTTP ${switchRes.status}: ${switchRes.body.slice(0, 200)}` : 'no response'}\n` + |
| 268 | ` Stop the existing daemon or pass --port <other> to run a second instance.` |
| 269 | ); |
| 270 | process.exit(1); |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 590 | headers: { ...this._authHeaders(), 'Content-Type': 'application/json', 'Content-Length': String(Buffer.byteLength(jsonBody)) }, |
| 591 | }); |
| 592 | if (status >= 200 && status < 300) return JSON.parse(body); |
| 593 | console.warn(`${LOG_PREFIX} POST ${endpoint} → HTTP ${status}: ${body.slice(0, 200)}`); |
| 594 | return null; |
| 595 | } catch (err) { console.warn(`${LOG_PREFIX} POST ${endpoint} failed:`, err.message); return null; } |
| 596 | } |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 94 | for (const event of parsed) { |
| 95 | // Handle event asynchronously — don't block the stream |
| 96 | handleSSEEvent(event).catch((err) => { |
| 97 | console.warn(`${LOG_PREFIX} SSE event handler error:`, err.message); |
| 98 | }); |
| 99 | } |
| 100 | }); |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 89 | }).catch(() => {}); |
| 90 | let lastPct = 0; |
| 91 | for (let i = 0; i < 60; i++) { |
| 92 | const r = await fetch('/api/v1/scan/status').catch(() => null); |
| 93 | if (r && r.ok) { |
| 94 | const s = await r.json(); |
| 95 | const status = s?.status || 'idle'; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 70 | // Derive has_docs / has_readme from scan/files if scan/status doesn't provide them. |
| 71 | try { |
| 72 | const r = await fetch(`${base}/scan/files?category=docs&limit=1`); |
| 73 | if (r.ok) { |
| 74 | const d = await r.json(); |
| 75 | if ((d?.total || 0) > 0) meta.has_docs = true; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 101 | const started = Date.now(); |
| 102 | try { |
| 103 | const url = `/api/v1/search?q=${encodeURIComponent(query)}&limit=${Math.max(limit, 8)}`; |
| 104 | const r = await fetch(url); |
| 105 | const elapsedMs = Date.now() - started; |
| 106 | if (!r.ok) return { items: [], meta: { elapsedMs, total: 0, raw_hits: 0 } }; |
| 107 | const data = await r.json(); |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 49 | }; |
| 50 | |
| 51 | try { |
| 52 | const r = await fetch(`${base}/stats`); |
| 53 | if (r.ok) { |
| 54 | const s = await r.json(); |
| 55 | meta.total_cards = s?.totalKnowledge ?? s?.stats?.totalKnowledge ?? 0; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 59 | async function getProjectDir() { |
| 60 | try { |
| 61 | const r = await fetch('/healthz'); |
| 62 | const j = await r.json(); |
| 63 | return j?.project_dir || '—'; |
| 64 | } catch { return '—'; } |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 123 | /** Fetch recent knowledge cards for tag-hotness based question generation. */ |
| 124 | async function loadKnowledgeMeta({ limit = 30 } = {}) { |
| 125 | try { |
| 126 | const r = await fetch(`/api/v1/knowledge?limit=${limit}`); |
| 127 | if (!r.ok) return []; |
| 128 | const data = await r.json(); |
| 129 | return data?.items || []; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 11 | async function fetchJson(url, opts) { |
| 12 | try { |
| 13 | const r = await fetch(url, opts); |
| 14 | if (!r.ok) return null; |
| 15 | return await r.json(); |
| 16 | } catch { return null; } |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 2793 | // Load workspaces async |
| 2794 | try { |
| 2795 | const ws = await (await fetch('/api/v1/workspaces')).json(); |
| 2796 | const el = document.getElementById('ws-list'); |
| 2797 | if (!ws || Object.keys(ws).length === 0) { |
| 2798 | el.innerHTML = `<span style="color:var(--text-muted);font-size:0.82rem">${t('settings.ws_no')}</span>`; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 35 | async function fetchJson(url) { |
| 36 | try { |
| 37 | const r = await fetch(url); |
| 38 | if (!r.ok) return null; |
| 39 | return await r.json(); |
| 40 | } catch { return null; } |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 119 | async function getWikiSummary() { |
| 120 | try { |
| 121 | const r = await fetch('/api/v1/scan/files?category=wiki&limit=10'); |
| 122 | if (r.ok) { |
| 123 | const data = await r.json(); |
| 124 | const pages = Array.isArray(data?.files) ? data.files : []; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 897 | // ── Helpers ── |
| 898 | async function api(path, options) { |
| 899 | try { const r = await fetch(API + path, options); if (!r.ok) throw new Error('HTTP ' + r.status); return await r.json(); } catch (e) { console.error('[api]', path, e); return null; } |
| 900 | } |
| 901 | let workspaceDataLoadToken = 0; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 81 | } catch {} |
| 82 | |
| 83 | try { |
| 84 | const r = await fetch(`${base}/scan/files?category=wiki&limit=5`); |
| 85 | if (r.ok) { |
| 86 | const data = await r.json(); |
| 87 | const pages = Array.isArray(data?.files) ? data.files : []; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 57 | } catch {} |
| 58 | |
| 59 | try { |
| 60 | const r = await fetch(`${base}/scan/status`); |
| 61 | if (r.ok) { |
| 62 | const s = await r.json(); |
| 63 | const langs = s?.languages || s?.language_counts || {}; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 15 | return r.json(); |
| 16 | } |
| 17 | async function get(path) { |
| 18 | const r = await fetch(`${API}${path}`); |
| 19 | if (!r.ok) throw new Error(`${path} → ${r.status}`); |
| 20 | return r.json(); |
| 21 | } |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 186 | // than asking them to "connect cloud" a second time. |
| 187 | (async () => { |
| 188 | try { |
| 189 | const r = await fetch('/api/v1/sync/status'); |
| 190 | if (r.ok) { |
| 191 | const s = await r.json(); |
| 192 | if (s?.cloud_enabled || s?.enabled || s?.connected) { |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 2947 | async function checkDaemon() { |
| 2948 | try { |
| 2949 | const resp = await fetch('/healthz'); |
| 2950 | if (!resp.ok) throw new Error(); |
| 2951 | const d = await resp.json(); |
| 2952 | document.getElementById('daemon-dot').className = 'dot ok'; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 259 | priority: z.string().optional().describe('Priority filter (tasks/risks)'), |
| 260 | session_id: z.string().optional().describe('Session ID (for session_history)'), |
| 261 | agent_role: z.string().optional().describe('Agent role filter'), |
| 262 | query: z.string().optional().describe('Keyword filter'), |
| 263 | }, |
| 264 | async (params) => { |
| 265 | try { |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" — the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 298 | 'Memory identifier (ignored in local mode, uses project dir)', |
| 299 | ), |
| 300 | source: z.string().optional().describe('Client source identifier'), |
| 301 | query: z.string().optional().describe('Current user request or task focus for context shaping'), |
| 302 | days: z.number().optional().default(7).describe( |
| 303 | 'Days of history to load', |
| 304 | ), |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" — the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 429 | priority: z.string().optional().describe('Priority filter (tasks/risks)'), |
| 430 | session_id: z.string().optional().describe('Session ID (for session_history)'), |
| 431 | agent_role: z.string().optional().describe('Agent role filter'), |
| 432 | query: z.string().optional().describe('Keyword filter'), |
| 433 | }, |
| 434 | async (params) => { |
| 435 | try { |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" — the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 83 | 'Memory identifier (ignored in local mode, uses project dir)' |
| 84 | ), |
| 85 | source: z.string().optional().describe('Client source identifier'), |
| 86 | query: z.string().optional().describe('Current user request or task focus for context shaping'), |
| 87 | days: z.number().optional().default(7).describe( |
| 88 | 'Days of history to load' |
| 89 | ), |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" — the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
Package declares an install-time hook (npm postinstall/preinstall/prepare, setup.py cmdclass override, custom setuptools install class, or non-default pyproject build-backend). Anyone installing this package runs the hook. Confirm the hook is necessary and review its contents; prefer shipping a plain library without install-time execution.
Evidence
| 61 | "benchmark:universal": "node bin/awareness-local.mjs benchmark --project ../../tests/memory-benchmark/projects/universal-core --dataset ../../tests/memory-benchmark/datasets/universal_core.jsonl --backend all --reindex --report ../../tests/memory-benchmark/reports/universal_core_baseline.json", |
| 62 | "benchmark:universal:robust": "node bin/awareness-local.mjs benchmark --project ../../tests/memory-benchmark/projects/universal-core --dataset ../../tests/memory-benchmark/datasets/universal_robust.js |
Remediation
Prefer libraries that do not require install-time code execution: - Drop `postinstall`/`preinstall`/`prepare` scripts if the work can happen at runtime or build-time instead. - Ship pre-built native binaries rather than compiling via a custom `cmdclass` or `build_ext` override. - For Dockerfiles: replace `RUN curl … | sh` with a pinned download + checksum verification + explicit `RUN` of a named script. - If the hook is unavoidable, document exactly what it does so downstream reviewers
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 207 | } |
| 208 | if (!Array.isArray(methods)) methods = []; |
| 209 | let pitfalls = []; |
| 210 | if (s.pitfalls) { try { pitfalls = JSON.parse(s.pitfalls); } catch {} } |
| 211 | let verification = []; |
| 212 | if (s.verification) { try { verification = JSON.parse(s.verification); } catch {} } |
| 213 | return { |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 1431 | function _safeJsonParse(val, fallback) { |
| 1432 | if (Array.isArray(val)) return val; |
| 1433 | if (typeof val === 'string') { |
| 1434 | try { const p = JSON.parse(val); if (Array.isArray(p)) return p; } catch {} |
| 1435 | } |
| 1436 | return fallback; |
| 1437 | } |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 30 | } |
| 31 | |
| 32 | function tearDown(markComplete = true) { |
| 33 | if (pollAbort) { try { pollAbort(); } catch {} pollAbort = null; } |
| 34 | if (overlayEl) { |
| 35 | overlayEl.remove(); |
| 36 | overlayEl = null; |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 207 | let pitfalls = []; |
| 208 | try { pitfalls = JSON.parse(skill.pitfalls || '[]'); } catch {} |
| 209 | let verification = []; |
| 210 | try { verification = JSON.parse(skill.verification || '[]'); } catch {} |
| 211 | |
| 212 | // Hydrate top-3 source cards so the skill is self-contained — |
| 213 | // LLM sees the linked context, not just IDs. "skill = head of its |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 2822 | } |
| 2823 | el.innerHTML = h || `<span style="color:var(--text-muted);font-size:0.82rem">${t('settings.ws_no_user')}</span>`; |
| 2824 | } |
| 2825 | } catch {} |
| 2826 | } |
| 2827 | |
| 2828 | function settingDisplay(label, value, isHtml) { |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 54 | const s = await r.json(); |
| 55 | meta.total_cards = s?.totalKnowledge ?? s?.stats?.totalKnowledge ?? 0; |
| 56 | } |
| 57 | } catch {} |
| 58 | |
| 59 | try { |
| 60 | const r = await fetch(`${base}/scan/status`); |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 33 | try { |
| 34 | await post('/cloud/auth/open-browser', { url }); |
| 35 | } catch { |
| 36 | try { window.open(url, '_blank'); } catch {} |
| 37 | } |
| 38 | } |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 456 | try { |
| 457 | const documents = batch.map(node => { |
| 458 | let meta = {}; |
| 459 | try { meta = JSON.parse(node.metadata || '{}'); } catch (_) {} |
| 460 | return { |
| 461 | title: node.title, |
| 462 | content: node.content || '', |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 861 | function setLocale(loc) { |
| 862 | if (!LOCALES[loc]) return; |
| 863 | currentLocale = loc; |
| 864 | try { localStorage.setItem('awareness_locale', loc); } catch {} |
| 865 | // Re-apply static labels + re-render current view |
| 866 | applyStaticI18n(); |
| 867 | if (typeof updateLangLabel === 'function') updateLangLabel(); |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 146 | const res = await pushCard(apiBase, memoryId, auth, card, card.version ?? undefined); |
| 147 | if (res.status >= 200 && res.status < 300) { |
| 148 | let cid = null; |
| 149 | try { cid = JSON.parse(res.body)?.id || JSON.parse(res.body)?.cloud_id; } catch {} |
| 150 | const sql = cid |
| 151 | ? 'UPDATE knowledge_cards SET cloud_id = ?, synced_to_cloud = 1 WHERE id = ?' |
| 152 | : 'UPDATE knowledge_cards SET synced_to_cloud = 1 WHERE id = ?'; |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 13 | try { localStorage.setItem(k, v); } catch {} |
| 14 | }; |
| 15 | const del = (k) => { |
| 16 | try { localStorage.removeItem(k); } catch {} |
| 17 | }; |
| 18 | |
| 19 | const State = { |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 189 | const content = esc(r.content || ""); |
| 190 | let daysAgo = 0; |
| 191 | if (r.created_at) { |
| 192 | try { daysAgo = Math.floor((Date.now() - new Date(r.created_at).getTime()) / 86400000); } catch {} |
| 193 | } |
| 194 | if (score > 0.8 && daysAgo > 3) { |
| 195 | return ` <aha score="${score.toFixed(2)}" days-ago="${daysAgo}">${content}</aha>`; |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 77 | headers: { 'Content-Type': 'application/json' }, |
| 78 | body: JSON.stringify({ enabled }), |
| 79 | }); |
| 80 | } catch {} |
| 81 | }; |
| 82 | root.querySelector('[data-action="next"]').onclick = async () => { await persistOptIn(); onNext(); }; |
| 83 | root.querySelectorAll('[data-action="skip-all"]').forEach((b) => { |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 87 | const pages = Array.isArray(data?.files) ? data.files : []; |
| 88 | meta.wiki_titles = pages.map((p) => p.title).filter(Boolean).slice(0, 5); |
| 89 | } |
| 90 | } catch {} |
| 91 | |
| 92 | return meta; |
| 93 | } |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 209 | let pitfalls = []; |
| 210 | if (s.pitfalls) { try { pitfalls = JSON.parse(s.pitfalls); } catch {} } |
| 211 | let verification = []; |
| 212 | if (s.verification) { try { verification = JSON.parse(s.verification); } catch {} } |
| 213 | return { |
| 214 | id: s.id, |
| 215 | title: s.name || '', |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 66 | meta.has_readme = !!s?.has_readme; |
| 67 | meta.has_docs = !!s?.has_docs || !!s?.doc_count; |
| 68 | } |
| 69 | } catch {} |
| 70 | |
| 71 | // Derive has_docs / has_readme from scan/files if scan/status doesn't provide them. |
| 72 | try { |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 131 | })), |
| 132 | }; |
| 133 | } |
| 134 | } catch {} |
| 135 | return { total: 0, samples: [] }; |
| 136 | } |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 78 | meta.has_readme = true; |
| 79 | } |
| 80 | } |
| 81 | } catch {} |
| 82 | |
| 83 | try { |
| 84 | const r = await fetch(`${base}/scan/files?category=wiki&limit=5`); |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 10 | try { return localStorage.getItem(k); } catch { return null; } |
| 11 | }; |
| 12 | const write = (k, v) => { |
| 13 | try { localStorage.setItem(k, v); } catch {} |
| 14 | }; |
| 15 | const del = (k) => { |
| 16 | try { localStorage.removeItem(k); } catch {} |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 69 | // -- Core logic (exported for testing) ------------------------------------- |
| 70 | function parseTags(raw) { |
| 71 | if (!raw) return []; |
| 72 | try { const p = JSON.parse(raw); if (Array.isArray(p)) return p.map(String); } catch {} |
| 73 | return String(raw).split(',').map(s => s.trim()).filter(Boolean); |
| 74 | } |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 41 | const filtered = candidates.filter((sig) => { |
| 42 | let sigTags = []; |
| 43 | try { sigTags = JSON.parse(sig.metadata || '{}').tags || []; } catch {} |
| 44 | const hasTagOverlap = sigTags.some((t) => memTags.has(String(t).toLowerCase())); |
| 45 | const sigWords = (sig.title || '').toLowerCase().split(/\s+/).filter((w) => w.length > 3); |
| 46 | const hasKeyword = sigWords.some((w) => memText.includes(w)); |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 176 | headers: { 'Content-Type': 'application/json' }, |
| 177 | body: JSON.stringify({ installation_id: this.installationId }), |
| 178 | }).catch(() => {}); |
| 179 | } catch {} |
| 180 | } |
| 181 | |
| 182 | shutdown() { |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 112 | } |
| 113 | await new Promise((r) => setTimeout(r, 1000)); |
| 114 | } |
| 115 | } catch {} |
| 116 | onProgress({ pct: 100 }); |
| 117 | return { files: 0, symbols: 0, wiki: 0 }; |
| 118 | } |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 840 | try { |
| 841 | const saved = localStorage.getItem('awareness_locale'); |
| 842 | if (saved && LOCALES[saved]) return saved; |
| 843 | } catch {} |
| 844 | // Detect browser language |
| 845 | const nav = (navigator.language || navigator.userLanguage || 'en').toLowerCase(); |
| 846 | if (nav.startsWith('zh')) return 'zh'; |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 1188 | // channel. Fire-and-forget — absence of embedder / closed task just |
| 1189 | // skips the cache write. |
| 1190 | if (task.status !== 'open') { |
| 1191 | try { this.db.prepare('DELETE FROM task_embeddings WHERE task_id = ?').run(task.id); } catch {} |
| 1192 | } else if (this._embedder?.embed) { |
| 1193 | const text = `${task.title || ''} ${task.description || ''}`.substring(0, 400); |
| 1194 | Promise.resolve(this._embedder.embed(text, 'passage')) |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 1026 | return d.toLocaleDateString(undefined, { month:'short', day:'numeric', year: d.getFullYear() !== now.getFullYear() ? 'numeric' : undefined }); |
| 1027 | } catch { return iso; } |
| 1028 | } |
| 1029 | function parseTags(t) { if (Array.isArray(t)) return t; if (typeof t === 'string') { try { const p = JSON.parse(t); if (Array.isArray(p)) return p; } catch {} } return []; } |
| 1030 | function catLabel(c) { return (c || 'other').replace(/_/g, ' ').replace(/\b\w/g, x => x.toUpperCase()); } |
| 1031 | function confClass(c) { return c >= 0.8 ? 'high' |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 205 | const triggerConditions = JSON.parse(skill.trigger_conditions || '[]'); |
| 206 | const sourceCardIds = JSON.parse(skill.source_card_ids || '[]'); |
| 207 | let pitfalls = []; |
| 208 | try { pitfalls = JSON.parse(skill.pitfalls || '[]'); } catch {} |
| 209 | let verification = []; |
| 210 | try { verification = JSON.parse(skill.verification || '[]'); } catch {} |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.