Back to skill

Security audit

AIEOS (AI Entity Object Specification)

Security checks for vulnerabilities and agentic risk

Overview

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.

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 (3)

T02 · Agent Memory Poisoning

Error
Location
scripts/aieos_tool.py:79
Finding

Persistent Agent Instruction Injection Through Untrusted Persona Schemas

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/aieos_tool.py:380
Finding

Stored HTML Injection in Generated Biography Pages

Content
View full analysis
\n" if portrait_url else "" ``` They are also inserted directly into HTML element content: ```python html_content_about_me = f""" {profile_image_html}

{name}

{creature_type} | {vibe}

About Me

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"

Core Values:

    " html_content_truths_start += ''.join([f"
  • {v}
  • " for v in moral_compass.get('core_values', [])]) html_content_truths_start += f"
\n" ``` Image values are also used as raw attribute values: ```python if portrait_url: image_gallery_html += f ...[truncated 2413 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/aieos_tool.py:33
Finding

Unrestricted Remote Schema Fetching Enables Server-Side Request Forgery and Resource Exhaustion

Content
View full analysis
Dict[str, Any]: """Load AIEOS schema from URL or file.""" if source.startswith(('http://', 'https://')): # Load from URL print(f"Loading schema from URL: {source}") try: with urllib.request.urlopen(source) as response: content = response.read().decode('utf-8') return json.loads(content) except Exception as e: raise ValueError(f"Failed to load schema from URL: {e}") ``` ### Technical Analysis The command accepts an arbitrary `http://` or `https://` URL and fetches it from the host running the skill. There is no destination allowlist, IP-address restriction, explicit timeout, maximum response size, or redirect-target revalidation. As a result, the process can be induced to send requests to network locations that are reachable from the agent host but not necessarily reachable by the external attacker. This includes loopback services and private or link-local network addresses. `response.read()` reads the entire response into memory before parsing it. A large response can therefore consume excessive memory, while a slow endpoint can tie up execution because no explicit timeout is supplied. Although JSON parsing limits practical data extraction to responses that parse as JSON, internal JSON APIs may still be accessed. The `load` command also prints successfully parsed responses, which can expose returned internal data to the invoking user or surrounding logs. ### Attack Path 1. An attacker controls or influences the value passed to `--source`. 2. The attacker supplies a URL pointing to an internal service, loopback address, private network host, link-local endpoint, or an external URL that redirects to such ...[truncated 1196 chars]
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Tainted flow: 'PERSONA_DATA_PATH' from os.getenv (line 28, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
88% confidence
Finding

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.

Content

Scanner excerpt · scripts/aieos_tool.py (reported line 85)May include surrounding context.

python
# --- 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:

Tainted flow: 'IDENTITY_PATH' from os.getenv (line 26, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
86% confidence
Finding

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.

Content

Scanner excerpt · scripts/aieos_tool.py (reported line 272)May include surrounding context.

python
# 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}")

Tainted flow: 'SOUL_PATH' from os.getenv (line 25, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
86% confidence
Finding

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.

Content

Scanner excerpt · scripts/aieos_tool.py (reported line 277)May include surrounding context.

python
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}")

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.