T09 · Insecure Skill Coding Practices
- Location
src/storage/integrity.ts:123- Finding
Predictable Default HMAC Secret Undermines Memory Integrity Verification
- Content
View full analysis
Vulnerability Details
File Location:
src/storage/integrity.ts:123-130
Vulnerability Type: Hard-coded cryptographic secret
Risk Level: MediumVulnerable Code
ts export class IntegrityStore { private db: Database.Database; private secretKey: string; constructor(db: Database.Database, secretKey?: string) { this.db = db; this.secretKey = secretKey || process.env.MUNINN_INTEGRITY_SECRET || 'default-secret-change-in-production'; this.initializeTables(); }Technical Analysis
The integrity subsystem silently falls back to the public, predictable string
default-secret-change-in-productionwhen neither a constructor argument norMUNINN_INTEGRITY_SECRETis supplied. The same secret is later used to produce HMAC signatures for stored memories.An HMAC only establishes authenticity while its key remains secret. Because the fallback is embedded in distributed source code, any attacker who can modify the SQLite database can calculate valid signatures for forged memory content. The integrity check may consequently treat attacker-modified records as authentic.
This is especially relevant because stored memories are later used for semantic retrieval and can influence agent responses and decisions. The issue does not independently grant database access; exploitation requires an existing ability to modify the database or its records.
Attack Path
- A deployment starts without setting
MUNINN_INTEGRITY_SECRETand without passing a secret toIntegrityStore. - The application uses the published default value as its HMAC key.
- An attacker obtains write access to the SQLite database through another local compromise, exposed database file, insecure backup, or excessive filesystem permissions.
- The attacker changes the content or entities of a stored memory.
- Using the known default key and the documented hashing logic, the attacker recomputes the correspond ...[truncated 856 chars]
- A deployment starts without setting
- Remediation
View remediation
Remediation Suggestions
-
Remove the hard-coded fallback and fail securely when no secret is configured:
ts const configuredSecret = secretKey || process.env.MUNINN_INTEGRITY_SECRET; if (!configuredSecret) { throw new Error('MUNINN_INTEGRITY_SECRET must be configured'); } this.secretKey = configuredSecret; -
Require a cryptographically random key with at least 256 bits of entropy. Provide a documented generation command, such as:
bash openssl rand -base64 32 -
Store the key in an operating-system secret store, container secret, or managed key service rather than in source code, logs, command-line arguments, or the memory database.
-
Validate minimum key strength during initialization and reject placeholder or commonly known values.
-
Restrict database and backup permissions to the service account that requires access.
-
Implement key rotation with explicit key identifiers and controlled re-signing of existing records. Rotating the key without a migration strategy would otherwise make legitimate historical records unverifiable.
-
Add automated tests confirming that production initialization fails when the secret is missing or set to the former default value.
-
