T02 · Agent Memory Poisoning
- Location
src/renderer.ts:6- Finding
Persistent Prompt Injection Through Untrusted Edict Content
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill's idea is legitimate, but the reviewed artifact does not match the plugin users are told to install and it can persist content into agent prompt context.
Review before installing. Use only a pinned, matching plugin artifact with provenance or a complete OpenClaw plugin source review. Keep agent write tools disabled unless the writers are trusted, prefer read-only tool whitelists and autoSave false, review imported edict files before use, and update flagged dependencies.
src/renderer.ts:6Persistent Prompt Injection Through Untrusted Edict Content
SKILL.md:2Audited Artifact Does Not Match the Plugin Installed by the Documented Command
\n${usage()}`);
const merge = hasFlag(args, '--merge') || !hasFlag(args, '--replace');
const imported = await loadImportFile(file);
let data = imported;
if (merge) {
const current = store.exportData();
const historyById = new Map([...current.history, ...(imported.history ?? [])].map((entry) => [entry.id, entry]));
const edictById = new Map([...current.edicts, ...(imported.edicts ?? [])].map((edict) => [edict.id, edict]));
data = {
version: imported.version ?? current.version,
...[truncated 2752 chars]:501Imported Stores Bypass Per-Edict and Capacity Validation
The description emphasizes a grounding layer for AI agents that exposes verified facts and read/search tools, with write tools only as an opt-in concept. The supplied code chunk is specifically a CLI application for local filesystem-based edict management. It implements numerous write and administrative commands directly: add, update, remove, import, export with file output, and init. It also searches the filesystem upward for edicts.yaml/yml/json and creates files on disk. Those are material capabilities not conveyed by the declared description, and the code’s primary role is a local CLI datastore manager rather than prompt-time fact injection for AI agents. While read/search functionality is present, the undeclared write/destructive capabilities and differing primary interface/purpose make this a clear mismatch.
The declared description describes a broad agent grounding and edict-management capability, but the supplied code only implements a duration parser. It validates and converts duration values; it does not provide verified facts, expose management tools, interact with prompts, or access any resources. This is a materially different primary purpose, so it is a clear mismatch.
The declared description suggests a factual knowledge/edict-management layer with tool exposure for retrieval and possibly writing. The supplied code does none of that. It is a small text-normalization utility for categories/tags, handling lowercase conversion, whitespace trimming, simple plural-to-singular rules, and deduplication. This is a materially different primary purpose, so the description does not accurately represent the code.
The code does support read/search functionality for edict management, but it also clearly provides extensive write and mutation capabilities by default: adding, updating, deleting, importing, compacting, superseding, pruning expired items, and saving to disk. In fact, autosave defaults to true, so writes are not merely optional in the implementation once mutation methods are used. The description says write tools are opt-in and declares no permissions, which understates the actual capabilities and resource access. The primary purpose is not just exposing verified facts/read-search tools; it is a full CRUD-style persistent storage layer for edicts.
The declared description emphasizes a ground-truth layer that injects verified facts into prompts and exposes read/search tools, with writes only as optional opt-in functionality. This code chunk instead defines the schema for a full CRUD-style edict store with persistence, history, import/export-related structures, mutation outcomes, auto-save behavior, and expiry/capacity management. While these features are related to edict management, the primary behavior visible here is a storage and mutation model rather than prompt grounding or fact verification. The presence of write-oriented types and persistence options is a meaningful undeclared capability relative to the empty declared permissions and read/search-focused description.
The declared description promises a runtime skill for factual grounding and tool exposure, but the provided code chunk contains only build tooling configuration for bundling a TypeScript project. It does not implement any agent-facing logic, data access, search, edict management, or write controls. This is a materially different primary purpose, so it should be flagged as a mismatch.
The declared description describes an AI-agent support layer with factual verification and management tools. The supplied code only configures the Vitest test runner to discover test files in a specific directory pattern. It does not implement any agent-facing tools, data access, fact verification, or edict management capabilities. This is a materially different primary purpose, so it is a clear mismatch.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
The README instructs users to run npx edicts without pinning a version. npx resolves and executes the latest published package, so users may unknowingly run a newly published or compromised release, creating a supply-chain execution risk on their local machine or CI environment.
The README again recommends npx edicts without a pinned version. Because this package is positioned for agent/runtime integration, encouraging unpinned on-demand execution increases the chance of users or automation fetching and executing an unexpected package version if the registry package changes or is hijacked.
The skill markets itself as read-only by default, yet the main tool table prominently presents destructive mutation tools (add, update, remove) as standard capabilities. In an agent ecosystem, this ambiguity can cause operators to enable or trust the plugin without fully appreciating that it can alter persistent context, increasing the risk of prompt-context poisoning or accidental policy/data modification.
The statement 'Only content you write to that file appears in prompts' conflicts with the earlier claim that agents can create or modify edicts via enabled write tools. That inconsistency matters because this plugin injects stored content into system context; if agents can write to the store, they may indirectly influence future prompts, enabling persistence of unsafe instructions, false facts, or policy tampering.
The manifest frames the skill primarily as a ground-truth layer that provides verified facts and exposes read/search tools, noting write tools are opt-in. This CLI prominently exposes add, remove, update, init, export-to-file, and import commands, including destructive replacement behavior, which goes materially beyond a read/search-focused interface.
The manifest emphasizes a ground-truth layer that provides verified facts and exposes read/search tools, while noting write tools are opt-in. This file implements full mutation capabilities as first-class store methods, including add, update, remove, compact, import, and save, making persistent modification a substantial part of the code behavior rather than a merely incidental read/search layer.
The get() method appears read-only but mutates persistent state by updating lastAccessed, marking the store dirty, and potentially auto-saving. In an agent or plugin context, a caller using a nominally safe read/search tool can therefore trigger unintended writes, changing audit state and potentially causing side effects on disk without explicit user intent.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
yaml 2.8.2 is a direct runtime dependency of the package, not merely a dev tool. If the skill parses attacker-controlled YAML, deeply nested collections could trigger stack exhaustion and deny service, which is more relevant here because the skill advertises read/search functionality and may ingest external edict content.
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"node": ">=20"
},
"dependencies": {
"yaml": "^2.8.2"
},
"devDependencies": {
"@types/node": "^25.5.0",
The package declares yaml 2.8.2, which is reported as vulnerable to stack overflow from deeply nested YAML collections. Because this skill advertises YAML-backed edict management and likely processes YAML content as part of its core function, maliciously crafted input could trigger denial of service through parser exhaustion or crash behavior, making the context more relevant than for a package that never parses untrusted YAML.
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"yaml": "^2.8.2"
},
"devDependencies": {
"@types/node": "^25.5.0",
"tsup": "^8.5.1",
"typescript": "^5.9.3",
"vitest": "^4.1.0"
Detected: suspicious.prompt_injection_instructions