Back to skill

Security audit

Xihu Hiring

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate recruiting-report purpose, but it handles sensitive candidate data with unsafe temporary files and generates spreadsheets from untrusted form data without neutralizing formulas.

Install only in a controlled environment where Feishu bot access, candidate PII, /tmp contents, and generated workbooks are protected. Before routine use, the publisher should move temporary files into a private per-run directory with restrictive permissions and cleanup, pin dependencies, and sanitize all workbook text fields that start with spreadsheet formula markers.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
references/build-excel.md:183
Finding

Spreadsheet Formula Injection Through Untrusted Recruitment Data

Content
View full analysis

Vulnerability Details

File Location: references/build-excel.md:183-204
Vulnerability Type: Spreadsheet formula injection
Risk Level: High

Vulnerable Code

python
# Sheet 1
ws1 = wb.create_sheet("审批总览")
ws1.append(SHEET1_HEADERS)
for idx, r in enumerate(rows, 1):
    ws1.append([
        idx, r.get("serial",""), r.get("status",""), r.get("submit_time",""), r.get("end_time",""),
        r.get("name",""), r.get("position",""), r.get("phone",""), r.get("email",""),
        r.get("school",""), r.get("prior_jobs",""), r.get("cv",""),
        r.get("node_resume_screen",""), r.get("node_r1",""), r.get("node_r2",""),
        r.get("node_r3",""), r.get("node_handle","")
    ])
_style_header(ws1, SHEET1_HEADERS, SHEET1_WIDTHS)
ws1.freeze_panes = "A2"

# Sheet 2
ws2 = wb.create_sheet("节点流转明细")
ws2.append(SHEET2_HEADERS)
for r in rows:
    for t in r.get("tasks", []):
        ws2.append([
            r.get("name",""), r.get("position",""), r.get("serial",""),
            t.get("node_name",""), t.get("type",""), t.get("status",""),
            t.get("start",""), t.get("end",""), t.get("approver_oid8","")
        ])

Technical Analysis

Values originating from Feishu approval forms and workflow tasks are written directly into workbook cells without being normalized as literal text. Spreadsheet applications interpret strings beginning with formula indicators such as =, +, -, or @ as formulas.

An applicant or another party able to control a recruitment form field could place a formula in a field such as the name, position, school, employment history, or email address. The generated workbook would preserve that input as an active formula rather than harmless text.

Formula behavior varies by spreadsheet client and security configuration. Possible payloads include deceptive hyperlinks, references that expose workbook content, and formulas that cause external network requests ...[truncated 1427 chars]

Remediation
View remediation

Remediation Suggestions

  • Sanitize every externally derived value before writing it to a workbook.
  • Prefix strings beginning with =, +, -, @, tab, carriage return, or line feed with an apostrophe.
  • Write untrusted values using explicit text cell types rather than relying on automatic type inference.
  • Apply sanitization to all sheets, including task metadata and future columns.
  • Preserve the unsanitized source only in an access-controlled data store if operationally necessary; do not place it in the workbook.
  • Add automated tests covering values such as =1+1, +SUM(A1:A2), -1+2, @SUM(A1:A2), and formulas containing hyperlinks or external references.
  • Consider disabling external links in generated workbook metadata where supported, while recognizing that this is defense in depth rather than a replacement for input neutralization.

A suitable defensive helper is:

python
def excel_safe_text(value):
    if value is None:
        return ""
    text = str(value)
    if text.startswith(("=", "+", "-", "@", "\t", "\r", "\n")):
        return "'" + text
    return text

Apply this helper to every value derived from forms, tasks, overrides, and other external sources before appending it to a worksheet.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:67
Finding

Predictable Shared Temporary Files Expose Candidate PII and Executable Code

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:67-85; references/fetch-approvals.md:62-96
Vulnerability Type: Unsafe temporary-file handling and plaintext sensitive-data exposure
Risk Level: Medium

Vulnerable Instructions

text
Key field mapping:
- Extract from form: name, applied position, phone number, email address, school, prior employment, CV
- Aggregate status by node name from task_list
- Node names: resume screening, first interview, second interview, final interview, handling

Write the payload to /tmp/hiring_payload.json.
bash
python3 /tmp/build_excel.py --workspace "$(pwd)" --payload /tmp/hiring_payload.json

The referenced payload construction also includes the following sensitive fields:

python
row = {
    "serial": inst["serial_number"],
    "status": translate(inst["status"]),
    "submit_time": format_time(inst["start_time"]),
    "end_time": format_time(inst["end_time"]),
    "name": form["姓名"],
    "position": form["申请职位"],
    "phone": form["手机号"],
    "email": form["邮箱"],
    "school": form["毕业院校"],
    "prior_jobs": form["曾经任职"],
    "cv": "(CV附件-需在飞书内查看)",
    "node_resume_screen": node_status("简历筛查") or node_status("简历筛选"),
    "node_r1": node_status("一面"),
    "node_r2": node_status("二面"),
    "node_r3": node_status("终面"),
    "node_handle": node_status("办理"),
    "tasks": [...]
}

