Back to skill

Security audit

UniProfit Mail Assistant

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent email-sending helper, but it should be reviewed because its scripts can send the mail API key and message contents to any configured base URL without enforcing HTTPS.

Install only if you trust the configured UniProfit API base URL and can ensure it uses HTTPS. Treat the mail_send key like a live credential, verify recipients and sender accounts before sending, and avoid putting confidential email bodies into command lines or logs.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/send_mail.py:25
Finding

API Credentials and Email Content Can Be Transmitted over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/send_mail.py:25-54; also affects scripts/check_credential.py:22-32
Vulnerability Type: Missing enforcement of encrypted transport
Risk Level: High

Vulnerable Code

python
base_url = _require_env("UNIPROFIT_API_BASE_URL").rstrip("/")
api_key = _require_env("UNIPROFIT_MAIL_SEND_KEY")

body = json.dumps(
    {
        "account_id": args.account_id,
        "to_email": args.to_email,
        "to_name": args.to_name or None,
        "subject": args.subject,
        "body": args.body,
        "reply_to": args.reply_to or None,
    },
    ensure_ascii=False,
).encode("utf-8")

req = urllib.request.Request(
    f"{base_url}/openclaw/mail/send",
    data=body,
    headers={
        "Content-Type": "application/json",
        "X-UniProfit-Key": api_key,
    },
    method="POST",
)

try:
    with urllib.request.urlopen(req, timeout=30) as resp:

The credential-checking script uses the same unvalidated base URL:

python
base_url = _require_env("UNIPROFIT_API_BASE_URL").rstrip("/")
api_key = _require_env(KEY_ENV)

req = urllib.request.Request(
    f"{base_url}/openclaw/credential/me",
    headers={"X-UniProfit-Key": api_key},
    method="GET",
)
try:
    with urllib.request.urlopen(req, timeout=20) as resp:

Technical Analysis

Both scripts accept UNIPROFIT_API_BASE_URL directly from the environment and pass it to urllib.request.urlopen without parsing the URL or requiring the https scheme. Although the documentation provides an HTTPS example, the implementation does not enforce that requirement.

If the configured URL uses http://, the X-UniProfit-Key credential is transmitted without transport encryption. The mail-sending request additionally exposes the sender account identifier, recipient address, recipient name, subject, complete message body, and reply-to address.

Because the host i ...[truncated 1545 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse UNIPROFIT_API_BASE_URL with urllib.parse.urlsplit.
  2. Reject every scheme other than https.
  3. If local HTTP development is necessary, permit it only behind an explicit development option and only for loopback addresses such as 127.0.0.1 or ::1.
  4. Require a nonempty hostname and reject URLs containing embedded user information, fragments, or unexpected path components.
  5. Where deployments have a fixed service destination, enforce an administrator-controlled hostname allowlist.
  6. Apply the same centralized URL validation to both scripts before constructing any authenticated request.
  7. Rotate the API key if it may previously have been sent to an HTTP or untrusted endpoint.
  8. Retain normal TLS certificate and hostname validation; do not introduce an unverified SSL context.

Example validation:

python
from urllib.parse import urlsplit

def _validate_base_url(value: str) -> str:
    value = value.rstrip("/")
    parsed = urlsplit(value)
    if parsed.scheme != "https":
        raise SystemExit("UNIPROFIT_API_BASE_URL must use HTTPS")
    if not parsed.hostname or parsed.username or parsed.password:
        raise SystemExit("Invalid UNIPROFIT_API_BASE_URL")
    return value

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/send_mail.py:16
Finding

Sensitive Email Data Is Exposed through Process Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/send_mail.py:16-23
Vulnerability Type: Sensitive information exposure through process arguments
Risk Level: Medium

Vulnerable Code

python
parser = argparse.ArgumentParser()
parser.add_argument("--account-id", type=int, required=True)
parser.add_argument("--to-email", required=True)
parser.add_argument("--subject", required=True)
parser.add_argument("--body", required=True)
parser.add_argument("--to-name", default="")
parser.add_argument("--reply-to", default="")
args = parser.parse_args()

Technical Analysis

The script requires the recipient address, subject, complete message body, recipient name, and reply-to address to be passed as command-line arguments. Process arguments are not an appropriate channel for confidential message content.

Depending on the operating system and execution environment, command lines may be visible through process-inspection interfaces, administrative tooling, audit systems, shell history, CI/CD logs, orchestration metadata, or agent tool-call logs. Even where process inspection is restricted to the same user, unrelated processes or support tooling operating under that identity may capture the data.

The issue does not require command injection: argparse correctly separates these values as data. The vulnerability is the avoidable disclosure caused by placing sensitive values in observable process metadata.

Attack Path

  1. A user or agent invokes send_mail.py with --to-email, --subject, and --body.
  2. The operating system records the complete invocation in the process argument vector.
  3. A local observer, monitoring agent, shell-history mechanism, process collector, or execution-log service captures the command line.
  4. The observer retrieves recipient information and the complete approved email content.
  5. If messages contain personal, commercial, or confidential information, that information ...[truncated 684 chars]
Remediation
View remediation

Remediation Suggestions

  1. Accept the complete mail request as JSON through standard input rather than command-line flags.
  2. Alternatively, accept a path to a securely permissioned input file and delete it safely after processing when appropriate.
  3. Keep only non-sensitive operational switches in command-line arguments.
  4. Do not print or log the request body, subject, recipient name, or other sensitive content.
  5. Review agent, shell, CI/CD, and process-monitoring logs for historical disclosure and apply suitable retention and access controls.
  6. Document that callers must avoid embedding message contents in shell commands.

Example interface:

python
import json
import sys

message = json.load(sys.stdin)
account_id = int(message["account_id"])
to_email = message["to_email"]
subject = message["subject"]
body_text = message["body"]
to_name = message.get("to_name", "")
reply_to = message.get("reply_to", "")

The caller can then provide the JSON through a protected standard-input stream without placing its contents in the process argument vector.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill is presented as an email-delivery helper, but it also instructs runtime credential inspection through /openclaw/credential/me and references a script that validates credentials. That mismatch can expose credential metadata or normalize extra API access beyond the user's expected action, which is especially sensitive in a skill handling authentication material.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill declares environment-variable and network-dependent behavior but does not define an explicit tool scope such as permissions or allowed-tools. That weakens runtime containment and reviewability, increasing the chance that an agent can access capabilities broader than reviewers expect when handling sensitive email credentials and outbound delivery.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file documents a mail-sending capability that transmits recipient identity, subject, and body content to a remote API. Under the markdown-specific warning criterion, it lacks any explicit caution about sending user data off-system, using configured sender accounts, or the consequences of dispatching real email.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.