Back to skill

Security audit

Openclaw Aligenie Push

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent notification purpose, but its documented deployment exposes a credentialed voice-broadcast service with weak transport, authentication, and persistence controls.

Review carefully before installing or deploying. Do not expose the relay publicly as documented; require HTTPS, authenticate callers, restrict source networks, avoid sending AppSecret from the client on every push, and use an audited included server artifact before enabling startup persistence.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
push.py:105
Finding

Aligenie credentials and private broadcast content are transmitted over plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: push.py:105-122; insecure endpoint configuration is documented in SKILL.md:42-49 and DEPLOY.md:98-107
Vulnerability Type: Sensitive information transmitted without transport encryption
Risk Level: Critical

Vulnerable Code

python
payload = {
    "appId": _app_id or "",
    "appSecret": _app_secret or "",
    "openId": _open_id,
    "text": text,
    "deviceType": device_type,
}

_LOGGER.info(f"[Aligenie Push] 发送播报请求: {text[:50]}...")

try:
    loop = asyncio.get_event_loop()
    response = await loop.run_in_executor(
        None,
        lambda: requests.post(
            _push_server,
            json=payload,
            headers={"Content-Type": "application/json"},
            timeout=15,
        )
    )

The documented configuration explicitly uses plaintext HTTP:

text
ALIGENIE_PUSH_SERVER=http://你的云服务器公网IP:58472/push
ALIGENIE_APP_ID=2026032918608
ALIGENIE_APP_SECRET=审批通过后获取
ALIGENIE_DEVICE_OPEN_ID=天猫精灵设备openId

Technical Analysis

The client sends the Aligenie AppSecret, AppId, device openId, and full broadcast message to a configurable relay server. The implementation does not require HTTPS, validate the URL scheme, pin a trusted relay identity, or authenticate the server at the application layer.

The deployment guide instructs operators to use a public IP over HTTP, despite the architecture diagram describing the connection as HTTPS. Consequently, the intended deployment exposes credentials and potentially private notification content to passive network monitoring and active man-in-the-middle attacks.

Sending the AppSecret to the relay on every push also exceeds the minimum data transfer necessary. The relay can retain the credentials securely and accept an independently authenticated push request that contains only the message and an authorized device alias.

Attack Path

  1. The operator follows the documented configuration and uses http://public-server:58472/push ...[truncated 1020 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require an https:// relay URL and reject plaintext HTTP except for explicitly enabled loopback-only development configurations.
  2. Deploy the relay behind a correctly configured TLS reverse proxy with a valid certificate and modern TLS settings.
  3. Keep the Aligenie AppSecret exclusively on the relay server. Do not include it in routine client push payloads.
  4. Authenticate client-to-relay requests with a separate, revocable credential or signed request protocol.
  5. Bind each client identity to a server-side allowlist of device identifiers instead of accepting arbitrary openId values.
  6. Protect configuration secrets with an operating-system secret store or restricted environment injection rather than plaintext workspace documentation.
  7. Rotate the AppSecret and relay credentials after migrating from HTTP because previously transmitted credentials must be considered exposed.
  8. Correct SKILL.md and DEPLOY.md so all production examples use HTTPS.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
push-server.py:123
Finding

Public push endpoint lacks authentication, authorization, and abuse controls

Content
View full analysis

Vulnerability Details

File Location: push-server.py:123-168; public exposure is directed by DEPLOY.md:23-29
Vulnerability Type: Unauthenticated externally reachable sensitive operation
Risk Level: Critical

Vulnerable Code

