T02 · Agent Memory Poisoning
- Location
scripts/sync-active-projects.py:67- Finding
Stored Prompt Injection Through Telegram Group Display Names
- Content
View full analysis
Vulnerability Details
File Location:
scripts/sync-active-projects.py:67-75, 199-209, 221-222
Vulnerability Type: Persistent prompt injection through untrusted metadata
Risk Level: HighVulnerable Code
python display_name = info.get("displayName", chat_id) # Clean display name: "telegram:g-faya-golem_content" → "FAYA-GOLEM_content" clean_name = display_name.replace("telegram:g-", "").replace("telegram:", "") activity[chat_id] = { "last_active": datetime.fromtimestamp(updated_at / 1000).strftime("%Y-%m-%d"), "session_id": info.get("sessionId", ""), "display_name": clean_name, }python else: name = get_project_name(chat_id) if name == chat_id: # Use display name from session if no project.md name = info.get("display_name", chat_id) size = "0" tier = "-" # Check for actual project knowledge if os.path.exists(os.path.join(PROJECTS_DIR, chat_id)): size, tier = get_knowledge_size(chat_id) active_projects.append({ "chat_id": chat_id, "name": name, "size": size, "tier": tier, "last_active": info["last_active"], })python Path(SOUL_MD).write_text(new_content, encoding="utf-8")The selected project name is subsequently interpolated into the active-project Markdown table:
python for p in active_projects: new_section_lines.append( f"| {p['chat_id']} | {p['name']} | {p['size']} | {p['tier']} | {p['last_active']} |" )Technical Analysis
The script reads
displayNamefrom Telegram session metadata and performs only two literal prefix removals. It does not reject or escape newline characters, Markdown headings, table delimiters, control characters, or instruction-like text.For an active group without a project name, this value becomes
p['name']and is embedded directly inSOUL.md. The target file is not merely a display report: it is an ...[truncated 1866 chars]- Remediation
View remediation
Remediation Suggestions
- Do not write Telegram-controlled metadata into
SOUL.mdor any other instruction-bearing file. - Store project state in a structured data file such as JSON, with a schema that distinguishes trusted instructions from untrusted display metadata.
- Render display names only in user-interface contexts where they are treated as quoted data.
- If Markdown generation remains necessary:
- Remove carriage returns, newlines, and control characters.
- Escape pipes, backticks, heading markers, HTML tags, and other Markdown metacharacters.
- Enforce a conservative length limit.
- Prefer a strict allowlist of ordinary Unicode letters, digits, spaces, underscores, and hyphens.
- Mark all externally sourced text explicitly as untrusted data when supplying it to an agent.
- Add tests using display names containing newlines,
##headings, table delimiters, code fences, and instruction-like content, and verify that none can create new Markdown blocks. - Review and clean existing generated
SOUL.mdcontent for previously injected metadata.
- Do not write Telegram-controlled metadata into
