Back to skill

Security audit

Memory Tree 记忆树架构

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent long-term memory skill, but it stores and reuses broad conversation data, including credential-like content, without enough privacy, retention, or prompt-injection controls.

Review before installing or copying this into an agent. Use it only with explicit user opt-in, redact secrets before storage, add retention and deletion controls, isolate memories by user/session/tenant, and inject retrieved memories only as clearly delimited untrusted context.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
references/mvp-implementation.py:55
Finding

Plaintext Persistence and Unconditional Admission of Sensitive Conversation Data

Content
View full analysis

Vulnerability Details

File Location: references/mvp-implementation.py, lines 55-80
Vulnerability Type: Plaintext sensitive-data storage
Risk Level: High

Complete Code Snippet:

python
          (r'api.?key|token|secret|密码', 0.05, '凭证相关'),
          (r'\d{4}-\d{2}-\d{2}', 0.05, '时间信息'),
      ]
      for pattern, pts, reason in rules:
          if re.search(pattern, text, re.I):
              score += pts
              reasons.append(reason)
      if len(text.strip()) < 20:
          score *= 0.5
          reasons.append('短文本惩罚')
      return round(score, 3), reasons

  def ingest(self, session_id, messages, source='chat'):
      """摄入消息,返回生成的 chunk IDs。"""
      c = self._conn.cursor()
      chunks = []
      for i, msg in enumerate(messages):
          content = msg.get('content', '')
          cid = f"{session_id[:12]}-{msg.get('role','u')[:3]}-{i:03d}-{self._content_hash(content)}"
          score, reasons = self._fast_score(content)
          token_count = self._token_count(content)
          c.execute('''INSERT OR IGNORE INTO memory_chunks
              (id, session_id, content, content_hash, token_count, source, role, timestamp, score, is_admitted, score_reasons)
              VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)''',
              (cid, session_id, content, self._content_hash(content), token_count,
               source, msg.get('role','user'), msg.get('timestamp', time.time()), score,
               json.dumps(reasons, ensure_ascii=False)))

Technical Analysis

The scoring logic explicitly recognizes credential-related strings such as API keys, tokens, secrets, and passwords. Despite this recognition, ingest() stores the complete raw message in the content column. The SQL statement also assigns is_admitted=1 to every message unconditionally, regardless of its score or sensitivity.

The implementation provides no secret redaction, field-level ...[truncated 1437 chars]

Remediation
View remediation

Remediation Suggestions

  1. Apply secret detection before persistence and reject or irreversibly redact recognized credentials.
  2. Replace secrets with a non-sensitive marker and retain only metadata needed for scoring.
  3. Do not admit every message automatically. Implement an admission policy based on sensitivity, provenance, message role, and score.
  4. Exclude tool output and assistant messages by default unless an explicit allowlist permits their storage.
  5. Encrypt sensitive fields or the entire database with keys managed separately from the database file.
  6. Create the database with owner-only permissions and document secure backup and deletion requirements.
  7. Add configurable retention periods, secure deletion, and per-session erasure.
  8. Require authorization for search and scope every retrieval operation to the requesting user or tenant.
  9. Add tests confirming that representative API keys, bearer tokens, passwords, and private keys are never stored or returned in plaintext.

T02 · Agent Memory Poisoning

Error
Location
SKILL.md:294
Finding

Persistent Memory Poisoning Through Verbatim Prompt Reinjection

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 294-296; references/mvp-implementation.py, lines 68-81 and 87-108
Vulnerability Type: Persistent indirect prompt injection
Risk Level: High

Complete Code and Instruction Snippets:

markdown
1. **AIAgent.__init__**:初始化 MemoryTreeBridge
2. **_build_system_prompt_parts**:注入检索到的相关记忆
3. **run_conversation**:每轮对话后调用 `bridge.ingest_turn()`
python
  def ingest(self, session_id, messages, source='chat'):
      """摄入消息,返回生成的 chunk IDs。"""
      c = self._conn.cursor()
      chunks = []
      for i, msg in enumerate(messages):
          content = msg.get('content', '')
          cid = f"{session_id[:12]}-{msg.get('role','u')[:3]}-{i:03d}-{self._content_hash(content)}"
          score, reasons = self._fast_score(content)
          token_count = self._token_count(content)
          c.execute('''INSERT OR IGNORE INTO memory_chunks
              (id, session_id, content, content_hash, token_count, source, role, timestamp, score, is_admitted, score_reasons)
              VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)''',
              (cid, session_id, content, self._content_hash(content), token_count,
               source, msg.get('role','user'), msg.get('timestamp', time.time()), score,
               json.dumps(reasons, ensure_ascii=False)))
          chunks.append({'id': cid, 'score': score, 'reasons': reasons})
      self._conn.commit()
      return chunks
