Back to skill

Security audit

CMI CPaaS - WhatsApp OTP Sender

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it sends API secrets and OTPs through an implementation that disables key network security protections.

Review before installing. Use this only in an environment where direct access to the CMI endpoint is approved and you accept the risk of disabled TLS verification. Prefer fixing certificate validation and proxy handling before real OTP use, avoid passing secrets on command lines, and rotate any CMI credentials that may already have been used with this implementation.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/send_whatsapp_otp.py:32
Finding
TLS Certificate and Hostname Verification Disabled## Vulnerability Details **File Location**: `scripts/send_whatsapp_otp.py:20`, `scripts/send_whatsapp_otp.py:32-44`, and `scripts/send_whatsapp_otp.py:115-124` **Vulnerability Type**: Improper certificate validation **Risk Level**: High ### Vulnerable Code ```python # Suppress SSL warnings for this specific endpoint import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) ``` ```python class SSLAdapter(HTTPAdapter): """Custom adapter to handle problematic SSL configurations""" def init_poolmanager(self, *args, **kwargs): # Create a very permissive SSL context for legacy servers context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) context.check_hostname = False context.verify_mode = ssl.CERT_NONE # Enable legacy server support context.options |= 0x4 # OP_LEGACY_SERVER_CONNECT # Use default minimum TLS version (TLSv1.2) to avoid deprecation warning # but allow legacy server connections via OP_LEGACY_SERVER_CONNECT kwargs['ssl_context'] = context return super().init_poolmanager(*args, **kwargs) ``` ```python # Create a session with custom SSL adapter for problematic endpoints session = requests.Session() session.mount('https://', SSLAdapter()) # Send POST request # Note: Using custom SSL adapter to handle the API endpoint's certificate configuration response = session.post( url, json=payload, headers=headers, timeout=60 ) ``` ### Technical Analysis The custom HTTPS adapter explicitly sets `verify_mode` to `ssl.CERT_NONE` and disables hostname checking. Consequently, the client does not establish that it is communicating with the legitimate `cpaas-rcs.cmidict.com` server. Suppressing `InsecureRequestWarning` also hides an important signal that transport authentication has been disabled. The transmitted JSON includes the tenant access-key secret, applicat ...[truncated 1585 chars]
Remediation
## Remediation Suggestions 1. Remove the custom `SSLAdapter` and use the default `requests` certificate and hostname validation. 2. Remove the global suppression of `InsecureRequestWarning`. 3. If the service uses a private certificate authority, obtain the legitimate CA certificate through a trusted channel and configure a narrowly scoped CA bundle: ```python response = requests.post( url, json=payload, headers=headers, timeout=60, verify="/secure/path/cmi-ca-bundle.pem" ) ``` 4. Do not use `verify=False` as a fallback. 5. Work with the API provider to correct incomplete certificate chains, hostname mismatches, or obsolete TLS settings. 6. Restrict outbound traffic to the documented destination and rotate API credentials if this implementation has been used across untrusted networks.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/send_whatsapp_otp.py:12
Finding
Configured Proxy and Network Security Controls Are Unconditionally Bypassed## Vulnerability Details **File Location**: `scripts/send_whatsapp_otp.py:12-16` and `scripts/send_whatsapp_otp.sh:60-62` **Vulnerability Type**: Forced bypass of configured network controls **Risk Level**: Medium ### Vulnerable Code ```python # CRITICAL: Clear proxy settings from environment to avoid connection timeout # This is necessary because the API endpoint may not be accessible through proxies os.environ['http_proxy'] = '' os.environ['https_proxy'] = '' os.environ['HTTP_PROXY'] = '' os.environ['HTTPS_PROXY'] = '' os.environ['no_proxy'] = '*' ``` ```bash RESPONSE=$(curl --noproxy "*" -s -X POST https://cpaas-rcs.cmidict.com:7081/singleSend \ -H "Content-Type: application/json" \ -d "$JSON_PAYLOAD") ``` ### Technical Analysis Both implementations force direct network access regardless of the operator's proxy configuration. The Python implementation modifies process environment variables and sets `no_proxy` to `*`, while the shell implementation passes `--noproxy "*"` to `curl`. Enterprise proxies may enforce destination allowlists, data-loss prevention, malware inspection, audit logging, or controlled egress. Unconditionally bypassing them is not necessary to implement an HTTPS API request and violates least-privilege network behavior. It also makes the security of the request dependent on the direct network path. The risk is amplified in the Python implementation because direct traffic is combined with disabled TLS certificate verification. ### Attack Path 1. An organization configures an HTTPS proxy to inspect, log, or restrict outbound requests. 2. The Skill clears the proxy variables or directs `curl` to bypass every proxy. 3. The request leaves through an unmanaged direct network route. 4. Corporate inspection, egress filtering, and related audit controls do not observe or protect the request. 5. An attacker controlling the direct route may target the connection; the Python implement ...[truncated 497 chars]
Remediation
## Remediation Suggestions 1. Remove the global proxy environment modifications from the Python script. 2. Remove `--noproxy "*"` from the shell script. 3. Respect the operator's standard proxy and `NO_PROXY` configuration by default. 4. If direct connectivity is genuinely required, provide an explicit opt-in option such as `--direct`, document its security consequences, and obtain operator approval before use. 5. Scope any exception to the exact API hostname rather than using the wildcard `*`. 6. Never combine direct-mode operation with disabled TLS certificate validation. 7. Coordinate with network administrators to allow the API through approved egress controls instead of bypassing those controls.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/send_whatsapp_otp.py:157
Finding
Long-Lived API Secrets Are Exposed Through Command-Line Arguments## Vulnerability Details **File Location**: `SKILL.md:25-31`, `scripts/send_whatsapp_otp.py:157-166`, and `scripts/send_whatsapp_otp.sh:2-9` **Vulnerability Type**: Sensitive information exposure through process arguments and command history **Risk Level**: Medium ### Vulnerable Code ```bash python scripts/send_whatsapp_otp.py \ --access-key-id "$ACCESS_KEY_ID" \ --access-key-secret "$ACCESS_KEY_SECRET" \ --app-name "$APPLICATION_NAME" \ --app-secret "$APPLICATION_SECRET" \ --to "$TO_NUMBER" \ --otp "$OTP_CODE" ``` ```python parser.add_argument("--access-key-id", required=True, help="Tenant AccessKeyId") parser.add_argument("--access-key-secret", required=True, help="Tenant AccessKeySecret") parser.add_argument("--app-name", default="default", help="Application name (default: default)") parser.add_argument("--app-secret", required=True, help="Application secret") parser.add_argument("--to", required=True, help="Recipient phone number with country code, no + prefix (e.g., 8613800138000)") parser.add_argument("--otp", required=True, help="OTP code to send") ``` ```bash # Usage: ./send_whatsapp_otp.sh <access_key_id> <access_key_secret> <app_name> <app_secret> <to_number> <otp_code> ACCESS_KEY_ID="$1" ACCESS_KEY_SECRET="$2" APP_NAME="${3:-default}" APP_SECRET="$4" TO_NUMBER="$5" OTP_CODE="$6" ``` ### Technical Analysis The documented and implemented interfaces place long-lived access and application secrets directly in the process argument vector. Depending on the operating system and execution environment, command-line arguments may be visible through process inspection tools, process telemetry, job runners, audit systems, error reports, or automation logs. Users who substitute literal secret values rather than prepopulated shell variables may additi ...[truncated 1372 chars]
Remediation
## Remediation Suggestions 1. Remove secret values from positional and named command-line arguments. 2. Retrieve long-lived credentials from an operating-system keyring, a dedicated secret manager, or files readable only by the executing account. 3. If environment variables are used, populate them through a protected execution environment rather than including assignments in the interactive command line. 4. Permit secrets to be read from standard input without echoing, for example through `getpass.getpass()` in interactive use. 5. Treat OTP values as sensitive and avoid including them in process arguments, debug logs, success output, or telemetry. 6. Update `SKILL.md` so its recommended invocation does not encourage secret-bearing command lines. 7. Rotate credentials that may already have appeared in process logs, shell history, or automation output.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/send_whatsapp_otp.sh:30
Finding
Shell Script Builds JSON by Interpolating Unescaped User Input## Vulnerability Details **File Location**: `scripts/send_whatsapp_otp.sh:30-55` **Vulnerability Type**: Improper neutralization of user-controlled data in a JSON payload **Risk Level**: Medium ### Vulnerable Code ```bash # Build JSON payload JSON_PAYLOAD=$(cat &lt;&lt;EOF { "Method": "SingleSend", "AccessKeyId": "$ACCESS_KEY_ID", "AccessKeySecret": "$ACCESS_KEY_SECRET", "Timestamp": "$TIMESTAMP", "ApplicationName": "$APP_NAME", "ApplicationSecret": "$APP_SECRET", "From": "+8618247665684", "To": "$TO_NUMBER", "Type": "template", "Content": { "template": { "name": "test_otp_cn_111501", "language": {"code": "zh_CN"}, "components": [ {"type": "body", "parameters": [{"type": "text", "text": "$OTP_CODE"}]}, {"type": "button", "sub_type": "url", "index": 0, "parameters": [{"type": "text", "text": "$OTP_CODE"}]} ] } }, "TemplateName": "test_otp_cn_111501" } EOF ) ``` ### Technical Analysis The script inserts every argument directly into a JSON heredoc without JSON escaping. The only recipient validation rejects a leading plus sign; it does not require the value to consist exclusively of digits. The OTP, application name, and credential fields also have no structural validation. A value containing a double quote, backslash, newline, or JSON delimiter can terminate its intended string and alter the resulting document. This is a JSON injection vulnerability rather than shell command injection: shell metacharacters produced by parameter expansion inside the heredoc are not re-evaluated as shell syntax, but they can still change the API payload. Whether duplicate or injected fields affect backend behavior depends on the API parser. At minimum, crafted values can produce malformed requests and reliable failures. If the backend accepts duplicate keys or attacker-added properties, the meaning of the authenticated request may be c ...[truncated 1028 chars]
Remediation
## Remediation Suggestions 1. Construct the request with a JSON-aware serializer rather than a shell heredoc. 2. Prefer the Python implementation after correcting its TLS and credential-handling issues. 3. If retaining the shell implementation, use `jq --arg` so every value is correctly encoded: ```bash JSON_PAYLOAD=$(jq -n \ --arg access_key_id "$ACCESS_KEY_ID" \ --arg access_key_secret "$ACCESS_KEY_SECRET" \ --arg timestamp "$TIMESTAMP" \ --arg app_name "$APP_NAME" \ --arg app_secret "$APP_SECRET" \ --arg to "$TO_NUMBER" \ --arg otp "$OTP_CODE" \ '{Method:"SingleSend", AccessKeyId:$access_key_id, AccessKeySecret:$access_key_secret, Timestamp:$timestamp, ApplicationName:$app_name, ApplicationSecret:$app_secret, To:$to}') ``` 4. Validate recipient numbers against the exact accepted format, such as a documented digit-only length range. 5. Validate OTP format and length according to the template's requirements. 6. Reject control characters and unexpected data before sending, while still relying on proper JSON serialization as the primary defense.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (7)

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script disables TLS certificate verification and hostname checking, and mounts a custom HTTPS adapter that accepts invalid certificates for all HTTPS requests made by the session. Because this skill transmits highly sensitive data including access keys, application secrets, phone numbers, and OTP codes to an external endpoint, a man-in-the-middle attacker could intercept or modify traffic and steal credentials or OTPs.

