Back to skill

Security audit

Agent Trust Protocol

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent trust-management purpose, but confirmed command-injection flaws and an unpinned signing dependency make it unsafe to install without review.

Install only after the publisher fixes the shell=True command construction, validates Moltbook identifiers, pins or vendors the skillsign dependency, and updates the documentation to match implemented behavior. Treat the local ~/.atp data as sensitive trust and identity metadata.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
moltbook_trust.py:39
Finding

Shell Command Injection Through Moltbook Usernames

Content
View full analysis
' to create one") return link = bridge["links"][username] print(f"Moltbook User: {username}") print(f" Fingerprint: {link['fingerprint']}") print(f" Linked: {link['linked_at']}") print(f" Verified: {'✓' if link.get('verified') else '✗ (unverified)'}") # Get ATP trust score score_out = atp_cmd(f"trust score {username}") if score_out: print(f" ATP Trust: {score_out}") def cmd_score(username, domain=None): """Get trust score for a Moltbook user.""" bridge = load_bridge() if username not in bridge["links"]: print(f"✗ Unknown user: {username}") return domain_flag = f" --domain {domain}" if domain else "" score_out = atp_cmd(f"trust score {username}{domain_flag}") ``` The leaderboard also passes stored usernames to the same shell sink: ```python for username, link in bridge["links"].items(): score_out = atp_cmd(f"trust score {username}") ``` ### Technical Analysis `atp_cmd()` builds a shell command by interpolating an untrusted string and executes it with `shell=True`. The shell t ...[truncated 2258 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
moltbook_trust.py:93
Finding

Shell Command Injection Through Moltbook Post IDs

Content
View full analysis
= 3: cmd_scan_post(sys.argv[2]) ``` ### Technical Analysis `post_id` is concatenated directly into a shell command and executed with `shell=True`. There is no validation, quoting, or separation between the intended post identifier and shell syntax. Although a 15-second timeout is configured, it does not prevent command injection. The injected process can complete within that period, modify files immediately, or spawn a detached process that survives termination of the original shell. The path to `moltbook.py` is locally generated and is not the primary injection source here. The direct command-line `post_id` is sufficient to gain command execution. ### Attack Path 1. An attacker convinces a user or agent workflow to scan a crafted post identifier: ```text python3 moltbook_trust.py scan-post '123; id #' ``` 2. `main()` passes the complete string to `cmd_scan_post()`. 3. The function constructs a shell command equivalent to: ```text python3 /home/user/.openclaw/skills/moltbook/moltbook.py post 123; id # ``` 4. The shell executes the intended Moltbook command and then executes the injected command. 5. The attacker can substitute commands that access ...[truncated 714 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
package.json:27
Finding

Unpinned Remote Git Dependency Creates a Supply-Chain Risk

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (19)

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · demo.py (reported line 58)May include surrounding context.

python
def run(cmd, env=None, capture=True):
    """Run a command, return stdout."""
    merged_env = {**os.environ, **(env or {})}
    result = subprocess.run(cmd, shell=True, capture_output=capture, text=True, env=merged_env)
    if result.returncode != 0 and capture:
        detail(f"stderr: {result.stderr.strip()[:200]}")

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
96% confidence
Finding

Using shell=True with a composed command string enables tool-parameter abuse because arguments are interpreted by the shell rather than passed literally to the target program. In a security/demo skill that manipulates keys, trust state, and file paths, this context increases risk: a crafted path, filename, or injected argument could execute arbitrary commands under the user's account.

Content

Scanner excerpt · demo.py (reported line 59)May include surrounding context.

python
def run(cmd, env=None, capture=True):
    """Run a command, return stdout."""
    merged_env = {**os.environ, **(env or {})}
    result = subprocess.run(cmd, shell=True, capture_output=capture, text=True, env=merged_env)
    if result.returncode != 0 and capture:
        detail(f"stderr: {result.stderr.strip()[:200]}")
    return result.stdout.strip() if capture else ""

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · demo.py (reported line 160)May include surrounding context.

python
alpha_pub_path = os.path.join(alpha_keys_dir, f)
                # Copy to bravo's keys dir so trust command can find it
                shutil.copy2(alpha_pub_path, os.path.join(bravo_keys_dir, f))
                detail(f"Copied {f} to Bravo's keyring")
    if alpha_pub_path:
        # Trust command needs path to the pub file in bravo's env
        bravo_pub_copy = os.path.join(bravo_keys_dir, os.path.basename(alpha_pub_path))

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

This is direct tool-parameter abuse: user-influenced values are funneled into a shell command without separation or escaping. In this skill context, the commands are exposed through CLI operations like lookup/score, making exploitation straightforward by passing crafted usernames or domain values.

Content

Scanner excerpt · moltbook_trust.py (reported line 40)May include surrounding context.

python
def atp_cmd(args):
    """Run ATP command and return output."""
    import subprocess
    result = subprocess.run(
        f"python3 {ATP_PY} {args}",
        shell=True, capture_output=True, text=True
    )

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
98% confidence
Finding

The scan-post path passes post_id into a shell command, allowing abuse of the external Moltbook tool invocation. Because this skill is intended to process external platform identifiers, attacker-controlled input is plausible and the trust/identity context does not reduce the danger of arbitrary shell execution.

