Back to skill

Security audit

Bidding Analysis Report

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward Chinese-language bidding-data report generator, with manageable local file and dependency hygiene risks users should understand.

Install only in an environment where the Python dependencies are acceptable, preferably with pinned versions if used for production. Run the generator from a trusted private directory, review the output path before use, and be aware it can leave chart PNG files containing analyzed business data in the working directory. Do not rely on PDF output unless the implementation is updated.

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

T09 · Insecure Skill Coding Practices

Warning
Location
bidding_report.py:304
Finding

Predictable Intermediate Chart Files Permit File Clobbering and Symlink Attacks

Content
View full analysis

Vulnerability Details

File Location: bidding_report.py:203-252, bidding_report.py:304-315, bidding_report.py:357-368, and bidding_report.py:445-459
Vulnerability Type: Insecure temporary-file handling
Risk Level: Medium

The report generator writes intermediate charts to predictable filenames in the current working directory. It does not create a private temporary directory, reject existing files, prevent symbolic-link traversal, or remove the files after embedding them in the report.

Relevant code:

python
def _create_nested_pie(self, data, title, filename):
    # ...
    plt.tight_layout()
    plt.savefig(filename, dpi=150, bbox_inches='tight', facecolor='white')
    plt.close()

    return filename

def _create_percent_bar(self, data, title, filename):
    # ...
    plt.tight_layout()
    plt.savefig(filename, dpi=150, bbox_inches='tight', facecolor='white')
    plt.close()

    return filename

Predictable global chart names are assigned as follows:

python
# Insert overall nested donut chart
chart_file = 'chart_overall.png'
self.generate_chart(
    'nested_pie',
    {
        'ai_count': total['ai_count'],
        'total_count': total['proj_count'],
        'ai_amount': total['ai_amount'],
        'total_amount': total['total_amount']
    },
    f"AI project count and amount ratio analysis\n"
    f"Total projects {total['proj_count']:,} | AI projects {total['ai_count']:,}",
    chart_file
)
python
# Insert yearly percentage bar chart
chart_file = 'chart_yearly.png'
self.generate_chart(
    'percent_bar',
    self.stats['yearly'],
    'Annual AI bidding ratio trend',
    chart_file
)

Organization-derived filenames are also written into the current directory:

