affaan-m/ECC · critical · Error
Refusing to save memory containing a suspected secret
Error message
Refusing to save memory containing a suspected secret (${secretKinds.join(', ')}). What it means
saveMemory serializes the memory payload to JSON and runs a secret scanner (findPotentialSecrets) before writing. If the payload matches patterns for API keys, tokens, passwords, or similar, the save is refused outright — a fail-closed guard so secrets never land in memory files that might be synced or committed.
Solutions
- Remove the secret from the memory content; store a reference/pointer instead of the credential.
- Redact the sensitive value (e.g. 'sk-***') before saving.
- Store the secret in a proper secret manager and save only its identifier in the memory.
- If it is a false positive, rephrase the content so it no longer matches the secret patterns.
Example fix
// before
saveMemory({ id: 'deploy-note', content: 'use API_KEY=sk-live-abc123' });
// after
saveMemory({ id: 'deploy-note', content: 'use API_KEY from secret manager (entry: deploy/api-key)' }); Defensive patterns
Strategy: validation
Validate before calling
const SECRET_PATTERNS = [/sk-[A-Za-z0-9]{20,}/, /AKIA[0-9A-Z]{16}/, /-----BEGIN [A-Z ]*PRIVATE KEY-----/, /Bearer\s+[A-Za-z0-9._\-]{20,}/, /(?:password|passwd|secret|token)\s*[=:]\s*\S+/i];
const found = SECRET_PATTERNS.filter(re => re.test(JSON.stringify(memory)));
if (found.length) throw new Error('Memory content contains a suspected secret; redact before saving.'); Try / catch
try {
saveMemory(memory);
} catch (err) {
if (err.message.startsWith('Refusing to save memory containing a suspected secret')) {
// redact the matched content and retry
} else throw err;
} Prevention
- Never paste credentials, tokens, or .env contents into memory payloads.
- Use secret references (vault entry names) instead of values.
- Run your own secret scan on content before saving in pipelines.
- If rotation is possible, rotate anything that was attempted to be saved.
When it happens
Trigger: Calling saveMemory (directly or via runWriteCommand/saveWithId) with any field whose stringified content matches a secret heuristic: e.g. a value like 'sk-...', 'Bearer <token>', 'password=...', PEM keys, AWS keys.
Common situations: Saving a memory that quotes an .env snippet or API key for later reference; a code snippet embedded in the memory contains a hardcoded credential; CI tokens accidentally pasted into notes.
Related errors
- must not contain control or bidirectional formatting…
- memory body must not contain unsafe control or…
- artifact path escapes output directory
- artifact permits provider execution
- capsule.secret_canary
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/76d1d93fd780ccdd.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/memory-vault.js:324
scope: input.scope || 'project',
trust: 'unreviewed',
status: 'active',
sourceHarness: input.sourceHarness || 'unknown',
targetHarnesses: input.targetHarnesses || ['all'],
tags: input.tags || [],
links: input.links || [],
createdAt: now,
updatedAt: now,
body: input.body || '',
});
}
function saveMemory(input, options = {}) {
const roots = options.roots || resolveVaultRoots(options);
const memory = normalizeSaveInput(input || {}, options);
const secretKinds = findPotentialSecrets(JSON.stringify(memory));
if (secretKinds.length > 0) {
throw new Error(`Refusing to save memory containing a suspected secret (${secretKinds.join(', ')}).`);
}
const root = assertMemoryRootSafe(roots, memory.scope);
fs.mkdirSync(root, { recursive: true, mode: 0o700 });
ensureProjectScopeIgnored(roots, memory.scope);
const directory = path.join(root, `${memory.kind}s`);
assertMemoryDirectorySafe(directory, root);
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
const destination = path.join(directory, `${memory.id}.md`);
try {
writeCreateOnlyTextFile(destination, serializeMemoryDocument(memory), root);
} catch (error) {
if (error && error.code === 'EEXIST') {
throw new Error(`Memory ${memory.id} already exists; writes are create-only.`);
}
throw error;
}View on GitHub (pinned to 8321021c54)