T02 · Agent Memory Poisoning
- Location
scripts/aieos_tool.py:79- Finding
Persistent Agent Instruction Injection Through Untrusted Persona Schemas
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill has a coherent persona-management purpose, but it needs Review because it can persist imported file or URL content into agent identity and behavior files without strong validation or sanitization.
Install only if you are comfortable with a skill that can change persistent agent identity files. Apply schemas only from sources you trust, review the dry-run output before using --apply, avoid arbitrary URLs, and do not publish generated bio pages from untrusted persona data without sanitizing the HTML first.
scripts/aieos_tool.py:79Persistent Agent Instruction Injection Through Untrusted Persona Schemas
scripts/aieos_tool.py:380Stored HTML Injection in Generated Biography Pages
{creature_type} | {vibe}
Full Name: {full_name}
""" if bio.get('birthday'): html_content_about_me += f"Birthday: {bio['birthday']}
\n" if bio.get('gender'): html_content_about_me += f"Gender: {bio['gender']}
\n" if origin.get('nationality'): birthplace_info = f" ({origin.get('birthplace', {}).get('city', '')})" if origin.get('birthplace', {}).get('city') else "" html_content_about_me += f"Origin: {origin['nationality']}{birthplace_info}
\n" if residence.get('current_city'): dwelling_info = f" ({residence.get('dwelling_type', '')})" if residence.get('dwelling_type') else "" html_content_about_me += f"Residence: {residence['current_city']}, {residence.get('current_country', '')}{dwelling_info}
\n" ``` Array values are rendered as raw list-item markup: ```python if moral_compass.get('core_values'): html_content_truths_start += f"scripts/aieos_tool.py:33Unrestricted Remote Schema Fetching Enables Server-Side Request Forgery and Resource Exhaustion
The skill instructs users to run a Python tool that can read local files, write to workspace files, access environment-derived paths, and fetch schemas from URLs, but the manifest declares no explicit tool scope or permissions. This creates an under-specified trust boundary: consumers may install or invoke the skill without realizing it has filesystem and network effects, increasing the risk of unintended data exposure, remote content ingestion, or unauthorized modification of identity files.
The tool fetches schemas from arbitrary HTTP/HTTPS URLs, which expands the trust boundary to remote untrusted content. In this skill, remote content is later used to generate local identity files and HTML, so network retrieval meaningfully increases exposure to malicious schemas, tracking, or unexpected outbound requests.
When apply_changes is enabled, the script writes directly to entity.json and later rewrites IDENTITY.md and SOUL.md, which can alter user-managed identity data. Although the CLI supports a dry run by default, there is no interactive confirmation or strong warning at the write points before these files are overwritten.
The write target is derived from OPENCLAW_WORKSPACE, an environment variable that is trusted without normalization or containment checks. If an attacker can influence the environment in which this tool runs, they can redirect persona data writes to arbitrary filesystem locations, potentially overwriting sensitive files the process can access.
# --- Step 1: Save the full AIEOS schema to entity.json ---
PERSONA_DATA_PATH.parent.mkdir(parents=True, exist_ok=True)
if apply_changes:
with open(PERSONA_DATA_PATH, 'w', encoding='utf-8') as f:
json.dump(schema, f, indent=2, ensure_ascii=False)
print(f"Updated full AIEOS persona data at {PERSONA_DATA_PATH}")
else:
IDENTITY_PATH is built from an environment-controlled workspace path and then opened for writing with no path safety checks. In a hostile execution environment, this enables arbitrary file overwrite within the permissions of the running user, and the file content is attacker-influenced through the supplied schema.
# Actually apply changes if requested
if apply_changes:
if IDENTITY_PATH.exists():
with open(IDENTITY_PATH, 'w', encoding='utf-8') as f:
f.write(identity_content)
print(f"Updated {IDENTITY_PATH}")
SOUL_PATH inherits the same trust boundary issue: it comes from an environment-derived base path and is written without restriction checks. This creates an arbitrary file overwrite primitive if the environment is attacker-controlled or if the workspace contains malicious symlinks.
print(f"Updated {IDENTITY_PATH}")
if SOUL_PATH.exists():
with open(SOUL_PATH, 'w', encoding='utf-8') as f:
f.write(soul_content)
print(f"Updated {SOUL_PATH}")
The bio page generator interpolates untrusted schema fields directly into HTML attributes and element bodies without escaping. If the generated page is opened in a browser, attacker-controlled values such as name, style descriptors, or image URLs can trigger stored XSS or load attacker-controlled resources, turning persona data into executable web content.
The accent.region and accent.strength fields define a regional accent profile, which can be used to force a locale-specific speaking style. Because the schema provides no accompanying language or locale choice requirement, it may enable downstream skills to impose a specific locale presentation without user opt-in.
The export function writes schema data directly to the user-supplied output_path with no confirmation if the destination already exists. This is a file-modifying operation that may overwrite existing content without a user-facing warning beyond a generic status message.
The generated page sets <html lang="en">, which forces an English locale regardless of the user's preferences or the persona data. This is a natural-language locale constraint without opt-in or a documented reason for being English-only.
The bio page generator writes HTML to the specified output_path without checking for an existing file or asking the user to confirm replacement. This can silently overwrite prior output or other user data at that path.
No suspicious patterns detected.