T09 · Insecure Skill Coding Practices
- Location
references/compaction-rpc.ts:76- Finding
Compaction Summaries Persisted in Plaintext Without Explicit Restrictive File Permissions
- Content
View full analysis
{ const configPath = getConfigPath(agentDir); await fs.mkdir(path.dirname(configPath), { recursive: true }); await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8"); } /** * Called by the compaction engine to record a result. * Exported for use by the sessions.compact RPC and auto-compaction trigger. */ export async function recordCompactionResult( result: CompactionLastResult, agentDir?: string, ): Promise { const config = await loadCompactionConfig(agentDir); if (config.settings.storeLastResult) { config.lastResult = result; } else { // Still store metadata, just not the summary config.lastResult = { ...result, summary: undefined }; } await saveCompactionConfig(config, agentDir); } ``` ### Technical Analysis When result storage is enabled, `result.summary` can contain a condensed representation of the user's conversation, including confidential prompts, personal information, source code, operational details, or credentials accidentally included in chat history. The summary is serialized directly into `{agentDir}/compaction-config.json` as plaintext. The `fs.writeFile` call does not specify a restrictive mode such as `0o600`, so permissions are determined by the process umask and any permissions already present on the file. In a permissively configured or multi-user environment, the resulting file may be readable by unintended local users or processes. The write is also performed directly against the destination rather than through an atomic temporary-file replacement. An interruption could leave a partially written configuration file, ...[truncated 1721 chars]- Remediation
View remediation
