Back to skill

Security audit

smart-memory-manager

Security checks for vulnerabilities and agentic risk

Overview

This memory skill is useful and mostly purpose-aligned, but it gives callers unchecked filesystem read and write paths that can expose or overwrite local JSON files if the runtime has broad permissions.

Install only if you can run it with tightly scoped Deno filesystem permissions and a dedicated memory directory. Do not store secrets or regulated data in memory entries, and avoid using load/save paths outside a controlled application data location until the skill adds path validation, safer persistence defaults, and clearer warnings.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
index.ts:210
Finding
Caller-Controlled Persistence Path Enables Unauthorized Local File Reads## Vulnerability Details **File Location**: `index.ts`, lines 210–216 **Vulnerability Type**: Arbitrary local JSON file read through an unrestricted path **Risk Level**: High ```typescript case "load": { const { persistPath } = validatedParams; try { const content = await Deno.readTextFile(persistPath); memoryStore = JSON.parse(content); config.persistPath = persistPath; return { success: true, loadedCount: memoryStore.length, persistPath }; ``` ### Technical Analysis The `load` action accepts `persistPath` directly from the caller and passes it to `Deno.readTextFile` without enforcing an application-owned storage directory. There is no path canonicalization, traversal prevention, absolute-path rejection, extension restriction, or authorization check. Consequently, a caller can request any file that is readable under the Deno process's effective permissions. If that file contains compatible JSON, its data is assigned to the global `memoryStore` and can subsequently be returned through the `list`, `search`, or `summarize` actions. The parsed content is also not validated using the declared `MemoryItem` schema. `JSON.parse` results are assigned directly to `memoryStore`, permitting malformed or structurally unexpected state to enter the application. Exploitation is constrained by the runtime's Deno read permissions and by the requirement that the selected file contain parseable JSON. Broad permissions such as `--allow-read` substantially increase the affected scope. ### Attack Path 1. Identify or guess the path of a JSON file readable by the Deno process. 2. Invoke the skill with `action: "load"` and set `persistPath` to that file, including an absolute path or a traversal path outside the intended memory-storage location. 3. The skill reads and parses the selected file into the global `memoryStore`. 4. Invoke `action: "list"`, `action: "search"`, or `action: "summarize"` to retrieve data deri ...[truncated 808 chars]
Remediation
## Remediation Suggestions - Remove caller control over the full persistence path and use a fixed application-owned file where possible. - If selectable filenames are required, define a dedicated storage root and accept only a basename or opaque store identifier. - Resolve and canonicalize the requested path, then verify that it remains inside the configured storage root. - Reject absolute paths, parent-directory traversal, symbolic-link escapes, and unexpected file extensions. - Start Deno with narrowly scoped permissions such as `--allow-read=/dedicated/memory/directory` rather than unrestricted `--allow-read`. - Validate loaded records before updating global state: ```typescript const MemoryStore = z.array(MemoryItem); const storageRoot = await Deno.realPath("./memory-data"); const candidate = await Deno.realPath(`${storageRoot}/${safeFileName}`); if (!candidate.startsWith(`${storageRoot}/`)) { throw new Error("Persistence path escapes the storage directory"); } const content = await Deno.readTextFile(candidate); const loadedStore = MemoryStore.parse(JSON.parse(content)); memoryStore = loadedStore; ``` - Do not replace the existing `memoryStore` until reading, parsing, and schema validation all succeed. - Return generic errors to untrusted callers rather than exposing detailed filesystem paths or operating-system error messages.

T09 · Insecure Skill Coding Practices

