Back to skill

Security audit

Agent P2P

Security checks across malware telemetry and agentic risk

Overview

This appears to be a real P2P agent messaging skill, but it needs Review because it grants broad local and VPS control while handling secrets and public endpoints unsafely.

Install only if you are comfortable giving this skill broad command execution, SSH access to a VPS, persistent background services, and access to OpenClaw/P2P secrets. Use a dedicated VPS and SSH key, rotate any hooks/API/admin credentials after testing, inspect the deploy source before running auto-install, and avoid using it for sensitive files until command injection, plaintext secret storage, endpoint authentication, and file-transfer approval issues are fixed.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (63)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run(cmd, check=True):
    """运行命令"""
    print(f"$ {cmd}")
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    if check and result.returncode != 0:
        print(f"错误: {result.stderr}")
        sys.exit(1)
Confidence
96% confidence
Finding
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
os.chmod(ssh_key, 0o600)
    
    # 测试连接
    result = subprocess.run(
        f"ssh -i {ssh_key} -o StrictHostKeyChecking=no -o BatchMode=yes ubuntu@{vps_ip} 'echo OK'",
        shell=True, capture_output=True, text=True
    )
Confidence
98% confidence
Finding
result = subprocess.run( f"ssh -i {ssh_key} -o StrictHostKeyChecking=no -o BatchMode=yes ubuntu@{vps_ip} 'echo OK'", shell=True, capture_output=True, text=True )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
echo "部署完成"
"""
    
    result = subprocess.run(
        f"ssh -i {ssh_key} ubuntu@{vps_ip} '{script}'",
        shell=True, capture_output=True, text=True
    )
Confidence
99% confidence
Finding
result = subprocess.run( f"ssh -i {ssh_key} ubuntu@{vps_ip} '{script}'", shell=True, capture_output=True, text=True )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""获取 API Key"""
    print(f"\n[4/6] 获取 API Key")
    
    result = subprocess.run(
        f"ssh -i {ssh_key} ubuntu@{vps_ip} 'python3 -c \"import sqlite3; conn = sqlite3.connect(\\\"/opt/agent-p2p/data/portal.db\\\"); cur = conn.cursor(); cur.execute(\\\"SELECT key_id FROM api_keys LIMIT 1\\\"); print(cur.fetchone()[0])\"'",
        shell=True, capture_output=True, text=True
    )
Confidence
96% confidence
Finding
result = subprocess.run( f"ssh -i {ssh_key} ubuntu@{vps_ip} 'python3 -c \"import sqlite3; conn = sqlite3.connect(\\\"/opt/agent-p2p/data/portal.db\\\"); cur = conn.cursor(); cur.execute(\\

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"\n[6/6] 测试连接")
    
    # 测试 Portal
    result = subprocess.run(
        f"curl -sk https://{domain}/api/portal/info",
        shell=True, capture_output=True, text=True
    )
Confidence
94% confidence
Finding
result = subprocess.run( f"curl -sk https://{domain}/api/portal/info", shell=True, capture_output=True, text=True )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return False
    
    # 测试 OpenClaw
    result = subprocess.run(
        f"curl -s -X POST {gateway_url}/hooks/wake -H 'Authorization: Bearer {hooks_token}' -H 'Content-Type: application/json' -d '{{\"text\":\"测试\"}}'",
        shell=True, capture_output=True, text=True
    )
Confidence
99% confidence
Finding
result = subprocess.run( f"curl -s -X POST {gateway_url}/hooks/wake -H 'Authorization: Bearer {hooks_token}' -H 'Content-Type: application/json' -d '{{\"text\":\"测试\"}}'", shell=Tr

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"\n[1/6] 检查域名解析: {domain}")
    
    for i in range(30):  # 最多等待 5 分钟
        result = subprocess.run(
            f"nslookup {domain}",
            shell=True, capture_output=True, text=True
        )
Confidence
95% confidence
Finding
result = subprocess.run( f"nslookup {domain}", shell=True, capture_output=True, text=True )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if new_pass:
                # 更新 VPS 上的密码
                update_cmd = f"ssh -i {args.ssh_key} ubuntu@{args.vps_ip} 'sudo htpasswd -cb /etc/nginx/.htpasswd {admin_user} \"{new_pass}\" && echo 密码已更新'"
                result = subprocess.run(update_cmd, shell=True, capture_output=True, text=True)
                if result.returncode == 0:
                    admin_pass = new_pass
                    print("✅ 密码已更新")
Confidence
100% confidence
Finding
result = subprocess.run(update_cmd, shell=True, capture_output=True, text=True)

Tainted flow: 'update_cmd' from input (line 398, user input) → subprocess.run (code execution)

Critical
Category
Data Flow
Content
if new_pass:
                # 更新 VPS 上的密码
                update_cmd = f"ssh -i {args.ssh_key} ubuntu@{args.vps_ip} 'sudo htpasswd -cb /etc/nginx/.htpasswd {admin_user} \"{new_pass}\" && echo 密码已更新'"
                result = subprocess.run(update_cmd, shell=True, capture_output=True, text=True)
                if result.returncode == 0:
                    admin_pass = new_pass
                    print("✅ 密码已更新")
Confidence
100% confidence
Finding
result = subprocess.run(update_cmd, shell=True, capture_output=True, text=True)

