Back to skill

Security audit

Skywork Excel

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for Skywork spreadsheet/report generation, but it sends user files to a remote service and contains credential and file-write handling flaws that users should review before installing.

Install only if you are comfortable sending selected spreadsheets, PDFs, images, CSVs, and prompts to Skywork's backend. Use a scoped/rotatable API key, do not print or paste it into logs or chats, avoid overriding --base-url, and run the skill in a workspace where downloaded files and logs cannot overwrite important user files.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/excel_api_client.py:520
Finding

API Key Disclosure Through Unrestricted Backend URL Override

Content
View full analysis
env var if api_key is not None: self.api_key = api_key else: self.api_key = _get_api_key_auto() self.timeout = timeout if not self.api_key: raise ValueError("SKYWORK_API_KEY is required (set env or pass api_key=)") self._headers = {"Authorization": f"Bearer {self.api_key}"} ``` ```python def _build_request( self, url: str, method: str = "GET", headers: Optional[dict] = None, data: Optional[bytes] = None ) -> urllib.request.Request: """Build a urllib request with merged headers.""" request_headers = {**self._headers} if headers: request_headers.update(headers) return urllib.request.Request(url=url, data=data, headers=request_headers, method=method) def _urlopen( self, request: urllib.request.Request, timeout: Optional[int] = None ): """Open a URL request with configured timeout.""" return urllib.request.urlopen(request, timeout=timeout or self.timeout) ``` ```python parser.add_argument("--base-url", default=SKYWORK_GATEWAY_URL, help="Backend service URL") ``` ### Technical Analysis The client accepts an unrestricted `--base-url` value while `_build_request()` automatically attaches the Skywork Bearer credential to every request. There is no scheme validation, hostname allowlist, origin validation, or redirect-target validation before transmitting the credential. Although sending the API key to the declared Skywork service is necessary for the Skill, allowing the same credential to be sent to an arbitrary caller-selected destination exceeds minimum privilege. The initial health-check request is sufficient to disclose the credential; successful ...[truncated 1053 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/excel_api_client.py:581
Finding

Arbitrary File Overwrite Through Server-Controlled Output Filename

Content
View full analysis
None: req = self._build_request(f"{self.base_url}/api/download/{file_id}") with self._urlopen(req, timeout=60) as resp: content = resp.read() with open(save_path, "wb") as f: f.write(content) print(f"💾 Downloaded: {save_path} ({len(content):,} bytes)") ``` The server-controlled name is directly combined with the local output directory: ```python for f in output_files: save_path = os.path.abspath(f"{final_output_dir}/{f['name']}") oss_url = f.get('oss_url', '') try: client.download_file(f["file_id"], save_path) write_log(f" ✅ {f['name']}") write_log(f" 📁 Local: {save_path}") ``` ### Technical Analysis The backend controls `f["name"]`, but the client does not reject absolute paths, parent-directory components, path separators, or symbolic-link targets. Calling `os.path.abspath()` only normalizes the path; it does not ensure that the result remains inside `final_output_dir`. For example, a backend-provided filename such as `../../.bashrc` can resolve outside the output ...[truncated 1270 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/excel_api_client.py:54
Finding

Arbitrary File Truncation Through Unsafe Log Path Handling

Content
View full analysis
str: """Initialize log file for this session.""" global _LOG_FILE if log_path: _LOG_FILE = log_path else: if not session_id: session_id = str(uuid.uuid4()).replace('-', '_') _LOG_FILE = f"/tmp/excel_run_{session_id}.log" # Clear previous run open(_LOG_FILE, "w").close() return _LOG_FILE ``` ```python if log_path: global _LOG_FILE _LOG_FILE = log_path open(_LOG_FILE, "w").close() else: _init_log_file(run_session_id) ``` ```python parser.add_argument("--log-path", default="", help="Path to save progress log (default: /tmp/excel_run_.log)") ``` ### Technical Analysis The caller can supply an arbitrary `--log-path`, and the file is immediately opened in `"w"` mode without path restriction, ownership validation, file-type validation, or symlink protection. Consequently, any existing file writable by the Skill process can be truncated. The default path is also created through a conventional path-based open operation rather than an atomic secure temporary-file API. Where a predictable or attacker-known path is used in a shared `/tmp` directory, another local user may pre-create a symbolic link pointing to a victim file. This behavior is not a legitimate persistence mechanism; it is transient progress logging. No scheduled task or service installation was found. Nevertheless, the implementation grants the logging feature unnecessary filesystem reach. ### Attack Path **Caller-controlled path scenario:** 1. An attacker influences the CLI arguments and supplies `--log-path` pointing to a sensitive writable file. 2. Task initialization calls `open(_L ...[truncated 822 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
references/apikey-fetch.md:73
Finding

API Key Exposed by Verification Instructions

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (17)

Vague Triggers

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The upload-based activation rule is ambiguous because it suggests triggering on Excel/CSV/PDF/Image uploads without clearly constraining file purpose, sensitivity, or user consent. That ambiguity can lead to automatic handling of uploaded documents by a remote service when the user may only want local assistance, expanding exposure of potentially confidential content.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill explicitly instructs passing user queries as-is and sending file paths to a backend that will read the files, but it does not present a clear user-facing warning that uploaded files and prompts are transmitted to an external service. This undermines informed consent and can expose sensitive business, financial, or personal documents to a third party without adequate disclosure.