python
  def search(self, query, limit=10, min_score=0.1):
      """搜索记忆(中文 LIKE / 英文 FTS5 MATCH)。"""
      c = self._conn.cursor()
      has_cjk = bool(re.search(r'[\u4e00-\u9fff]', query))
      if has_cjk:
          sql = '''SELECT id, session_id, content, score, is_admitted, score_reasons
              FROM memory_chunks WHERE content LIKE ? AND is_admitted >= 1 AND score >= ?
              ORDER BY score DESC LIMIT ?'''
          params = [f'%{
...[truncated 3311 chars]
Remediation
View remediation

Remediation Suggestions

  1. Treat all retrieved memories as untrusted data, never as system-level or developer-level instructions.
  2. Do not concatenate memory directly into privileged prompt sections. Place it in a clearly delimited, structured data block with an explicit instruction that its contents must not be followed as commands.
  3. Store normalized facts in a constrained schema instead of arbitrary message text.
  4. Reject or quarantine instruction-like memories, including requests to override policy, reveal hidden context, invoke tools, or alter future behavior.
  5. Preserve provenance, author identity, source role, trust level, and tenant ownership for every memory.
  6. Enforce user, session, and tenant authorization during both ingestion and retrieval.
  7. Avoid automatically admitting assistant and tool messages, which may contain untrusted material copied from external sources.
  8. Require confirmation or trusted summarization before promoting user-controlled content into persistent memory.
  9. Ensure summaries cannot convert untrusted instructions into apparently trusted statements.
  10. Add adversarial tests covering cross-session prompt injection, retrieval-trigger manipulation, poisoned summaries, and cross-user memory leakage.
  11. Restrict tool execution independently of model output through capability checks, argument validation, and approval gates.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (11)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill is explicitly designed to ingest, score, persist, and reuse user conversations and documents as long-term memory, but it does not include consent, privacy notice, retention limits, or guidance for handling sensitive data. In an agent context, persistent collection without transparent user warning creates a real privacy and compliance risk, especially because the stored content may later be surfaced back into prompts or operator-visible storage.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This section instructs the system to persistently store broad categories of user-provided content and even treats credential-related material such as API keys as memory-worthy. That creates a direct path for collecting secrets and sensitive business or personal information into durable storage, increasing the blast radius of compromise, misuse, or accidental disclosure.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The scoring rules positively reward retention of financial details, preferences, important markers, and credential-related content, which systematically biases the memory system toward preserving sensitive information. Because the skill also supports later retrieval and prompt injection of stored memories, these scoring rules materially increase the chance that private data is retained and resurfaced inappropriately.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The integration design says retrieved memories should be injected into prompt construction, which creates a plain-language exfiltration channel from stored memory to model context and downstream outputs. If sensitive items were previously stored, prompt injection, overbroad retrieval, or simple user queries could cause unintended disclosure of secrets, personal data, or confidential project information.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring and class docstring describe the MVP as providing ingestion plus full-text retrieval, and the search() method uses the FTS5 table for non-CJK queries. However, ingest() only inserts into memory_chunks and never inserts into or synchronizes memory_chunks_fts, so the advertised English full-text search behavior is not actually implemented.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code persists full message content, including text matching credentials such as API keys, tokens, secrets, and passwords, into a local SQLite database by default. In a long-term memory skill, this increases the chance of sensitive data retention, later disclosure through search, local compromise, backups, or accidental reuse in prompts, especially because no consent, minimization, masking, or retention controls are enforced.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The docstring at search() explicitly states that Chinese uses LIKE and English uses FTS5 MATCH. But the only data insertion path writes solely to memory_chunks, leaving memory_chunks_fts empty unless some external synchronization exists, so the documented English-search behavior contradicts the actual implementation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The module docstrings, comments, user-visible messages, and search behavior descriptions are all written exclusively in Chinese, with no indication that the language is configurable or intentionally limited to a Chinese-only context. This can violate language/locale policy when a skill implicitly forces one language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file contains user-facing natural-language guidance exclusively in Chinese, and there is no indication that the skill is region-specific or that users may opt into another language. Under the policy rule for language or locale constraints, forcing a single language without opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

All user-facing instructional text in this file is Chinese, and there is no indication that the skill or documentation offers language selection or is intentionally limited to a Chinese-speaking audience. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown quickstart shows initialization with db_path='memory.db' and ingestion of message content including budget information, but it does not warn that conversational data will be written to local persistent storage. Because this behavior can affect user data and privacy, the markdown description should disclose it clearly.

Content

No source excerpt is available for this finding.