python
@app.route("/push", methods=["POST"])
def handle_push():
    """
    接收 OpenClaw 的推送请求

    请求体:
    {
        "appId": "2026032918608",
        "appSecret": "xxx",
        "openId": "ou_xxx",
        "text": "要播报的内容",
        "deviceType": "speaker"
    }
    """
    try:
        data = request.get_json()
        if not data:
            return jsonify({"success": False, "error": "请求体为空"}), 400

        app_id = data.get("appId") or os.environ.get("ALIGENIE_APP_ID", "")
        app_secret = data.get("appSecret") or os.environ.get("ALIGENIE_APP_SECRET", "")
        open_id = data.get("openId") or os.environ.get("ALIGENIE_DEVICE_OPEN_ID", "")
        text = data.get("text", "").strip()
        device_type = data.get("deviceType", "speaker")

        if not text:
            return jsonify({"success": False, "error": "text 不能为空"}), 400
        if not open_id:
            return jsonify({"success": False, "error": "openId 不能为空"}), 400

        # 优先用请求体里的凭证,否则用环境变量
        _app_id = app_id or os.environ.get("ALIGENIE_APP_ID", "")
        _app_secret = app_secret or os.environ.get("ALIGENIE_APP_SECRET", "")

        if not _app_id or not _app_secret:
            return jsonify({
                "success": False,
                "error": "AppId 或 AppSecret 未配置"
            }), 400

        # 获取 token 并推送
        access_token = get_access_token(_app_id, _app_secret)
        if not access_token:
            return jsonify({"success": False, "error": "获取 access_token 失败"}), 500

        result = push_message(access_token, open_id, text, device_type)

The service listens on every interface by default:

python
parser.add_argument("--host", default="0.0.0.0", help="监听地址 (默认: 0.0.0.0)")

