-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
I performed a full security audit of this repository (v10.5.2, main branch as of Feb 2026). The analysis covered all source files under src/, plugin/, scripts/, openclaw/, and configuration files. Pre-built binaries (plugin/scripts/claude-mem, 61 MB) and compiled .cjs bundles were excluded.
Overall Risk Rating: HIGH
Claude-mem captures and persists extensive data from coding sessions (tool usage, user prompts, code changes, AI-generated summaries). This data can contain confidential business logic, API keys, passwords, and proprietary source code. The fully unauthenticated HTTP API on a well-known port (37777) makes all of this accessible to any local process and to the entire network if the host is misconfigured.
Findings Overview:
| Severity | Count |
|---|---|
| 🔴 Critical / High | 4 |
| 🟡 Medium | 6 |
| 🟢 Low / Info | 7 |
🔴 Critical / High Findings
C-1: Path Traversal via MCP Tools smart_unfold and smart_outline
File: src/servers/mcp-server.ts, lines 296–298 and 337–339
Type: CWE-22 Path Traversal
The MCP tools smart_unfold and smart_outline accept a file_path parameter from the caller. The path is resolved to an absolute path via resolve(), but no validation is performed to check whether the resulting path stays within an allowed directory. The file is then read directly:
// Line 296-297 no path boundary check
const filePath = resolve(args.file_path);
const content = await readFile(filePath, 'utf-8');Risk: An attacker (or a compromised LLM context) that can control MCP tool calls can read arbitrary files on the filesystem e.g. ~/.ssh/id_rsa, ~/.claude-mem/.env (containing API keys), /etc/passwd, or any source code files.
Recommendation: Validate the resolved path against an allowed base directory:
const basePath = resolve(process.cwd());
const filePath = resolve(args.file_path);
if (!filePath.startsWith(basePath + path.sep)) {
return { content: [{ type: 'text', text: 'Access denied: path outside project' }], isError: true };
}C-2: Entire HTTP API Has No Authentication
File: src/services/worker/http/middleware.ts (entire file), src/services/server/Server.ts
Type: CWE-306 Missing Authentication for Critical Function
The worker service on port 37777 exposes 30+ HTTP endpoints, including:
| Endpoint | Exposed Data / Action |
|---|---|
GET /api/settings |
Returns all settings including API keys in cleartext |
POST /api/settings |
Allows setting any configuration value including API keys |
GET /api/observations |
Returns all stored coding observations |
GET /api/prompts |
Returns all stored user prompts |
GET /api/summaries |
Returns all session summaries |
POST /api/memory/save |
Allows injecting new "memories" into the database |
POST /api/import |
Allows data import |
DELETE /api/pending-queue/all |
Deletes the processing queue |
GET /api/logs |
Returns complete log files |
POST /api/logs/clear |
Deletes log files |
None of these endpoints require any form of authentication. Only the admin endpoints (/api/admin/restart, /api/admin/shutdown) have a localhost IP check via requireLocalhost.
Risk: Any process on the local system can:
- Exfiltrate all stored coding observations, user prompts, and session summaries
- Extract API keys for Gemini, OpenRouter, and Anthropic
- Inject false "memories" that Claude will use as context in future sessions (memory poisoning)
- Manipulate configuration (e.g. switch AI provider, change host binding to
0.0.0.0) - Delete all data
Recommendation: Implement at least one of:
- Token-based auth: Generate a random bearer token at startup, store it in a permission-restricted file, require it on all API calls
- Unix socket instead of TCP: Access is then restricted by filesystem permissions
- Extend
requireLocalhostmiddleware to ALL endpoints as an interim measure
C-3: Network Exposure When Host Is Set to 0.0.0.0
File: src/services/worker/http/routes/SettingsRoutes.ts, lines 268–274
Type: CWE-668 Exposure of Resource to Wrong Sphere
The settings validation explicitly allows 0.0.0.0 as a valid host value:
const validHostPattern = /^(127\.0\.0\.1|0\.0\.0\.0|localhost|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/;When CLAUDE_MEM_WORKER_HOST is set to 0.0.0.0, the entire unauthenticated API becomes available on all network interfaces. The CORS policy blocks browser requests from foreign origins, but direct HTTP calls (curl, scripts, other tools) are not blocked.
Risk: On any shared network (corporate, co-working, home), any participant can read all data and manipulate configuration. Especially critical in combination with C-2 (no authentication).
Recommendation:
- Remove
0.0.0.0from host validation, or at minimum require authentication when binding to non-localhost - CORS alone is not a security mechanism against non-browser clients
C-4: API Keys Exposed via GET /api/settings
File: src/services/worker/http/routes/SettingsRoutes.ts, lines 46–51
Type: CWE-200 Exposure of Sensitive Information
The GET /api/settings endpoint reads the entire settings.json and returns it unfiltered as JSON. This file contains CLAUDE_MEM_GEMINI_API_KEY, CLAUDE_MEM_OPENROUTER_API_KEY, and CLAUDE_MEM_CHROMA_API_KEY in cleartext:
private handleGetSettings = this.wrapHandler((req: Request, res: Response): void => {
const settings = SettingsDefaultsManager.loadFromFile(settingsPath);
res.json(settings); // <-- API keys returned in cleartext
});Risk: Combined with C-2 (no auth), any local process can extract API keys. These could be used to make API calls at the user's expense.
Recommendation: Mask API key fields before returning them (e.g. show only last 4 characters: sk-...abcd). Accept full keys on write, redact on read.
🟡 Medium Findings
M-1: Credential Files Written Without Restrictive Permissions
File: src/shared/EnvManager.ts, line 169
Type: CWE-732 Incorrect Permission Assignment for Critical Resource
~/.claude-mem/.env is written with writeFileSync() without restricting file permissions. Default umask on most systems is 0022, creating files with 0644 readable by all users on the system. Same applies to ~/.claude-mem/settings.json, which contains API keys.
Recommendation: Set restrictive permissions after writing:
writeFileSync(ENV_FILE_PATH, content, { mode: 0o600 });M-2: Automatic Tool Installation via curl | bash
File: scripts/smart-install.js, lines 168–173 and 215–218
Type: CWE-494 Download of Code Without Integrity Check
The smart-install script auto-installs Bun and uv by executing:
execSync('curl -fsSL https://bun.sh/install | bash', { stdio: 'inherit', shell: true });
execSync('curl -fsSL https://astral.sh/uv/install.sh | bash', { stdio: 'inherit', shell: true });No checksums or GPG signatures are verified.
Risk: Supply-chain attack if bun.sh or astral.sh are compromised (DNS hijacking, CDN compromise), arbitrary code is executed with the user's privileges.
Recommendation: Implement checksum verification, or prompt the user to install these tools manually instead.
M-3: Gemini API Key Passed as URL Parameter
File: src/services/worker/GeminiAgent.ts, line 374
Type: CWE-598 Sensitive Query Strings in GET Requests
const url = `${GEMINI_API_URL}/${model}:generateContent?key=${apiKey}`;While this is Google's standard API method, the key may appear in server logs, proxy logs, and error messages.
Recommendation: Use the x-goog-api-key HTTP header instead where supported. Ensure URLs containing keys are not logged.
M-4: JSON Body Limit of 50 MB
File: src/services/worker/http/middleware.ts, line 25
Type: CWE-400 Uncontrolled Resource Consumption
middlewares.push(express.json({ limit: '50mb' }));Risk: Memory exhaustion by sending large JSON payloads to any POST endpoint. Multiple concurrent requests can crash the worker with OOM.
Recommendation: Reduce to a realistic limit (1–5 MB) or use per-endpoint limits. The import endpoint can retain a higher limit.
M-5: Error Handler Leaks Internal Details
File: src/services/server/ErrorHandler.ts, lines 54–80
Type: CWE-209 Error Messages Containing Sensitive Information
The global error handler returns err.message and err.details directly to the client. Unhandled exceptions may contain internal paths, stack traces, or database errors.
Recommendation: Return generic error messages to clients in production. Log details internally only.
M-6: CORS Allows Requests Without Origin Header
File: src/services/worker/http/middleware.ts, lines 29–32
Type: CWE-346 Origin Validation Error
if (!origin || origin.startsWith('http://localhost:') || ...) {
callback(null, true);
}All non-browser clients send requests without an Origin header. CORS is not a security mechanism against non-browser clients this reinforces C-2.
🟢 Low / Informational Findings
| ID | Description | File |
|---|---|---|
| L-1 | No rate limiting on any API endpoint | middleware.ts |
| L-2 | ReDoS protection incomplete tag count > 100 is logged but processing continues (actual regex risk is low due to non-backtracking patterns) | src/utils/tag-stripping.ts:39–47 |
| L-3 | SQLite synchronous = NORMAL minimal data loss risk on system crash (acceptable for use case) |
src/services/sqlite/Database.ts:43 |
| L-4 | Health endpoint reveals process details PID, platform, workerPath, uptime, AI provider status | src/services/server/Server.ts:162–176 |
| L-5 | DOMPurify is a dependency but usage in server code wasn't found verify it's used consistently in the viewer UI | package.json:103 |
| L-6 | Handlebars dependency has known SSTI risks if user-controlled data is used as template strings | package.json:106 |
| L-7 | PID file race conditions in process management mitigated by cooldown mechanisms, low practical risk | ProcessManager.ts |
Recommended Fix Priority
| Priority | Finding | Effort | Impact |
|---|---|---|---|
| P0 | C-2: Add authentication to HTTP API | Medium | Eliminates the single largest risk unauthorized data access |
| P0 | C-1: Path boundary check in MCP tools | Low | Simple fix, prevents arbitrary file reading |
| P1 | C-4: Redact API keys in GET /api/settings | Low | Prevents cleartext key exfiltration |
| P1 | M-1: Set 0600 permissions on credential files | Low | One-line fix per write operation |
| P1 | C-3: Remove or restrict 0.0.0.0 host binding |
Low | Prevents accidental network exposure |
| P2 | M-5: Sanitize error responses | Low | Prevents information disclosure |
| P2 | M-4: Reduce JSON body limit | Low | Prevents memory exhaustion |
| P2 | M-2: Add integrity checks for auto-installed tools | Medium | Reduces supply-chain risk |
Scope & Methodology
- Analyzed: All TypeScript source files (
src/,plugin/hooks/,scripts/,openclaw/), configuration files (.gitignore,.mcp.json,conductor.json,package.json,tsconfig.json), Dockerfile, install scripts - Not analyzed: Pre-built binary
plugin/scripts/claude-mem(61 MB), compiled bundles (worker-service.cjs,mcp-server.cjs,context-generator.cjs), documentation translations (docs/i18n/), test files (reviewed for pattern confirmation only) - No dynamic testing was performed all findings are based on static code analysis
- No private infrastructure was accessed or assumed