Content

Scanner excerpt · moltbook_trust.py (reported line 97)May include surrounding context.

python
try:
        import subprocess
        moltbook_py = os.path.expanduser("~/.openclaw/skills/moltbook/moltbook.py")
        result = subprocess.run(
            f"python3 {moltbook_py} post {post_id}",
            shell=True, capture_output=True, text=True, timeout=15
        )

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module usage documentation says users can run challenge respond and challenge verify, implying the skill supports both challenge signing and verification workflows. In the command dispatcher, only challenge create is registered, so the documented capabilities contradict the actual available behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The challenge workflow writes challenge and response artifacts containing agent identifiers, nonces, timestamps, and signature output to predictable files under the user's home directory without any permission hardening, warning, or consent gate. In an agent-skill context, that can silently persist sensitive authentication metadata and make later misuse, replay analysis, or local data harvesting easier for other local processes or users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This function performs a signing operation via an external tool with no in-function warning, confirmation, or trust check on the challenge source. In a security-sensitive identity protocol, silently causing signing actions is dangerous because signatures are authoritative and an agent or user may be induced to sign attacker-supplied nonces or protocol messages without understanding the consequence.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · atp.py (reported line 298)May include surrounding context.

python
nonce_file.write_text(nonce)
    
    # Use skillsign to sign
    result = subprocess.run(
        ["python3", str(Path.home() / "clawd/skillsign/skillsign.py"), "sign", str(nonce_file)],
        capture_output=True, text=True
    )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The helper executes dynamically constructed command strings with subprocess.run(..., shell=True), which makes the shell parse metacharacters and expansions. Although most arguments in this demo are locally constructed, some values ultimately come from filesystem-derived names and command arguments assembled as strings, so a malicious filename, path, or future refactor introducing external input could trigger command injection.

Content

Scanner excerpt · demo.py (reported line 59)May include surrounding context.

python
def run(cmd, env=None, capture=True):
    """Run a command, return stdout."""
    merged_env = {**os.environ, **(env or {})}
    result = subprocess.run(cmd, shell=True, capture_output=capture, text=True, env=merged_env)
    if result.returncode != 0 and capture:
        detail(f"stderr: {result.stderr.strip()[:200]}")
    return result.stdout.strip() if capture else ""

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code executes a shell command via subprocess.run with shell=True using interpolated arguments, but there is no visible prompt, warning, or disclosure to the user that shell execution will occur. For a code file, subprocess execution is a safety-relevant operation that should have some user-facing disclosure unless it is clearly documented as part of the skill's stated purpose, which this file's top-level description does not explicitly do.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

This subprocess invocation uses shell=True with a command string that incorporates the caller-controlled args parameter. Any metacharacters in username or domain values can be interpreted by the shell, enabling command injection and arbitrary command execution under the user's account.

Content

Scanner excerpt · moltbook_trust.py (reported line 40)May include surrounding context.

python
def atp_cmd(args):
    """Run ATP command and return output."""
    import subprocess
    result = subprocess.run(
        f"python3 {ATP_PY} {args}",
        shell=True, capture_output=True, text=True
    )

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · moltbook_trust.py (reported line 63)May include surrounding context.

python
bridge = load_bridge()
    if username not in bridge["links"]:
        print(f"✗ No link found for {username}")
        print(f"  Run 'moltbook_trust.py link {username} <fingerprint>' to create one")
        return
    
    link = bridge["links"][username]

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The scan-post command calls another local CLI to retrieve post information, which may process user or content data, but the code provides no advance disclosure that an external subprocess will be launched for this purpose. For code files, this kind of subprocess-based data access should be accompanied by a visible warning or clear documentation when not already disclosed.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

This command builds a shell string with untrusted post_id and executes it with shell=True. An attacker supplying a crafted post_id could inject additional shell commands, leading to arbitrary code execution when scan-post is used.

Content

Scanner excerpt · moltbook_trust.py (reported line 97)May include surrounding context.

python
try:
        import subprocess
        moltbook_py = os.path.expanduser("~/.openclaw/skills/moltbook/moltbook.py")
        result = subprocess.run(
            f"python3 {moltbook_py} post {post_id}",
            shell=True, capture_output=True, text=True, timeout=15
        )

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger list includes broad conversational phrases such as 'trust score', 'agent trust', and 'trust status' that can plausibly appear in ordinary user dialogue. This creates a real risk of unintended skill activation, causing the security-oriented skill to intercept conversations unexpectedly and potentially influence agent behavior or user decisions in contexts where it was not explicitly invoked.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The top-level docstring describes the skill as using a 'local graph database for relationship tracking'. The implementation stores trust data in trust.json and interactions in interactions.jsonl, which is materially different from the documented storage model.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The save_bridge function writes user linkage data, including usernames and fingerprints, to a persistent file in the user's home directory. Although the link command prints a success message after saving, there is no prior disclosure in code comments, prompts, or the usage text warning that identity mappings will be stored locally.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

Line L056 instructs users to run a 'verify' command to verify identities via challenge-response, and L052 says verification is set after that process. However, the command dispatcher in L148-L170 has no 'verify' branch and no verification logic exists anywhere in the file, so the inline documentation actively misrepresents implemented behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.