The deployment guide di ...[truncated 2082 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require strong client authentication for /push, such as mutual TLS or HMAC-signed requests with a timestamp and nonce.
  2. Implement authorization that binds each authenticated client to specific server-side device aliases.
  3. Do not accept Aligenie application credentials from request bodies.
  4. Do not allow arbitrary client-supplied openIds unless explicitly authorized.
  5. Restrict the cloud firewall to trusted source addresses or private-network/VPN access instead of 0.0.0.0/0.
  6. Add per-client and global rate limits, request quotas, replay detection, and abuse monitoring.
  7. Limit request body size and validate maximum message length.
  8. Restrict deviceType to an explicit allowlist such as speaker and screen.
  9. Return generic errors to clients and keep detailed diagnostics in protected logs.
  10. Prefer binding the application directly to loopback behind an authenticated TLS reverse proxy.

T09 · Insecure Skill Coding Practices

Error
Location
push-server.py:57
Finding

OAuth client secret is placed in a GET query string

Content
View full analysis

Vulnerability Details

File Location: push-server.py:57-65
Vulnerability Type: Credential exposure through URL query parameters
Risk Level: High

Vulnerable Code

python
resp = requests.get(
    TOKEN_URL,
    params={
        "grant_type": "client_credentials",
        "client_id": app_id,
        "client_secret": app_secret,
    },
    timeout=10,
)

Technical Analysis

The OAuth client secret is supplied through params on an HTTP GET request. The requests library serializes these values into the URL query string. HTTPS encrypts the request while in transit, but does not prevent the full URL from being recorded by the destination service, reverse proxies, gateways, monitoring agents, debugging tools, browser-like diagnostics, or request logs.

Secrets should not be placed in URLs because URL retention and propagation are typically broader than request-body or Authorization-header retention. This design unnecessarily increases the number of infrastructure components that may store the AppSecret.

Attack Path

  1. The relay requests an OAuth token.
  2. requests.get(..., params=...) creates a URL containing client_secret.
  3. An upstream proxy, provider access log, network monitoring product, or diagnostic trace records the complete URL.
  4. An attacker or unauthorized operator obtains access to the retained logs.
  5. The attacker extracts the client secret and attempts to request access tokens or perform other operations permitted to the application identity.

Impact Assessment

Disclosure compromises the Aligenie application credential. An attacker may be able to obtain access tokens and exercise API privileges assigned to the application until the secret is revoked or rotated.

The exact API scope depends on provider configuration, but the affected trust boundary is the entire Aligenie application rather than a single push request.

Remediation
View remediation

Remediation Suggestions

  1. Use the provider-supported OAuth token POST flow.
  2. Place client credentials in the request body or an Authorization header according to the provider's documented authentication method.
  3. Never include secrets in URL query parameters.
  4. Configure proxies, application monitoring, and HTTP clients to redact Authorization headers and credential fields.
  5. Avoid logging complete OAuth responses because failure responses may contain sensitive diagnostic data.
  6. Rotate the existing AppSecret if token requests may already have passed through URL-logging infrastructure.

T08 · Insecure Dependencies

Warning
Location
DEPLOY.md:55
Finding

Deployment relies on unpinned dependencies and an unaudited persistent Java artifact

Content
View full analysis

Vulnerability Details

File Location: DEPLOY.md:55-82; unpinned installation instructions also appear in push-server.py:6-7 and push.py:5-6
Vulnerability Type: Uncontrolled third-party and external executable supply chain
Risk Level: Medium

Vulnerable Configuration

text
依赖: flask, requests
安装: pip install flask requests

The deployment instructions execute an external Java artifact that is not included in the audited project:

powershell
cd C:\temp
java -cp . PushServer --port 58472

They then configure that artifact to execute after every system startup:

powershell
$action = New-ScheduledTaskAction -Execute 'java' -Argument '-cp C:\temp PushServer --port 58472'
$trigger = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName 'AligeniePushServer' -Action $action -Trigger $trigger -Settings $settings

Technical Analysis

The Python dependencies are installed without pinned versions or integrity hashes. A later installation may therefore resolve to materially different code than the versions reviewed or tested.

The deployment guide states that PushServer.java and PushServer.class were uploaded separately, but neither artifact exists in the audited project. Its network, credential-handling, logging, authentication, and execution behavior cannot be verified from the supplied source. The task scheduler subsequently grants that unaudited artifact persistent execution across server reboots.

Startup persistence is operationally understandable for a server, but applying it to an artifact outside the review and build chain increases supply-chain impact. If the class file is replaced, the replacement executes automatically under the scheduled task's security context.

Attack Path

  1. An operator installs the latest available Flask and Requests packages without a lock file or hash verification, or receive ...[truncated 947 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin all Python dependencies to reviewed versions in a lock file.
  2. Require cryptographic hashes for installed packages and use a trusted package index.
  3. Include the Java source code in the project and review it as part of the same audit.
  4. Build the Java class reproducibly from reviewed source rather than distributing a precompiled class separately.
  5. Publish and verify a cryptographic digest or signed release for every deployed artifact.
  6. Run the service under a dedicated, non-administrative account with minimal filesystem and network permissions.
  7. Protect the deployment directory from modification by unprivileged users.
  8. Configure startup only after verifying the artifact and use a service manager with restricted privileges and auditable logs.
  9. Add dependency vulnerability scanning and a controlled update process.

T09 · Insecure Skill Coding Practices

Warning
Location
mock-server.py:41
Finding

Mock server exposes and logs device identifiers and complete message content

Content
View full analysis

Vulnerability Details

File Location: mock-server.py:41-52; network binding is configured at mock-server.py:79-92
Vulnerability Type: Sensitive data exposure in logs and unsafe default test-server binding
Risk Level: Medium

Vulnerable Code

python
text = data.get("text", "")
open_id = data.get("openId", "")
device_type = data.get("deviceType", "speaker")
app_id = data.get("appId", "")

_LOGGER.info("=" * 50)
_LOGGER.info("📢 [MOCK] 收到推送请求(未真实发送)")
_LOGGER.info(f"   AppId:   {app_id}")
_LOGGER.info(f"   OpenId:  {open_id}")
_LOGGER.info(f"   Device:  {device_type}")
_LOGGER.info(f"   Text:    {text}")
_LOGGER.info("=" * 50)

The test server listens on every network interface by default:

python
def main():
    parser = argparse.ArgumentParser(description="Aligenie Push Mock Server(本地测试用)")
    parser.add_argument("--port", type=int, default=5000)
    parser.add_argument("--host", default="0.0.0.0")
    args = parser.parse_args()

    print("=" * 60)
    print("🧪 Aligenie Push Mock 服务器(本地测试)")
    print("   不会真实调用阿里云 API,仅打印日志")
    print(f"   监听: http://{args.host}:{args.port}")
    print("=" * 60)

    server = HTTPServer((args.host, args.port), PushHandler)
    _LOGGER.info(f"服务器启动,监听 {args.host}:{args.port}")
    server.serve_forever()

Technical Analysis

The mock server records the full device openId and message content at information level. Broadcast messages may include reminders, schedules, task status, or other private information. Logs can persist longer than the originating request and may be copied into terminals, CI logs, support archives, or centralized logging systems.

Although described as a local test server, it binds to 0.0.0.0 by default and uses unencrypted HTTP without authentication. Other hosts on the same network can therefore submit data to it, and operators may accidentally send real credentials and message content to an exposed testing process. The client payload also contains appSecret, e ...[truncated 931 chars]

Remediation
View remediation

Remediation Suggestions

  1. Bind the mock server to 127.0.0.1 by default.
  2. Require an explicit command-line option before permitting non-loopback binding.
  3. Do not log complete openIds or message text; redact or hash identifiers and truncate sanitized test content.
  4. Ensure the client uses dummy credentials when connecting to a mock service.
  5. Remove appSecret from mock requests entirely.
  6. Add a request-body size limit and basic authentication if shared-network testing is required.
  7. Mark mock output as sensitive and configure short log retention.
  8. Document that production data and credentials must never be sent to the mock endpoint.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (19)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · push-server.py (reported line 57)May include surrounding context.

python
return _access_token_cache["token"]

    try:
        resp = requests.get(
            TOKEN_URL,
            params={
                "grant_type": "client_credentials",

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · push-server.py (reported line 92)May include surrounding context.

python
device_type: "speaker"=无屏音箱, "screen"=带屏设备
    """
    try:
        resp = requests.post(
            PUSH_API_URL,
            headers={
                "Authorization": f"Bearer {access_token}",

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

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The code sends app credentials, device identifiers, and message content to a URL taken from configuration without validating or constraining the destination. If an attacker can influence ALIGENIE_PUSH_SERVER or the local TOOLS.md file, they can redirect sensitive data to an arbitrary endpoint, causing credential exfiltration and unauthorized message delivery. In this skill context, the function is explicitly designed to push notifications externally, so destination integrity is critical and the unvalidated endpoint makes the issue more dangerous.

Content

Scanner excerpt · push.py (reported line 117)May include surrounding context.

python
loop = asyncio.get_event_loop()
        response = await loop.run_in_executor(
            None,
            lambda: requests.post(
                _push_server,
                json=payload,
                headers={"Content-Type": "application/json"},

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The documented behavior says the skill pushes messages to Tmall Genie, but the implementation reportedly runs a local mock HTTP service and returns simulated IDs instead of performing the claimed action. This mismatch is dangerous because users and operators may trust it with real notifications or secrets under false assumptions, while it also exposes a generic network service surface not reflected in the stated purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The deployment guide explicitly instructs exposing TCP port 58472 to 0.0.0.0/0 and describes a publicly reachable push service, but provides no authentication, TLS, IP allowlisting, or warning about the risks. In the skill context, this service appears to trigger voice push notifications to a household device, so an exposed endpoint could be abused by Internet attackers to send unauthorized messages, spam, or probe the server for further compromise.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill advertises network- and environment-dependent behavior but does not declare any explicit tool scope or permission boundaries. In practice, this weakens reviewability and allows the skill to access external services and secrets without clear user-facing constraints, which is risky for a message-pushing integration that may handle sensitive content.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trigger description includes broad activation conditions such as any situation where a notification or completion status might be sent, not just explicit user commands. In a skill that transmits content to an external server/device, broad triggers increase the chance of unintended exfiltration of private task data or autonomous actions the user did not specifically authorize at that moment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The configuration shows message content will be sent to an external push server and onward to a device, but the skill description does not warn users that their text leaves the local agent boundary. This is especially risky because users may include sensitive reminders, work status, or personal information in messages that are then transmitted over the network and spoken aloud on a device.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The mock server logs message text, OpenId, AppId, and device type directly from incoming requests. Even in a local test utility, these fields can contain personal identifiers and private message content, so storing them in logs creates an avoidable privacy exposure if logs are retained, shared, or accessed by other users on the system.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · DEPLOY.md (reported line 117)May include surrounding context.

md
# 阿里云 OAuth2 获取 access_token 的地址
TOKEN_URL = "https://oauth.taobao.com/token"
# Aligenie 消息推送 API 地址
PUSH_API_URL = "https://api.aligenie.com/v1.0/push/pushMsg"

# 内存缓存 token(避免每次请求都重新认证)
_access_token_cache = {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · push-server.py (reported line 38)May include surrounding context.

python
# 阿里云 OAuth2 获取 access_token 的地址
TOKEN_URL = "https://oauth.taobao.com/token"
# Aligenie 消息推送 API 地址
PUSH_API_URL = "https://api.aligenie.com/v1.0/push/pushMsg"

# 内存缓存 token(避免每次请求都重新认证)
_access_token_cache = {

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · push-server.py (reported line 92)May include surrounding context.

python
device_type: "speaker"=无屏音箱, "screen"=带屏设备
    """
    try:
        resp = requests.post(
            PUSH_API_URL,
            headers={
                "Authorization": f"Bearer {access_token}",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The service transmits user-provided message content and a device identifier to a third-party provider without any visible consent, caller authentication, or ownership verification. In the context of a voice-assistant push skill, this increases privacy and abuse risk because arbitrary text can be broadcast to a user's device.

Content

No source excerpt is available for this finding.

Tainted flow: 'text' from requests.get (line 145, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
89% confidence
Finding

Untrusted request content is forwarded directly to an external voice/push service with no authentication, authorization, rate limiting, or content policy enforcement shown on the /push endpoint. This enables misuse of the service to send arbitrary spoken messages to a target device, creating spam, harassment, or social-engineering risk.

Content

Scanner excerpt · push-server.py (reported line 92)May include surrounding context.

python
device_type: "speaker"=无屏音箱, "screen"=带屏设备
    """
    try:
        resp = requests.post(
            PUSH_API_URL,
            headers={
                "Authorization": f"Bearer {access_token}",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The /push endpoint accepts appId and appSecret directly from incoming requests and uses them for external authentication, which is a serious credential-handling weakness. An attacker can abuse the server as a credential relay, inject their own secrets, or cause sensitive credentials to be exposed through logs, monitoring, or downstream failures.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code includes natural-language descriptions, usage text, and error/help messages entirely in Chinese, which effectively forces a specific language for users without offering any language or locale choice. Under the policy, language constraints should be opt-in or clearly justified as region-specific, and no such opt-in or justification appears in this file.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · push.py (reported line 117)May include surrounding context.

python
loop = asyncio.get_event_loop()
        response = await loop.run_in_executor(
            None,
            lambda: requests.post(
                _push_server,
                json=payload,
                headers={"Content-Type": "application/json"},

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The natural-language documentation and user-facing messages in this file are Chinese-only, which can impose a language constraint on users without opt-in. The file does not state that the skill is region-specific or provide an alternative language option.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The file's natural-language descriptions, help text, and comments are presented in Chinese only. This may impose a language choice on users or operators without offering an alternative language or explicit opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.