Back to skill

Security audit

spreadsheet-analysis

Security checks across malware telemetry and agentic risk

Overview

The skill appears to provide the advertised spreadsheet analysis, but review is warranted because a configurable server setting can redirect spreadsheet text and the API key, and crafted XLSX files could exhaust local resources.

Install only if you trust the configured API destination and are comfortable sending parsed spreadsheet contents to the platform. Keep AI_SKILLS_API_URL unset or pinned to the intended HTTPS service, protect the API key environment, and avoid analyzing untrusted or unusually compressed XLSX files until archive-expansion limits are added.

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

Warning
Location
references/HTTP-REQUESTS.md:3
Finding
Configurable API Origin Can Expose Bearer Credentials and Spreadsheet Data## Vulnerability Details **File Location**: `references/HTTP-REQUESTS.md`, line 3 **Vulnerability Type**: Unrestricted API endpoint configuration and credential forwarding **Risk Level**: Medium ### Vulnerable Configuration ```text ${AI_SKILLS_API_URL:-https://ai-skills.open-idea.net}/api/v1/spreadsheet-analysis/spreadsheet.analyze Authorization: Bearer ${SPREADSHEET_ANALYSIS_API_KEY} Content-Type: application/json ``` The documented request sends the extracted spreadsheet document to a base URL controlled through `AI_SKILLS_API_URL`, while attaching the spreadsheet-analysis bearer credential. ### Technical Analysis The API base URL is configurable through an environment variable, but the instructions do not require HTTPS, validate the destination hostname, or define an allowlist of trusted origins. The bearer credential is attached to requests made using this configurable URL. If an attacker can influence the Agent or Gateway environment, the attacker can set `AI_SKILLS_API_URL` to a server under their control. Subsequent analysis, question, comparison, or export requests may then disclose the API key and request content to that server. This is an insecure configuration pattern rather than evidence of intentional credential theft. The default endpoint uses HTTPS and points to the declared service, but the unrestricted override weakens that protection. ### Attack Path 1. An attacker obtains the ability to alter the environment or deployment configuration used by the Skill. 2. The attacker sets `AI_SKILLS_API_URL` to an attacker-controlled HTTP or HTTPS endpoint. 3. A user invokes spreadsheet analysis, question answering, comparison, or export. 4. The Agent follows the documented request procedure and sends an `Authorization: Bearer` header to the configured endpoint. 5. The attacker receives the API credential and any spreadsheet-derived content included in the request. 6. The stolen credential may be reused aga ...[truncated 764 chars]
Remediation
## Remediation Suggestions 1. Pin production requests to `https://ai-skills.open-idea.net` unless endpoint customization is an explicit operational requirement. 2. If customization is required, parse and validate the URL before sending any request: - Require the `https` scheme. - Allowlist exact trusted hostnames and ports. - Reject embedded user information, malformed hosts, IP-literal bypasses, and unapproved subdomains. 3. Do not attach the `Authorization` header until the final request origin has passed validation. 4. Disable cross-origin redirects or revalidate every redirect target before forwarding credentials. 5. Separate development credentials from production credentials and scope keys to the minimum necessary product permissions. 6. Document the endpoint override as security-sensitive configuration and protect it from untrusted process, project, and user-level environment changes. 7. Rotate the API key if requests may already have been sent to an untrusted endpoint.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/extract_spreadsheet.py:6
Finding
XLSX Archive Expansion Can Cause Local Resource Exhaustion## Vulnerability Details **File Location**: `scripts/extract_spreadsheet.py`, lines 6-44 **Vulnerability Type**: Unbounded archive decompression and XML tree materialization **Risk Level**: Medium ### Vulnerable Code ```python path = sys.argv[1]; ext = os.path.splitext(path)[1].lower() if not os.path.isfile(path) or os.path.getsize(path) > 10 * 1024 * 1024: raise SystemExit("Spreadsheet does not exist or exceeds 10 MB.") rows = [] ``` ```python with zipfile.ZipFile(path) as z: ns = {"m":"http://schemas.openxmlformats.org/spreadsheetml/2006/main", "r":"http://schemas.openxmlformats.org/officeDocument/2006/relationships"} shared = [] if "xl/sharedStrings.xml" in z.namelist(): sr = ET.fromstring(z.read("xl/sharedStrings.xml")); shared = ["".join(t.text or "" for t in si.iter("{http://schemas.openxmlformats.org/spreadsheetml/2006/main}t")) for si in sr] wb = ET.fromstring(z.read("xl/workbook.xml")); rels = ET.fromstring(z.read("xl/_rels/workbook.xml.rels")) relmap = {x.attrib["Id"]: x.attrib["Target"] for x in rels} for sheet in wb.find("m:sheets", ns): name = sheet.attrib.get("name", "Sheet"); target = relmap[sheet.attrib["{http://schemas.openxmlformats.org/officeDocument/2006/relationships}id"]] target = target.lstrip("/"); target = target if target.startswith("xl/") else "xl/" + target root = ET.fromstring(z.read(target)) for row in root.findall(".//m:sheetData/m:row", ns): vals = [] for c in row.findall("m:c", ns): ref = c.attrib.get("r", "?"); value = c.findtext("m:v", default="", namespaces=ns) if c.attrib.get("t") == "s" and value.isdigit(): value = shared[int(value)] elif c.attrib.get("t") == "inlineStr": value = "".join(t.text or "" for t in c.findall(".//m:t", ns)) column = re.sub(r'\d+$', '', ref) if value != "": vals.append(f"{co ...[truncated 2959 chars]
Remediation
## Remediation Suggestions 1. Inspect every `ZipInfo` entry before extraction and enforce: - A maximum number of archive members. - A maximum uncompressed size per member. - A maximum aggregate uncompressed size. - A conservative maximum compression ratio. 2. Reject encrypted members, unexpected archive structures, duplicate critical entries, and unsupported compression methods. 3. Replace `z.read()` and full-tree `ET.fromstring()` processing with bounded streaming reads and `ElementTree.iterparse()` where practical. 4. Enforce row, cell, character, and XML-element limits during parsing rather than after all rows have been retained. 5. Stop parsing immediately once any configured limit is reached. 6. Avoid retaining the complete workbook and output simultaneously; emit or process bounded segments incrementally. 7. Run extraction in an isolated subprocess with memory, CPU, execution-time, and file-descriptor limits. 8. Add regression tests using high-compression XLSX archives, oversized shared-string tables, oversized worksheets, and excessive XML element counts.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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

VirusTotal

VirusTotal findings are pending for this skill version.

View on VirusTotal

Static analysis

No suspicious patterns detected.