Error
Location
index.ts:222
Finding
Unrestricted Save Path Allows Overwriting Arbitrary Writable Files## Vulnerability Details **File Location**: `index.ts`, lines 222–225 and 239–241 **Vulnerability Type**: Arbitrary file overwrite through an unrestricted persistence path **Risk Level**: High ```typescript case "save": { const { persistPath } = validatedParams; try { await saveMemory(persistPath); return { success: true, savedCount: memoryStore.length, persistPath }; ``` ```typescript async function saveMemory(path: string) { await Deno.writeTextFile(path, JSON.stringify(memoryStore, null, 2)); } ``` ### Technical Analysis The `save` action accepts a caller-controlled `persistPath` and forwards it to `Deno.writeTextFile`. No restriction ensures that the destination is the intended memory file or resides within an application-owned storage directory. By default, `Deno.writeTextFile` creates the destination if it does not exist and truncates an existing file before writing. A caller can therefore replace any file writable by the Deno process with serialized memory data. The attacker can influence that serialized data through prior `add`, `load`, or `clear` actions. The implementation also lacks symbolic-link protection, overwrite policy enforcement, safe file permissions, and atomic replacement. Runtime sandboxing limits the affected scope, but broad `--allow-write` permissions make unrelated application and user files reachable. ### Attack Path 1. Invoke `action: "add"` one or more times to place attacker-selected values in `memoryStore`, or invoke `action: "clear"` to produce an effectively empty serialized store. 2. Select an existing file writable by the Deno process. 3. Invoke `action: "save"` with the target file as `persistPath`. 4. `Deno.writeTextFile` truncates the target and replaces it with the JSON representation of `memoryStore`. 5. The target application or service later fails because of the corrupted file or processes the replacement content, depending on the target file's purp ...[truncated 710 chars]
Remediation
## Remediation Suggestions - Use a fixed, application-owned persistence location instead of accepting arbitrary filesystem paths. - If multiple stores are required, map validated logical identifiers to server-controlled filenames. - Canonicalize the destination and verify that it remains beneath a dedicated storage directory. - Reject absolute paths, traversal components, symbolic links, unsupported extensions, and unsafe filenames. - Run the skill with a narrowly scoped Deno permission such as `--allow-write=/dedicated/memory/directory`. - Define whether overwriting existing stores is permitted. If not, create files with an exclusive-create policy. - Defend against symbolic-link races by using filesystem primitives that do not follow links where supported, and ensure the storage directory is not writable by untrusted users. - Write to a securely created temporary file in the same protected directory, flush it, and atomically rename it to the final destination to avoid partial or corrupted writes. - Apply restrictive filesystem permissions so persisted memory is not readable or writable by unrelated users. - Avoid returning sensitive absolute paths and raw filesystem errors to untrusted callers. A hardened design should resemble: ```typescript const storageRoot = "/var/lib/smart-memory-manager"; const safeFileName = validateStoreIdentifier(storeId) + ".json"; const destination = `${storageRoot}/${safeFileName}`; await Deno.writeTextFile( destination, JSON.stringify(memoryStore, null, 2), { create: true, mode: 0o600 } ); ``` The destination must still be canonicalized and checked against the storage root, and production code should use atomic replacement and symbolic-link protections.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (7)

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README explicitly promotes saving and loading agent memory to disk, but provides no warning that those memories may contain sensitive user data, prompts, credentials, or conversation history. In a memory-management skill, persistence materially increases confidentiality risk because retained data can be exposed through insecure file paths, accidental commits, shared hosts, or later unauthorized reads.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill explicitly supports saving memory content to disk and loading it from arbitrary file paths, but the documentation does not warn that persisted memories may contain sensitive user data, secrets, or prompt material. In an agent context, this omission can lead operators to enable persistence unsafely, increasing the risk of confidential data exposure, unintended retention, or loading untrusted memory files.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The clear action can delete all or a selected class of memories immediately with no confirmation, safeguard, or scoped authorization check. In an agent memory skill, this creates a realistic integrity and availability risk because another tool invocation, prompt injection chain, or user mistake could irreversibly wipe important stored context.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The load and save actions perform direct filesystem reads and writes using a caller-controlled path without any user-visible disclosure or path restriction. In this context, that is more than a UX issue: it can let an agent read unexpected local files into memory or overwrite arbitrary writable files, creating confidentiality and integrity risks.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The entire README is presented in Chinese and does not indicate that other languages are supported or that the locale limitation is intentional and justified. The policy requires flagging language or locale constraints when they are imposed without user opt-in.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The natural-language documentation and headings are presented in Chinese, which effectively forces a specific language for users reading or configuring the skill. The file does not indicate that Chinese is optional, user-selected, or required for a region-specific purpose.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The exported skill description is written only in Chinese and presents the skill identity and behavior in that language, with no indication that users may choose another language or locale. Under the policy, forcing a specific language without opt-in can be a natural-language policy violation.

Static analysis

No suspicious patterns detected.