External Script Fetching

High
Category
Supply Chain
Content
# Send request
echo "[INFO] Sending WhatsApp OTP to $TO_NUMBER..."
RESPONSE=$(curl --noproxy "*" -s -X POST https://cpaas-rcs.cmidict.com:7081/singleSend \
  -H "Content-Type: application/json" \
  -d "$JSON_PAYLOAD")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes a Python script with shell, network, and environment-variable capabilities but does not declare any tool scope restrictions such as allowed-tools or permissions. In this context, the skill also requests highly sensitive credentials and explicitly documents insecure transport behavior, so the absence of scoped tool declarations increases the chance that an agent can access secrets or perform unintended outbound actions without clear sandbox limits.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The template and language code are fixed to a Chinese locale ("zh_CN"), which forces a specific language for outgoing messages. The file does not offer an opt-in or parameter to choose locale, and it does not clearly justify this as a region-specific tool.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This code sends access credentials, application secrets, phone number, and OTP content to a remote HTTPS endpoint. While the script includes comments and a CLI description, it does not provide a clear user-facing warning at runtime or in its docstring that sensitive data will be transmitted off-system.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The payload forces the template language to `zh_CN`, which is a natural-language locale constraint. The file does not offer any user opt-in, override, or explanation that this skill is intentionally region-specific, so it can violate language/locale policy requirements.

External Transmission

Medium
Category
Data Exfiltration
Content
# Send request
echo "[INFO] Sending WhatsApp OTP to $TO_NUMBER..."
RESPONSE=$(curl --noproxy "*" -s -X POST https://cpaas-rcs.cmidict.com:7081/singleSend \
  -H "Content-Type: application/json" \
  -d "$JSON_PAYLOAD")
Confidence
93% confidence
Finding
This script transmits highly sensitive data—including access credentials, application secret, recipient phone number, and OTP content—to an external third-party endpoint. In the context of an OTP delivery skill this is expected behavior, but it is still security-relevant because compromise, misconfiguration, or misuse of the endpoint could expose secrets or authentication codes and enable account takeover.

Static analysis

No suspicious patterns detected.