T09 · Insecure Skill Coding Practices
- Location
scripts/manage.py:11- Finding
Overbroad Access to a Shared Credential File and Insecure Plaintext Token Persistence
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a real NginxWebUI admin helper, but it handles powerful credentials and live proxy changes too broadly for automatic installation.
Review before installing. Only use this in a tightly controlled workspace with trusted local users, rotate NginxWebUI credentials after testing, and avoid storing the admin token in a shared .env file. Treat delete and reload commands as live infrastructure changes that need backup or confirmation outside the skill.
scripts/manage.py:11Overbroad Access to a Shared Credential File and Insecure Plaintext Token Persistence
scripts/manage.py:65Administrative Password and API Token Exposed Through Process Arguments
Saving an API token to a .env file is a credential-handling weakness because .env files are commonly readable by local users, captured in backups, or accidentally committed to version control. In this skill's context, the stored token appears to authorize administrative NginxWebUI actions, so compromise of the file could directly enable unauthorized proxy reconfiguration or service disruption.
# First time — get token and save to .env
python3 {{SKILL_DIR}}/scripts/manage.py --mode login
The script automatically loads secrets from a hard-coded workspace .env file, which is a form of credential access and secret material handling inside a broadly callable agent skill. In this context, the skill manages infrastructure and runs with Docker access, so reading shared workspace secrets increases the blast radius if the skill is misused or the workspace is multi-tenant.
import json, os, re, subprocess, sys, urllib.parse
from datetime import datetime, timezone, timedelta
# Auto-load .env from workspace root
_env_path = '/home/node/.openclaw/workspace/liyj/.env'
if os.path.isfile(_env_path):
with open(_env_path) as _f:
Opening and parsing the hard-coded .env file directly exposes the skill to credential harvesting from the workspace. Because this skill can modify and reload NginxWebUI configuration, coupling infrastructure control with direct secret-file access materially increases the impact of abuse.
from datetime import datetime, timezone, timedelta
# Auto-load .env from workspace root
_env_path = '/home/node/.openclaw/workspace/liyj/.env'
if os.path.isfile(_env_path):
with open(_env_path) as _f:
for _line in _f:
Persisting the API token back into the shared .env file stores an active authentication token in plaintext on disk. This creates a durable secret that other processes, users, or tools with workspace access may read and reuse to manipulate NginxWebUI and reload production proxy configuration.
token, _ = raw_api("POST", "/token/getToken", data=f"name={USER}&pass={PASS}")
if token:
os.environ["NGINXWEBUI_TOKEN"] = token
# Persist to .env
env_file = "/home/node/.openclaw/workspace/liyj/.env"
with open(env_file) as f:
content = f.read()
Referencing the shared .env path as the sink for token persistence confirms that credentials are written into a common workspace file rather than a protected secret store. In an agent skill environment, this is especially dangerous because other skills or users in the workspace may gain access to reusable infrastructure credentials.
if token:
os.environ["NGINXWEBUI_TOKEN"] = token
# Persist to .env
env_file = "/home/node/.openclaw/workspace/liyj/.env"
with open(env_file) as f:
content = f.read()
if "NGINXWEBUI_TOKEN=" in content:
This second login implementation also writes the authentication token into the same hard-coded .env file, reinforcing the plaintext credential storage issue. The duplication suggests the behavior is built into the normal workflow, making credential leakage likely rather than exceptional.
token = extract_token(resp)
if token:
os.environ["NGINXWEBUI_TOKEN"] = token
env_file = "/home/node/.openclaw/workspace/liyj/.env"
with open(env_file) as f:
content = f.read()
if "NGINXWEBUI_TOKEN=" in content:
The skill exposes sensitive capabilities including shell, network, environment-variable access, and file writes, yet declares no explicit tool scope or permission boundaries. In an agent setting, this increases the chance of overbroad execution and misuse, especially because the documented workflow includes Docker access and secret handling, which can enable host-level impact.
The skill explicitly describes storing authentication tokens in environment variables and a .env file without any security warning, which can lead to credential exposure through logs, process inspection, backups, or accidental commits. Since the token grants administrative API access to NginxWebUI, leakage could enable unauthorized configuration changes and service compromise.
The skill documents nginx validation and reload operations without warning about service disruption, invalid configuration rollout, or production impact. In practice, an operator or agent could trigger a reload at the wrong time or after unsafe changes, causing outages or failed deployments.
Documenting delete-server and delete-location commands without emphasizing irreversibility or backup requirements creates a real risk of accidental destructive changes. Because these commands modify reverse proxy configuration, misuse can break routing, disable applications, or expose services unintentionally.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
cmd.extend(["-d", data])
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
output = result.stdout.strip()
if not output:
return None, False
delete_server performs an irreversible destructive action immediately from a supplied ID with no confirmation prompt, dry-run mode, or safety flag. In an agent skill that can be triggered programmatically, this increases the chance of accidental or unauthorized deletion of reverse proxy configuration and service disruption.
delete_location deletes configuration objects with no confirmation or warning, making accidental execution easy in automation or agent-driven use. Removing a location can break routing or expose unintended backend behavior, resulting in outage or misconfiguration.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def main():
# Check docker & nginxwebui container
ps = subprocess.run(["docker", "ps", "--format", "{{.Names}}"],
capture_output=True, text=True, timeout=5)
if "nginxwebui" not in ps.stdout:
log("❌ NginxWebUI container not found or Docker socket unavailable")
No suspicious patterns detected.