T09 · Insecure Skill Coding Practices
- Location
src/ClassifiedAccessEnforcer.js:168- Finding
Partially Redacted Input May Leak Sensitive Data into Audit Logs
- Content
View full analysis
Vulnerability Details
File Location:
src/ClassifiedAccessEnforcer.js:168-173
Vulnerability Type: Plaintext sensitive-data logging
Risk Level: MediumVulnerable Code
javascript if (total > 0) { // SECURITY: log uses the already-redacted result for preview — never the original text this._log('REDACT', `Removed ${total} classified reference(s) [${context}]`, { context, count: total, redactedPreview: result.substring(0, 80), // safe — already redacted }); }Technical Analysis
The application assumes that
resultis safe to log because registered classified terms have been replaced. However, redaction only covers exact terms loaded fromclassified/classified-terms.md. Any sensitive content not present in that registry remains unchanged.When at least one registered term is detected, the first 80 characters of the partially redacted result are passed to
_log()and appended tomemory/security/classified-access-audit.jsonl. Consequently, passwords, API tokens, personal information, confidential text, or variants of registered terms may be stored in plaintext if they appear within that preview.This behavior contradicts the documentation's assertion that the audit log “never contains original sensitive text.” Rotated logs can retain the exposed content beyond the lifetime of the active audit file.
Attack Path
- An outbound payload or subagent task contains at least one exact term from the classified-term registry.
- The same payload contains another sensitive value that is absent from the registry or does not match its exact redaction pattern.
- The caller invokes
sanitizeOutbound(),redactTaskBeforeSpawn(), orredactAll(). - The registered term is replaced with
[REDACTED], while the unregistered sensitive value remains intact. - Because at least one replacement occurred,
redactAll()records the first 80 characters of the partially redacted payload. - The residual sensitive value is per ...[truncated 729 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove all payload-derived content from audit records. Log only metadata such as the action, service or context identifier, redaction count, input length, and timestamp.
- Replace the vulnerable context with a metadata-only structure:
javascript this._log('REDACT', `Removed ${total} classified reference(s) [${context}]`, { context, count: total, inputLength: text.length, note: 'payload content intentionally omitted' });- If previews are operationally required, disable them by default and require explicit administrator opt-in. Apply independent credential and secret detection rather than relying solely on the classified-term registry.
- Restrict audit directory and file permissions to the service account that owns the process.
- Define retention and secure-deletion policies for both active and rotated logs.
- Update the documentation so its confidentiality guarantees accurately describe the implemented behavior.
- Add automated tests using a payload that contains both a registered term and an unrelated secret, then assert that neither active nor rotated audit files contain the secret.
