Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions hooks/scripts/store-memories.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ try {
return text && text.trim().length > 0;
}

function redactSensitiveUrls(text) {
if (!text) return text;

return text.replace(/\bhttps?:\/\/(localhost|127\.0\.0\.1|\[::1\])(?::\d+)?(?:\/[^\s"'`]*)?/gi, '[LOCAL_URL_REDACTED]');
}

/**
* Extract the last turn's user input and assistant response
*
Expand Down Expand Up @@ -192,8 +198,8 @@ try {

// Extract the last turn's content
const lastTurn = extractLastTurn(lines);
const lastUser = lastTurn.user;
const lastAssistant = lastTurn.assistant;
const lastUser = redactSensitiveUrls(lastTurn.user);
const lastAssistant = redactSensitiveUrls(lastTurn.assistant);

debug('extracted:', {
userLength: lastUser?.length || 0,
Expand Down
65 changes: 65 additions & 0 deletions scripts/test-redact-sensitive-urls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env node

import { mkdtempSync, writeFileSync, readFileSync, rmSync, existsSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { spawnSync } from 'child_process';

const pluginRoot = '/Users/deepzen/projects/evermem-claude-code';
const storeScript = join(pluginRoot, 'hooks/scripts/store-memories.js');
const tempDir = mkdtempSync(join(tmpdir(), 'evermem-redact-'));
const transcriptPath = join(tempDir, 'transcript.jsonl');
const debugLogPath = '/tmp/evermem-debug.log';

const transcript = [
JSON.stringify({
type: 'user',
message: {
content: '<command-message>evermem:hub</command-message>\n<command-name>/evermem:hub</command-name>\nOpen http://localhost:3456/?key=${EVERMEM_API_KEY}'
}
}),
JSON.stringify({
type: 'assistant',
message: {
content: [
{ type: 'text', text: 'Memory Hub 服务已启动。\n\nhttp://localhost:3456/?key=fake-secret-key' }
]
}
})
].join('\n');

writeFileSync(transcriptPath, transcript + '\n', 'utf8');
writeFileSync(debugLogPath, '', 'utf8');

const result = spawnSync('node', [storeScript], {
input: JSON.stringify({ transcript_path: transcriptPath, cwd: '/Users/deepzen' }),
encoding: 'utf8',
env: {
...process.env,
EVERMEM_DEBUG: '1',
EVERMEM_API_KEY: process.env.EVERMEM_API_KEY || ''
}
});

const stdout = result.stdout || '';
const debugLog = existsSync(debugLogPath) ? readFileSync(debugLogPath, 'utf8') : '';

try {
if (stdout.includes('FAILED (403)')) {
console.error('Expected sensitive URL content to be redacted before save, but save still failed with 403.');
if (debugLog) console.error(debugLog);
process.exit(1);
}

const leakedLocalUrlPattern = /https?:\/\/(localhost|127\.0\.0\.1|\[::1\])/i;
if (leakedLocalUrlPattern.test(debugLog)) {
console.error('Expected debug log to avoid leaking raw localhost URLs.');
console.error(debugLog);
process.exit(1);
}

console.log('Sensitive URL content was redacted before save.');
process.exit(0);
} finally {
rmSync(tempDir, { recursive: true, force: true });
}