python
safe_name = org_name.replace('/', '_').replace('\\', '_')
chart_file = f'chart_{safe_name}_pie.png'
self.generate_chart(
    'nested_pie',
  
...[truncated 2755 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create a private temporary directory for each report-generation operation:

    python
    import tempfile
    from pathlib import Path
    
    with tempfile.TemporaryDirectory(prefix="bidding-report-") as temp_dir:
        chart_file = Path(temp_dir) / "overall.png"
        self.generate_chart(
            "nested_pie",
            chart_data,
            chart_title,
            str(chart_file)
        )
        doc.add_picture(str(chart_file), width=Inches(6))
        doc.save(output_path)
    
  2. Keep all intermediate charts inside that private directory and allow TemporaryDirectory to remove them after the document has been saved.

  3. Use generated identifiers rather than organization names for filesystem paths. Organization names should appear only in chart content:

    python
    import uuid
    
    chart_file = Path(temp_dir) / f"{uuid.uuid4().hex}.png"
    
  4. Do not run the application from shared or attacker-writable directories, especially when using a privileged account.

  5. If charts must be retained, require an explicit chart-output directory, verify that it is trusted, and reject existing destination files or create them atomically with protections against symbolic links.

  6. Validate and resolve the final output path against an approved output directory when the application is deployed as a service or invoked with untrusted arguments.

Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (16)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The README is entirely written in Chinese and the documented defaults, sample titles, keywords, field names, and notes all assume Chinese-language input/output and Chinese font handling. There is no statement that the skill is China/Chinese-specific, nor any indication that users can opt into another language or locale.

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 contains natural-language and code examples that hard-code Chinese fonts and present the report structure entirely in Chinese, indicating a forced locale/output convention. SQP-3 applies to all file types, and there is no opt-in, language selection, or clear justification that this skill is intentionally limited to a Chinese-only regional compliance context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The file-level description and implementation indicate the report generator is intended to operate in Chinese, and later code constructs report headings and narrative text exclusively in Chinese. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file states that the skill automatically generates Word/PDF reports and shows examples with explicit output paths, which implies file creation on the user's system. The README does not include a user-facing warning or disclosure about overwriting/creating local files or advising users to choose output paths carefully.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This is a markdown file, so SQP-2 applies to user-facing descriptions of behaviors affecting user data or system state. The description emphasizes automatic report generation and later examples show output files being created, but there is no explicit warning that the skill will save documents and chart image files locally and may overwrite existing paths if reused.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest description explicitly states that the skill supports automatic Word/PDF report generation. In the code, output_format accepts 'word' or 'pdf' in the initializer docstring, but the implementation only ever calls generate_word_report, saves a .docx document, and never implements PDF export logic.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The __init__ docstring says output_format can be 'word' or 'pdf', which communicates a real capability choice to developers. However, no code path uses self.output_format to select PDF generation, and the CLI hardcodes output_format='word', so the documentation overstates implemented behavior.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency is specified with a lower bound only, which allows future unreviewed versions to be installed and prevents reproducible builds. In a reporting skill that processes spreadsheet/document inputs, this increases supply-chain risk and makes it harder to determine whether vulnerable pandas releases are in use.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
pandas>=1.3.0
matplotlib>=3.5.0
python-docx>=0.8.11
openpyxl>=3.0.0

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The manifest does not pin pandas, so it is impossible to verify from this file whether a vulnerable or patched version will be installed. This ambiguity is a real supply-chain security issue because affected environments could unknowingly resolve to insecure versions.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

Using matplotlib with only a minimum version permits non-deterministic installs and unvetted upstream releases, which is a software supply-chain weakness. While not directly exploitable by itself, it increases the chance of pulling a problematic version into report-generation environments.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
pandas>=1.3.0
matplotlib>=3.5.0
python-docx>=0.8.11
openpyxl>=3.0.0
numpy>=1.21.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

python-docx is unpinned, so the environment may resolve to different versions over time, including versions with known parser-related issues. Because this skill generates and likely handles Office document content, dependency uncertainty is somewhat more dangerous here than in a simple utility package.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
pandas>=1.3.0
matplotlib>=3.5.0
python-docx>=0.8.11
openpyxl>=3.0.0
numpy>=1.21.0

Unverifiable Dependency: python-docx has 2 known advisory(ies) (CVE-2016-5851 (Improper Restriction of XML External Entity Reference in python-docx); CVE-2016-5851 (python-docx before 0.8.6 allows context-dependent attackers to conduct XML Exter)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding

python-docx has known historical XXE-related advisories, and without a pinned version there is no assurance that deployment avoids those vulnerable releases. In a skill that creates or may manipulate Office documents, unresolved document-parser version risk is more consequential.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

openpyxl is declared with a minimum version only, which weakens reproducibility and may permit installation of vulnerable or incompatible releases. Since this skill is designed to work with Excel data, weaknesses in spreadsheet parsing libraries are more relevant to the operational context.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
pandas>=1.3.0
matplotlib>=3.5.0
python-docx>=0.8.11
openpyxl>=3.0.0
numpy>=1.21.0

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
98% confidence
Finding

openpyxl has known XXE-related advisories, and the unpinned requirement means the actual installed version cannot be validated as safe. Because the skill analyzes bidding data and likely reads Excel files, this dependency uncertainty is more dangerous in context than it would be for an unrelated package.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

An unpinned numpy dependency creates the same supply-chain and reproducibility problem as the other entries, allowing unexpected versions to be installed. The direct security impact is usually limited, but it complicates assurance and can expose the environment to version-specific flaws.

Content

Scanner excerpt · requirements.txt (reported line 5)May include surrounding context.

text
matplotlib>=3.5.0
python-docx>=0.8.11
openpyxl>=3.0.0
numpy>=1.21.0

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
89% confidence
Finding

The requirement for numpy is not pinned, so the manifest cannot prove whether deployed instances use versions affected by any of the listed advisories. This is primarily a dependency hygiene and assurance problem rather than an immediately exploitable flaw from the manifest alone.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.