Back to skill

Security audit

Aegis Shield

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-built for memory safety, but its reviewed artifacts can still write lightly sanitized untrusted text into persistent agent memory and execute an unpinned local module outside the package.

Review this skill carefully before installing. It should only be used in an environment where the external aegis-shield library path is trusted and locked down, and where memory writes require explicit user approval. Do not rely on it as a strong sanitizer for untrusted web, email, or social content until it validates all fields strictly and bundles or verifies its scanner dependency.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T02 · Agent Memory Poisoning

Error
Location
openclaw-safe-memory-append.js:60
Finding
Insufficient sanitization permits persistent Agent memory poisoning<![CDATA[ ## Vulnerability Details **File Location**: `openclaw-safe-memory-append.js:60-66`, `openclaw-safe-memory-append.js:114-116`, and `openclaw-safe-memory-append.js:141-148` **Vulnerability Type**: `T02: Agent Memory Poisoning` **Risk Level**: High ### Vulnerable Code ```js function sanitizeToDeclarative(text) { // v0.1: conservative. Strip excess whitespace; do not attempt heavy rewriting. // Keep as a single paragraph summary marker. const t = text.replace(/\r\n/g, '\n').trim(); // Collapse very long blocks a bit. return t.length > 800 ? (t.slice(0, 800) + '…') : t; } ``` ```js const sanitized = sanitizeToDeclarative(text); const tagStr = tags.length ? ` [${tags.join(', ')}]` : ''; const entry = `- [${nowUtcISO()}]${tagStr} ${sanitized}\n Source: ${source}\n`; ``` ```js let outPath; if (target === 'longterm') { outPath = path.join(wsRoot, 'MEMORY.md'); } else { outPath = path.join(memDir, `${day}.md`); } fs.appendFileSync(outPath, entry, 'utf8'); ``` ### Technical Analysis The function named `sanitizeToDeclarative()` does not transform untrusted input into a safe declarative representation. It only normalizes line endings, removes leading and trailing whitespace, and truncates content after 800 characters. Consequently, accepted input retains embedded instructions, Markdown structures, role-like text, multiline directives, and other prompt-injection syntax. The preceding lint logic is a limited keyword blacklist, so semantically equivalent instructions can avoid its specific regular expressions. The behavior of the separately loaded scanner cannot be established from the audited project. If the scanner and lint checks accept a crafted input, the substantially unchanged content is appended to either a daily memory file or the long-term `MEMORY.md` file. These are persistent Agent state locations and may later be loaded into an Agent context. ### Attack Path 1. An attacker places disguised instructions in web, email, social, or ...[truncated 1105 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not place raw untrusted text into memory files that are subsequently loaded as Agent context. - Store untrusted material in a structured quarantine record outside prompt-loaded memory, including provenance, trust status, and a content hash. - Generate memory entries from a strict schema containing only explicitly permitted declarative fields. - Reject or escape newlines, Markdown control structures, role markers, and instruction-like syntax before promotion. - Replace keyword blacklisting with allowlist-oriented validation and contextual prompt-injection detection. - Require explicit trusted approval before promoting external content into long-term memory. - Treat scanner failure, unavailable scanner results, unknown severity, and malformed scanner output as quarantine conditions. - Add adversarial tests covering obfuscation, Unicode substitutions, multiline injection, Markdown injection, and paraphrased directives. ]]>

T02 · Agent Memory Poisoning

Warning
Location
openclaw-safe-memory-append.js:74
Finding
Unvalidated source and tag metadata permits memory-entry injection<![CDATA[ ## Vulnerability Details **File Location**: `openclaw-safe-memory-append.js:74-77` and `openclaw-safe-memory-append.js:114-116` **Vulnerability Type**: `T02: Agent Memory Poisoning` **Risk Level**: Medium ### Vulnerable Code ```js const textArg = getArg('text'); const source = getArg('source'); const target = getArg('target') || 'daily'; // daily|longterm const tags = (getArg('tags') || '').split(',').map(s => s.trim()).filter(Boolean); ``` ```js const sanitized = sanitizeToDeclarative(text); const tagStr = tags.length ? ` [${tags.join(', ')}]` : ''; const entry = `- [${nowUtcISO()}]${tagStr} ${sanitized}\n Source: ${source}\n`; ``` ### Technical Analysis The `source` and `tags` command-line values are interpolated directly into the persistent memory entry. These metadata fields are not passed through the scanner or lint function and have no restrictions on length, newlines, control characters, Markdown syntax, or permitted tag characters. A malicious caller can therefore provide benign `text` while placing the actual payload in `--source` or `--tags`. Embedded newline characters can terminate the expected metadata line and create additional Markdown entries or instruction-like blocks. This bypasses the controls applied to the primary text field. ### Attack Path 1. An attacker or untrusted integration controls arguments supplied to the script. 2. The attacker supplies benign text that passes scanning and linting. 3. The attacker places multiline Markdown or instruction text in the `--source` or `--tags` argument. 4. The script does not scan, lint, escape, or reject the malicious metadata. 5. Template interpolation writes the injected lines into a daily or long-term memory file. 6. A later Agent session reads the injected entry as part of persistent memory. ### Impact Assessment Exploitation permits arbitrary textual content to be inserted into Agent memory through metadata fields, subject to the caller's ability to invoke the script or infl ...[truncated 303 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate `source` against a strict schema, such as an enumerated source type followed by a syntactically valid URI. - Reject all newline, carriage-return, NUL, and other control characters in metadata. - Enforce conservative maximum lengths for sources and tags. - Restrict each tag to an allowlisted expression such as `[A-Za-z0-9_-]+`. - Apply security scanning to every field that can reach persistent memory, not only `text`. - Serialize records as structured data rather than interpolating untrusted fields into Markdown. - If Markdown output is required, escape all metacharacters and construct each field as a single validated line. - Add tests proving that metadata cannot create additional entries, headings, code blocks, or role-like instructions. ]]>

T08 · Insecure Dependencies

Warning
Location
openclaw-safe-memory-append.js:88
Finding
Unpinned external workspace module is executed outside the audited package boundary<![CDATA[ ## Vulnerability Details **File Location**: `openclaw-safe-memory-append.js:88-93` **Vulnerability Type**: `T08: Insecure Dependencies` **Risk Level**: Medium ### Vulnerable Code ```js // Load scanner (local) let scan; try { ({ scan } = require('/home/openclaw/.openclaw/workspace/aegis-shield/dist/index.js')); } catch (e) { die('Failed to load aegis-shield local library. Is /home/openclaw/.openclaw/workspace/aegis-shield built?', 3); } ``` ### Technical Analysis The script loads a JavaScript module from a hard-coded absolute path outside the submitted project. Node.js `require()` executes the module's top-level code immediately. The dependency is not bundled, version-pinned, covered by a lockfile in this project, or verified using an integrity hash. The external file was not present in the audited artifact, so its implementation and safety cannot be confirmed. If another process or user can replace or modify that module, invoking this otherwise legitimate Skill will execute the substituted code. This is also inconsistent with the documentation's description of a bundled, local-only resource: the scanner is local in network terms, but it is not contained within the reviewed package. ### Attack Path 1. An attacker obtains write access to `/home/openclaw/.openclaw/workspace/aegis-shield/dist/index.js` or one of its relevant parent paths. 2. The attacker replaces the module or injects malicious top-level JavaScript into it. 3. A user invokes `openclaw-safe-memory-append.js`. 4. The hard-coded `require()` loads and executes the modified module before calling `scan()`. 5. The malicious module runs with the same filesystem, environment, and process privileges as the Node.js script. ### Impact Assessment Successful exploitation yields arbitrary JavaScript execution with the privileges of the user running the Skill. The resulting scope can include reading or modifying files accessible to that user, tampering with Agent memory, accessing inherited ...[truncated 354 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Bundle the scanner implementation inside the reviewed Skill package. - Resolve the dependency relative to the script directory rather than from a mutable absolute workspace path. - If distributed as a package, pin its exact version and commit the associated lockfile and integrity metadata. - Verify the scanner artifact against an expected cryptographic hash before loading it. - Ensure the scanner and parent directories are not writable by less-trusted users or processes. - Run the Skill with only the filesystem and environment permissions needed to read input and append to designated memory locations. - Include the scanner source and dependency manifest in future security reviews. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill invokes a shell command (`node scripts/openclaw-safe-memory-append.js ...`) but does not declare an explicit tool scope such as `permissions` or `allowed-tools`. That omission weakens least-privilege controls and can let the runtime or calling agent use shell access without a clear, reviewable declaration, which is especially relevant in a security-focused skill that processes untrusted text and may be used in sensitive workflows like memory writes.

Static analysis

No suspicious patterns detected.