Back to skill

Security audit

Scalekit Agent Auth

Security checks for vulnerabilities and agentic risk

Overview

This skill is broadly useful for connected-service automation, but it exposes raw OAuth tokens and allows high-impact proxy/file operations with weak scoping.

Install only if you trust the Scalekit environment and the operator controlling it. Treat this as a high-authority integration skill: do not use --get-authorization in agent workflows, avoid granting broad OAuth scopes, review any proxy upload/download or write request before it runs, and prefer a version that removes raw token printing and constrains local file paths.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
tool_exec.py:358
Finding

Plaintext Disclosure of OAuth Access and Refresh Tokens

Content
View full analysis
None: """ Fetch the connected account and display OAuth access and refresh tokens. """ client = get_scalekit_client() print(f" Connection: {connection_name}") print(f" Identifier: {identifier}") print() try: response = client.actions.get_connected_account( connection_name=connection_name, identifier=identifier, ) connected_account = response.connected_account print(f" Connected Account ID: {connected_account.id}") print(f" Status: {connected_account.status}") print() tokens = connected_account.authorization_details["oauth_token"] access_token = tokens["access_token"] refresh_token = tokens["refresh_token"] print(f"{GREEN}✅ Tokens retrieved:{RESET}") print(f" Access Token: {access_token}") print(f" Refresh Token: {refresh_token}") except KeyError as e: print(f"{RED}❌ Error: Could not find token key {e}. authorization_details: {connected_account.authorization_details}{RESET}") _exit(1) except Exception as e: print(f"\n{RED}❌ Error: {e}{RESET}") _exit(1) ``` The operation is exposed through the command-line interface at `tool_exec.py:578-580` and dispatched at `tool_exec.py:777-791`. ### Technical Analysis The `--get-authorization` operation retrieves reusable OAuth credentials from a connected account and prints both the access token and refresh token directly to standard output. Standard output from a Skill can be captured in Agent context, terminal history, orchestration logs, observability systems, or conversation transcripts. Refresh tokens are particularly sensitive because they can permit long-lived ac ...[truncated 1795 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
tool_exec.py:279
Finding

Unrestricted Local File Upload and Arbitrary Output-File Overwrite

Content
View full analysis
= 400: print(f"{RED}❌ Error response:{RESET}") try: print(json.dumps(response.json(), indent=2)) except Exception: print(response.text) _exit(1) # Save to file if requested if output_file: with open(output_file, "wb") as f: f.write(response.content) print(f"{GREEN}✅ Saved {len(response.content):,} bytes to: {output_file}{RESET}") return ``` The corresponding ...[truncated 2849 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
tool_exec.py:429
Finding

Management Client Secret Sent to an Unvalidated Environment Endpoint

Content
View full analysis
str: """ Obtain a management API bearer token via OAuth2 client credentials grant. """ token_url = f"{TOOL_ENV_URL.rstrip('/')}/oauth/token" response = requests.post(token_url, data={ "grant_type": "client_credentials", "client_id": TOOL_CLIENT_ID, "client_secret": TOOL_CLIENT_SECRET, }, timeout=30) response.raise_for_status() return response.json()["access_token"] ``` The endpoint and credentials originate from environment variables loaded at `tool_exec.py:58-60`: ```python TOOL_CLIENT_ID = os.getenv('TOOL_CLIENT_ID', '') TOOL_CLIENT_SECRET = os.getenv('TOOL_CLIENT_SECRET', '') TOOL_ENV_URL = os.getenv('TOOL_ENV_URL', '') ``` ### Technical Analysis The management client secret is posted to a URL derived entirely from `TOOL_ENV_URL`. Before transmission, the code does not verify that the scheme is HTTPS, that the hostname belongs to an approved Scalekit environment, that the port is expected, or that the URL lacks embedded credentials and other ambiguous components. The client-credentials exchange itself is legitimate and necessary for connection-management operations. The vulnerability is the lack of destination validation around a highly sensitive credential. An environment configuration error or attacker-controlled environment can redirect the secret to an arbitrary server. An `http://` URL could also expose it over an unencrypted transport. ### Attack Path 1. An attacker gains the ability to influence the Skill's environment, deployment configuration, `.env` file, or launch parameters. 2. The attacker sets `TOOL_ENV_URL` to an attacker-controlled endpoint, for example `https://attacker.example`. 3. The Agent invokes connection discovery or another operation that calls `g ...[truncated 716 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
pyproject.toml:6
Finding

Non-Reproducible Installation Through Unpinned Dependencies

Content
View full analysis
=5.29.6", "python-dotenv>=1.1.1", "scalekit-sdk-python>=2.6.1", ] ``` Installation is instructed by `SKILL.md:35-39`: ```yaml install: - id: python-deps kind: exec command: "uv sync" label: "Install Python dependencies" ``` No dependency lockfile is present in the audited project. ### Technical Analysis All runtime dependencies use open-ended lower-bound constraints. Consequently, identical source code can resolve to different package versions at different times. Future releases satisfying these constraints may introduce vulnerabilities, breaking behavior, or supply-chain compromise without any change to the reviewed Skill package. The audit found no evidence that the named packages are typosquatted or currently malicious. The confirmed issue is the absence of reproducible, reviewed dependency resolution for packages that execute with the same privileges and environment access as the Skill. This is especially relevant because the dependencies can access the configured client secret, OAuth-connected operations, local files, and network resources. ### Attack Path 1. A future compromised, vulnerable, or otherwise unsafe dependency version is published and satisfies one of the open-ended version constraints. 2. A user follows the documented installation process and runs `uv sync`. 3. In the absence of a committed lockfile, the resolver selects the newer release. 4. The dependency is imported by the Skill or executes during package installation. 5. Malicious dependency code can access Skill environment variables, local files available to the process, and network connectivity. ### Impact Assessment A compromised runtime dependency executes with the same operating-system privileges as the Skill. It could read `TOOL_CL ...[truncated 301 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (22)

Tainted flow: 'url' from os.getenv (line 455, 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 · tool_exec.py (reported line 411)May include surrounding context.

python
while True:
        try:
            response = requests.get(url, params={"page_size": 30, "page_token": page_token}, headers=headers, timeout=30)
            response.raise_for_status()
            data = response.json()
        except Exception:

Tainted flow: 'token_url' from os.getenv (line 433, 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 · tool_exec.py (reported line 434)May include surrounding context.

python
Obtain a management API bearer token via OAuth2 client credentials grant.
    """
    token_url = f"{TOOL_ENV_URL.rstrip('/')}/oauth/token"
    response = requests.post(token_url, data={
        "grant_type": "client_credentials",
        "client_id": TOOL_CLIENT_ID,
        "client_secret": TOOL_CLIENT_SECRET,

Tainted flow: 'url' from os.getenv (line 455, 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 · tool_exec.py (reported line 466)May include surrounding context.

python
while True:
        try:
            response = requests.get(url, params={"page_size": page_size, "page_token": page_token}, headers=headers, timeout=30)
            response.raise_for_status()
            data = response.json()
        except Exception as e:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 27)May include surrounding context.

Copy .env.example to .env and fill in your Scalekit credentials:

bash
cp .env.example .env
env

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The documentation explicitly references --get-authorization as exposing raw OAuth tokens and indicates the system can list all configured environment connections via management APIs. Even though it says not to use that path in the normal flow, documenting token inspection and broad connection enumeration creates a credential-access and reconnaissance surface beyond a normal tool-execution skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documentation explicitly references --get-authorization as exposing raw OAuth tokens and indicates the system can list all configured environment connections via management APIs. Even though it says not to use that path in the normal flow, documenting token inspection and broad connection enumeration creates a credential-access and reconnaissance surface beyond a normal tool-execution skill.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The activation criteria are extremely broad: any request involving an external service, integration, or data source can trigger the skill, including ordinary read and write requests. Over-broad routing increases the likelihood that sensitive tasks are automatically delegated to a highly privileged integration skill, amplifying the impact of prompt injection, confused-deputy behavior, or accidental destructive actions.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 206)May include surrounding context.

md
Some providers do not have Scalekit tools for file operations. Use `--proxy-request` with `--input-file` (upload) or direct S3/CDN URL download (download). Provider-specific flows are documented below.

> ⚠️ **Proxy token expiry:** `--proxy-request` passes the stored OAuth access token directly to the provider. If the token has expired, the provider will return `401 Unauthorized`. Unlike `--execute-tool` which auto-refreshes tokens, the proxy does not. If you get a 401, the token needs to be refreshed — re-run `--generate-link` to check status; if the connection is ACTIVE but proxy still returns 401, the user must re-authorize via a new magic link to obtain a fresh token.

---

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill includes functionality to retrieve and print OAuth access and refresh tokens directly. That exceeds the stated purpose of tool discovery/execution and creates a credential-exfiltration path: anyone able to invoke this command or view its output can reuse long-lived tokens to access third-party accounts outside the intended control plane.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Printing OAuth access and refresh tokens to stdout exposes secrets to terminal history, logs, observability pipelines, and any user or process with output access. Refresh tokens are especially sensitive because they may enable durable account access long after the session ends.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
99% confidence
Finding

This line prints the OAuth access token directly, constituting explicit credential disclosure. In the context of a tool-execution skill, exposing bearer credentials is particularly dangerous because it allows bypassing normal tool mediation and direct API access to connected third-party services.

Content

Scanner excerpt · tool_exec.py (reported line 384)May include surrounding context.

python
refresh_token = tokens["refresh_token"]

        print(f"{GREEN}✅ Tokens retrieved:{RESET}")
        print(f"   Access Token:  {access_token}")
        print(f"   Refresh Token: {refresh_token}")

    except KeyError as e:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · tool_exec.py (reported line 672)May include surrounding context.

python
# Resolve identifier: env var → CLI arg → error
    if not args.identifier:
        if not TOOL_IDENTIFIER:
            print(f"{RED}❌ Identifier is required. Set TOOL_IDENTIFIER in .env or pass --identifier.{RESET}")
            _exit(1)
        else:
            args.identifier = TOOL_IDENTIFIER

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README describes automatic discovery, authorization, tool execution, and proxied API fallback across connected services without warning that the skill may read, modify, or transmit sensitive third-party user data. This omission is risky because operators may deploy or invoke the skill without understanding its broad access and action surface.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README instructs the agent to use this skill for essentially any request involving an external service, with very broad examples and no meaningful constraints. In an agent setting, this can cause over-triggering and unintended access or actions across third-party systems, increasing the chance of data exposure or unauthorized operations.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill has powerful capabilities including environment-variable access and broad networked third-party execution, but it does not declare a restrictive tool scope such as permissions or allowed-tools. That makes it easier for the skill to be invoked with broader authority than users may expect, increasing the blast radius of prompt injection, misrouting, or accidental data access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill includes file uploads, downloads, page modifications, and direct API requests, but it does not define clear confirmation or warning requirements before modifying remote data or saving files locally. In a general-purpose agent context, this can lead to unintended writes, exfiltration via downloads/uploads, or unsafe handling of user content across third-party systems.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code performs management-plane actions such as obtaining a bearer token via client credentials and enumerating application connections, which goes beyond the manifest's stated role of executing third-party tools on behalf of a user. In a skill context, this broadens privilege and increases the blast radius if the skill is misused or exposed to untrusted prompts/operators.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · SKILL.md (reported line 4)May include surrounding context.

md
---
name: openclaw-tool-executor
description: |
  Use this skill whenever the user asks for information from, or wants to take an action in, a third-party tool or service. This includes — but is not limited to — searching the web, reading or writing documents, sending messages, querying databases, managing tasks, fetching data from APIs, or interacting with any connected SaaS product (e.g. "search Exa for...", "read my Notion page", "send a Slack message", "get my Google Sheet", "create a GitHub issue", "query Snowflake", "look up a HubSpot contact"). Trigger this skill any time the user's request involves an external service, integration, or data source — even if the provider is not explicitly named. Handles OAuth and non-OAuth (API Key, Bearer, Basic) connections, tool discovery, execution, and proxy fallback via Scalekit Connect.

  ## Provider Mapping

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest states this skill is for interacting with third-party tools and services, but the code documentation in pyproject.toml says only "Add your description here." This is not merely incomplete metadata; it actively fails to represent the declared intent of the skill and conflicts with the documented purpose auditors and developers would rely on.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: protobuf has 9 known advisory(ies) (CVE-2026-0994 (protobuf affected by a JSON recursion depth bypass); CVE-2022-1941 (protobuf-cpp and protobuf-python have potential Denial of Service issue); CVE-2025-4565 (protobuf-python has a potential Denial of Service issue) +6 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: pytest has 2 known advisory(ies) (CVE-2025-71176 (pytest has vulnerable tmpdir handling); CVE-2025-71176 (pytest has vulnerable tmpdir handling)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.