T05 · Unauthorized Access and Privilege Escalation
- Location
vps/main.py:187- Finding
Portal Authentication Bypass Through Unauthenticated API-Key Creation
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent P2P messaging and file-transfer portal, but it requests broad authority and contains serious access-control, credential-handling, installer, and remote-message safety flaws.
Install only in a test environment unless you are prepared to audit and fix it first. Before production use, require authentication and role separation on all Portal APIs, remove the hardcoded/default passwords, stop printing or storing plaintext secrets, validate contact portal URLs, restore TLS verification, sanitize downloaded filenames and UI rendering, add file-size and storage limits, avoid shell=True, pin deployed code and dependencies, and keep OpenClaw wake-hook processing isolated from remote message instructions.
vps/main.py:187Portal Authentication Bypass Through Unauthenticated API-Key Creation
vps/main.py:995Administrative API Discloses Owner and OpenClaw Credentials
vps/main.py:205Hardcoded Default Administrative Password
vps/main.py:539Multiple Sensitive Portal Endpoints Are Unauthenticated
local/bridge.py:95Untrusted Remote Messages Are Injected Directly Into the Agent Wake Hook
auto_install.py:93Shell Command Injection in the Automated Installer
vps/static/admin.html:347Stored Cross-Site Scripting in Contact Rendering
local/client.py:24TLS Certificate Verification Is Disabled for Portal Communications
send_file.py:233Downloaded Filename Allows Arbitrary Local File Overwrite
vps/main.py:1441Unbounded File Transfers Permit Memory, Database, and Disk Exhaustion
scripts/deploy_portal.py:92Privileged Deployer Uses Predictable Credentials, Trusts Unknown SSH Hosts, and Runs Portal as Root
auto_install.py:288Sensitive Configuration and Credential Files Are Written Without Enforced Permissions
scripts/setup_openclaw_hooks.py:29Hook Configuration Backup Is Broken and Sensitive Configuration Is Rewritten Unsafely
install.sh:19Dependencies and Deployed Source Are Not Pinned to Reviewed Versions
The document points to a local file containing an administrator password and presents it as a normal lookup source. Exposing or encouraging access to admin credentials is especially dangerous because compromise would permit full administrative control over the related service or environment.
The new admin password is taken from interactive user input and inserted directly into update_cmd, which is executed with shell=True. A password containing quotes or shell metacharacters can break out of the intended command and execute arbitrary commands locally and/or remotely with sudo on the VPS.
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("✅ 密码已更新")
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
headers = {"Authorization": f"Bearer {api_key}"}
try:
resp = requests.get(url, headers=headers, timeout=10)
if resp.status_code == 200:
contacts = resp.json().get("contacts", [])
for c in contacts:
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
headers = {"Authorization": f"Bearer {api_key}"}
try:
resp = requests.get(url, headers=headers, timeout=10)
if resp.status_code == 200:
contacts = resp.json().get("contacts", [])
for c in contacts:
The code fetches contact metadata from the hub and then blindly POSTs sensitive message content plus a shared key to contact.portal_url. If an attacker can poison contact data or register a malicious portal URL, this creates an SSRF/external exfiltration path and leaks the per-contact secret to an attacker-controlled endpoint.
# 1. 发送到对方 Portal 的 /api/message/receive
try:
resp = requests.post(
f"{to_portal}/api/message/receive",
json={
"api_key": shared_key,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
# 2. 记录到我们 Portal 的 /api/message/sent
try:
resp = requests.post(
f"{my_hub_url}/api/message/sent",
json={
"api_key": api_key,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
def get_contact(contact_id: int, api_key: str, hub_url: str):
"""获取联系人信息"""
try:
resp = requests.get(
f"{hub_url}/api/contacts",
headers={"Authorization": f"Bearer {api_key}"},
timeout=10
The script takes a recipient-controlled portal_url from contact metadata and sends an authentication secret (shared_key as api_key) plus file metadata directly to that URL. Because there is no validation, trust check, or confirmation step, a malicious or poisoned contact record can redirect uploads and credentials to an attacker-controlled server, enabling unauthorized file exfiltration and secret disclosure.
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,
Each file chunk is uploaded to a recipient-supplied portal URL together with the shared secret and raw file content encoded in base64. Without destination validation or recipient confirmation, a malicious contact entry can silently siphon entire files and associated credentials to an attacker-controlled endpoint.
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,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
try:
# 查询状态
resp = requests.get(
f"{hub_url}/api/file/status/{file_id}",
params={"api_key": api_key},
timeout=10
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
print(f"📥 下载文件: {filename}")
# 下载
resp = requests.get(
f"{hub_url}/api/file/download/{file_id}",
params={"api_key": api_key},
stream=True,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
### 安全建议
1. **使用专用 SSH 密钥**
- 不要直接使用主密钥(`~/.ssh/id_rsa`)
- 创建专用密钥:`ssh-keygen -t ed25519 -C "agent-p2p" -f ~/.ssh/agent-p2p`
- 仅授权访问 Portal VPS
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
ssh-keygen -t ed25519 -C "agent-p2p"
ssh-copy-id -i ~/.ssh/id_ed25519.pub ubuntu@your-vps-ip
### 2. 部署 Portal
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
ssh-keygen -t ed25519 -C "agent-p2p"
ssh-copy-id -i ~/.ssh/id_ed25519.pub ubuntu@your-vps-ip
### 2. 部署 Portal
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
ssh-keygen -t ed25519 -C "agent-p2p"
ssh-copy-id -i ~/.ssh/id_ed25519.pub ubuntu@your-vps-ip
### 2. 部署 Portal
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
定期更新系统
sudo apt update && sudo apt upgrade -y
备份数据
This documentation explicitly identifies files and locations containing live secrets, including API keys and hook tokens, and does so without any warning about secrecy, consent, or redaction. In an agent skill context, this materially increases the chance that an agent or operator will retrieve and expose credentials during routine assistance, enabling account compromise or unauthorized system access.
The quick-reference commands directly print credential files and tokens to stdout, which can leak into chat responses, logs, terminal scrollback, screenshots, or monitoring systems. Providing copy-paste commands for plaintext secret disclosure meaningfully lowers the barrier to accidental or unauthorized exfiltration.
The quick-reference section tells the operator or agent to display files that contain secrets in plaintext, which is an unsafe handling pattern for credentials. In practice, these commands can expose secrets to any system that captures terminal output, model context, support transcripts, or logs.
This guidance instructs the agent to inspect local credential files when answering user questions, without requiring necessity checks, user authorization, or redaction. In a skill environment, that creates a direct path for prompt-driven secret harvesting, where a user can induce the agent to read and potentially reveal sensitive local data.
The document operationalizes access to sensitive local secrets—API keys, hook tokens, and an admin password—as part of normal response generation. That is a substantive secret-disclosure design flaw because it encourages the agent to treat highly sensitive credentials as answerable context rather than protected data.
The generic run(cmd, check=True) helper executes arbitrary strings with shell=True, making it an inherently dangerous primitive. Even though it is only used here for a local trusted script path, the helper invites future unsafe reuse and normalizes shell execution of raw strings.
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)
The script interpolates the user-supplied domain directly into a shell command (nslookup {domain}) with shell=True. An attacker who can influence the domain argument can inject arbitrary local shell commands during installation, which is especially dangerous because this is an admin-run setup script likely executed with access to SSH keys and local secrets.
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
)
The SSH test command embeds ssh_key and vps_ip directly into a shell command while also disabling host key checking. This enables local command injection via crafted arguments and increases MITM risk by trusting any host key presented by the server.
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
)
The remote deployment script performs sudo rm -rf agent-p2p under /opt without explicit confirmation or backup. This is destructive behavior in an installation script; if the target path or repository state is wrong, it can delete an existing deployment and data unexpectedly.
No suspicious patterns detected.