Content

No source excerpt is available for this finding.

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · references/apikey-fetch.md (reported line 60)May include surrounding context.

Option B — Claude Code settings

Add the variable to ~/.claude/settings.json:

json
{

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · references/apikey-fetch.md (reported line 94)May include surrounding context.

Option B — Claude Code settings

Add the variable to ~/.claude/settings.json:

json
{

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · references/apikey-fetch.md (reported line 99)May include surrounding context.

Option B — Claude Code settings

Add the variable to ~/.claude/settings.json:

json
{

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes a Python client that uses network access, writes logs and output files, and consumes an API key, but it declares no explicit tool scope or allowed-tools policy. That makes the effective privileges implicit and broad, increasing the chance of unintended execution with file, network, and secret access beyond what users or the platform may expect.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The upload-based activation rule is ambiguous because it suggests triggering on Excel/CSV/PDF/Image uploads without clearly constraining file purpose, sensitivity, or user consent. That ambiguity can lead to automatic handling of uploaded documents by a remote service when the user may only want local assistance, expanding exposure of potentially confidential content.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation sets zh-CN as the default language, which imposes a locale choice unless the operator actively changes it. This can violate language/locale policy because the skill does not make neutral language selection the default or require user opt-in before choosing Chinese.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

The guide encourages creating/copying an API key and then storing it in persistent runtime configuration, which establishes long-lived credential presence on disk and across sessions. Session persistence of secrets is not inherently malicious, but without minimization or expiration guidance it increases the window for theft from local compromise, backups, or accidental sharing.

Content

Scanner excerpt · references/apikey-fetch.md (reported line 15)May include surrounding context.

md
- Log in with your Skywork account
- Open account / Settings / API Key (**https://skywork.ai/?openApiKeySetting=1**)
- Create or copy your **API key**

If your organization uses a separate console or test environment, use the URL and credentials your team provides.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The guide explicitly tells users to place a live API key into persistent configuration and to print it with echo, but it gives no warning about shell history, screen sharing, terminal logging, or accidental disclosure in config files. While this is common operational guidance, omitting secret-handling precautions increases the chance of credential exposure and downstream unauthorized API use.

Content

No source excerpt is available for this finding.

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
55% confidence
Finding

Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.

Content

Scanner excerpt · scripts/excel_api_client.py (reported line 24)May include surrounding context.

python
if not client.health_check():
        raise RuntimeError("Service not available or api key invalid")

    file_ids = [client.upload_file("data.xlsx")]
    outputs = client.run_agent("Create a summary report", file_ids=file_ids)

    for f in outputs:

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The client is designed to upload arbitrary local files to a remote backend service, creating a real data-exfiltration path if users or higher-level agents pass sensitive files without clear consent. In this skill context, the risk is elevated because the skill explicitly triggers on Excel/CSV/PDF/Image uploads and encourages passing the user's original query directly, making accidental transmission of confidential business data more likely.

Content

Scanner excerpt · scripts/excel_api_client.py (reported line 267)May include surrounding context.

python
file_ids = []
        total = len(file_paths)
        for i, file_path in enumerate(file_paths):
            file_id = self.upload_file(file_path)
            file_ids.append(file_id)
            # Add delay between uploads (except after the last one)
            if i < total - 1 and delay_between > 0:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The client sets the agent request language to "zh-CN" by default, which imposes a specific locale unless the caller explicitly overrides it. This is a natural-language policy concern because the skill does not first ask the user for language preference or make the default locale clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The command-line interface assigns "zh-CN" as the default for --lang/--language, so users who do not notice the option will have interactions forced into Chinese. This violates the language/locale policy criteria because no opt-in or preference selection is required.

Content

No source excerpt is available for this finding.

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The CLI path uploads user-supplied local files directly to the backend, again creating a concrete exfiltration channel for spreadsheet and document contents. In an agent skill intended for data analysis and file conversion, this is particularly relevant because users may provide highly sensitive financial, operational, or personal datasets under the assumption of local-only processing.

Content

Scanner excerpt · scripts/excel_api_client.py (reported line 547)May include surrounding context.

python
write_log(f"   - {file_path}")
        for file_path in args.files:
            try:
                file_id = client.upload_file(file_path)
                file_ids.append(file_id)
                write_log(f"   ✅ {os.path.basename(file_path)} -> file_id={file_id}")
            except Exception as e:

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The primary command example uses --language zh-CN, which may steer implementations toward Chinese output even when the user has not requested that locale. Although the text says to match the user's language, the example still normalizes one specific language choice.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation says to use heartbeat lines only as an internal liveness signal and explicitly says not to output raw heartbeat lines to the user. However, the required monitor command includes grep -E "\[HEARTBEAT\]" "$EXCEL_LOG" | tail -1, which prints a raw heartbeat line as part of the command output, directly conflicting with that instruction.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.