Tainted flow: 'to_portal' from os.environ.get (line 102, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
# 1. 发送到对方 Portal 的 /api/message/receive
    try:
        resp = requests.post(
            f"{to_portal}/api/message/receive",
            json={
                "api_key": shared_key,
Confidence
87% confidence
Finding
resp = requests.post( f"{to_portal}/api/message/receive", json={ "api_key": shared_key, "from_portal": my_hub_url, "cont

Tainted flow: 'to_portal' from os.environ.get (line 186, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
file_size: int, file_md5: str, chunks_total: int) -> str:
    """初始化文件传输(简化版:直接返回file_id,无需确认)"""
    try:
        resp = requests.post(
            f"{to_portal}/api/file/initiate",
            json={
                "api_key": api_key,
Confidence
91% confidence
Finding
resp = requests.post( f"{to_portal}/api/file/initiate", json={ "api_key": api_key, "filename": filename, "size": file_si

Tainted flow: 'to_portal' from os.environ.get (line 186, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
for attempt in range(max_retries):
        try:
            resp = requests.post(
                f"{to_portal}/api/file/chunk/{file_id}/{chunk_index}",
                json={
                    "api_key": api_key,
Confidence
94% confidence
Finding
resp = requests.post( f"{to_portal}/api/file/chunk/{file_id}/{chunk_index}", json={ "api_key": api_key, "file_id": f

Intent-Code Divergence

High
Confidence
98% confidence
Finding
These instructions explicitly tell the agent to inspect local files containing secrets such as API keys, hook tokens, and admin passwords in order to answer user questions. In an agent skill context, that creates a direct path for secret retrieval and possible disclosure to an untrusted requester, violating least-privilege and secret-handling boundaries.

Intent-Code Divergence

Medium
Confidence
85% confidence
Finding
The skill states that file transfer uploads directly to the recipient portal without receiver confirmation, which weakens the earlier approval model for new contacts/shared-key acceptance. Even if authentication exists, automatic acceptance of inbound files can enable unwanted content delivery, storage abuse, or malicious payload staging once a shared key is available.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The installer reads hooks tokens from unrelated local OpenClaw configuration files without an explicit prompt or narrowly scoped consent. This expands its access to sensitive credentials beyond what a simple portal deployment step obviously requires, increasing the chance of accidental secret use or leakage.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The script persists sensitive secrets locally, including admin password, API key, VPS IP, and SSH key path, in plaintext under the user's home directory. This broadens the exposure window for credentials and infrastructure details well beyond the immediate installation task.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The document explicitly recommends using a fixed JWT SECRET_KEY so tokens survive service restarts. A long-lived shared static signing secret increases blast radius if leaked, enables forging of all tokens across restarts/environments, and prevents safe key rotation. In a P2P trust-establishment flow, compromised tokens directly undermine authentication between agents.

Intent-Code Divergence

Medium
Confidence
99% confidence
Finding
The design claims a 6-digit code is sufficient, but the same document exposes the verification code via the status API response. If any caller can query status or enumerate requester_portal values, the out-of-band proof is defeated and an attacker can confirm requests without possessing the code from the separate channel. This turns the verification step into little more than an API lookup.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The code claims it only 'wakes' the OpenClaw session, but it actually forwards the full notification object, including user-supplied message content and metadata, to the hook endpoint. This broadens data exposure and can cause unintended prompt/data injection into the downstream agent if the hook is treated as a simple signal channel.

Intent-Code Divergence

High
Confidence
92% confidence
Finding
The script claims to deploy Portal code but actually deletes any existing deployment and pulls replacement code from a hard-coded third-party GitHub repository. This creates a software supply-chain risk and can overwrite a trusted local deployment with unreviewed remote code, especially dangerous because the script later runs that code as a persistent service with elevated privileges.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The script claims to make a safe backup before changing configuration, but backup_config calls os.time(), which does not exist and will raise an exception before any backup is created. This can leave users with a modified or partially processed configuration flow without the promised recovery path, increasing the risk of configuration loss or failed setup.

Context-Inappropriate Capability

Medium
Confidence
82% confidence
Finding
The tool reads sensitive local credentials from ~/.openclaw/gateway.env automatically, expanding its access beyond the explicit send operation. In an agent-skill context, silent credential harvesting from local files increases risk because invoking the skill can unexpectedly grant it access to secrets needed for outbound communication.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The implementation contradicts the intended security model by marking new transfers as immediately transferable and receiver_confirmed=TRUE, which removes recipient consent from the file-transfer workflow. In this portal context, that allows any party with a valid API key to push unsolicited content into backend storage and potentially surprise the receiving agent with files that were never approved.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The /api/chat/owner/reply endpoint accepts unauthenticated POST requests and writes attacker-controlled content into owner_chats, then broadcasts it to connected clients. That creates an external message-injection path where anyone who can reach the service can impersonate OpenClaw, manipulate the owner, and spam or socially engineer downstream users.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The UI states the shared key is only for messaging, but the code later reuses `data.api_key || data.SHARED_KEY` to authenticate a WebSocket agent connection. This expands the privilege of the shared secret beyond what the UI discloses, so anyone who learns that key may gain unintended real-time agent-channel access rather than only message-sending capability.

VirusTotal

65/65 vendors flagged this skill as clean.

View on VirusTotal

Static analysis

No suspicious patterns detected.