T02 · Agent Memory Poisoning
Warning
- Location
- dingtalk-command.py:72
- Finding
- Unauthenticated Persistent Mutation of Bot-Name Configuration<![CDATA[ ## Vulnerability Details **File Location**: `dingtalk-command.py:72-101` and `dingtalk-command.py:128-130` **Vulnerability Type**: Untrusted persistent state mutation **Risk Level**: Medium ### Vulnerable Code ```python def save_bot_name(new_name: str) -> bool: config_file = Path(__file__).parent / "config.json" if not config_file.exists(): return False try: with open(config_file, 'r', encoding='utf-8') as f: config = json.load(f) bot_names = config.get('bot_names', []) if new_name in bot_names: return False bot_names.append(new_name) config['bot_names'] = bot_names with open(config_file, 'w', encoding='utf-8') as f: json.dump(config, f, indent=2, ensure_ascii=False) print(f"✅ Automatically saved new name: {new_name}") return True except Exception as e: print(f"❌ Failed to save name: {e}") return False ``` The persistence operation is invoked automatically while parsing messages: ```python extracted_name = extract_bot_name(message) if extracted_name and auto_save: save_bot_name(extracted_name) ``` ### Technical Analysis The command parser extracts an arbitrary mention from each incoming message and persists it into the skill's `config.json` file. The operation does not verify that the sender is an administrator, that the mentioned name belongs to the deployed bot, or that configuration learning has been explicitly approved. The value is only constrained by the mention extraction expression: ```python match = re.search(r'@([^\s,,]+)', message) ``` Consequently, an untrusted sender can supply a large number of unique names. Each value is appended to `bot_names`, written to persistent storage, and later incorporated into the regular expression used to remove bot mentions from future messages. Although names are escaped before being incorporated into that expression, preventing direct regular-e ...[truncated 1876 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Disable automatic bot-name persistence by default. 2. Maintain an explicit administrator-controlled allowlist instead of learning names from arbitrary messages. 3. Require authenticated administrative authorization before modifying persistent configuration. 4. Validate names using a restrictive character policy and reject control characters or unexpected punctuation. 5. Enforce strict limits on: - Individual name length. - Total number of names. - Configuration file size. - Update frequency per user or conversation. 6. Store runtime observations separately from trusted routing configuration. 7. Use an atomic write process: - Write validated JSON to a securely created temporary file in the same directory. - Flush and synchronize the file. - Atomically replace the original configuration. 8. Apply file locking or another concurrency-control mechanism during read-modify-write operations. 9. Record the authenticated actor and reason for every approved configuration change. 10. Provide a review and rollback mechanism for learned state. ]]>