Technical Analysis

The workflow uses fixed paths under the globally shared /tmp directory for both sensitive recruitment data and executable Python code:

  • /tmp/hiring_payload.json
  • /tmp/build_excel.py

The instructions do not require restrictive permissions, atomic file creation, ownership checks, collision handling, or cleanup. Candidate names, phone numbers, email addresses, education history, and employment history are therefore stored as plaintext in a predictable location.

Recreating and executing a program from a ...[truncated 1831 chars]

Remediation
View remediation

Remediation Suggestions

  • Create a private temporary directory using tempfile.TemporaryDirectory() or mktemp -d.
  • Ensure the directory has mode 0700 and payload files have mode 0600.
  • Generate unpredictable filenames and open them atomically with exclusive creation.
  • Do not execute code recreated in a shared temporary directory. Package the reviewed generator as a normal project script or execute verified in-memory source only if packaging is impossible.
  • Verify ownership and reject symbolic links before consuming any temporary file.
  • Set a restrictive umask, such as 077, before creating files containing PII.
  • Remove payloads and other temporary artifacts in a finally block, including after failures.
  • Minimize temporary data by retaining only fields required for report generation.
  • Keep the final workbook in an access-controlled workspace because it also contains candidate PII.
  • If concurrent runs are possible, give each run a separate private directory to prevent cross-run data corruption or disclosure.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:38
Finding

Unpinned Runtime Installation of a Third-Party Package

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:38-43; references/build-excel.md:16-18
Vulnerability Type: Unpinned dependency installation
Risk Level: Medium

Vulnerable Code

bash
python3 -c "import openpyxl" 2>/dev/null || pip install openpyxl -q

The build documentation independently recommends:

bash
pip install openpyxl

Technical Analysis

The workflow installs openpyxl at runtime without specifying an approved version, integrity hash, trusted package index, or isolated environment. The installed artifact therefore depends on the package repository and pip configuration active at execution time.

This permits the effective dependency to change after the Skill has been audited. Risk sources include a compromised upstream release, a compromised or malicious package mirror, environment-level pip index redirection, and future dependency changes that have not been reviewed.

The package name itself is not shown to be a typosquat, and no evidence demonstrates that the current upstream package is malicious. The vulnerability is the uncontrolled runtime resolution and installation process.

Attack Path

  1. The host does not already have an importable openpyxl installation.
  2. The Skill invokes pip install openpyxl automatically.
  3. pip resolves the package and transitive dependencies using the host's current configuration and configured package index.
  4. An attacker who has compromised the selected repository, mirror, package release, or local pip configuration supplies malicious package content.
  5. The package is installed and subsequently imported by the Excel generator.
  6. Malicious package code executes with the privileges of the account running the Skill.

Impact Assessment

Successful supply-chain exploitation would allow Python code execution with the Agent process's privileges. The malicious dependency could access candidate PII, Feishu-related environment ...[truncated 353 chars]

Remediation
View remediation

Remediation Suggestions

  • Declare the dependency before runtime rather than installing it opportunistically during Skill execution.
  • Pin openpyxl and all transitive dependencies to reviewed versions.
  • Require cryptographic hashes using a lock file or pip install --require-hashes.
  • Use python3 -m pip to ensure installation into the intended Python environment.
  • Install dependencies in an isolated virtual environment with controlled ownership and permissions.
  • Specify an explicitly trusted package index and prevent unreviewed index overrides.
  • Perform vulnerability and provenance checks when updating the lock file.
  • Fail safely with a clear dependency error if the approved dependency is absent instead of silently retrieving the latest version.
  • Where possible, use a prebuilt, reviewed runtime image containing the pinned package.
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
Findings (4)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document instructs writing a payload containing candidate PII such as name, phone, email, school, and prior employment history to /tmp/hiring_payload.json without any guidance on access controls, retention, or cleanup. On multi-user systems, shared runners, or agent environments, /tmp is often broadly accessible or persisted long enough to expose sensitive hiring data to other processes or users.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file’s natural-language instructions and examples are presented only in Chinese, and there is no indication that users may choose another language or that the restriction is required for a region-specific purpose. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file describes generating 西湖数智-招聘进度.xlsx and the embedded script later saves that file into the provided workspace, but the usage/output section does not explicitly warn the user that an existing workbook at that path will be replaced. Because the file contains candidate recruiting data, even routine overwrites can affect user data and should be disclosed in the skill description.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The command example hardcodes "locale":"zh-CN", which imposes a specific language/locale choice. The document does not indicate that this is optional, user-selectable, or required for a region-specific compliance reason, so it fits the language/locale policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.