Back to skill

Security audit

Finance Paper Daily

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but it can install unpinned Python packages into the user's environment while fetching remote data and writing an Excel report.

Review before installing. Only run it in a dedicated virtual environment, avoid --break-system-packages, preinstall reviewed dependency versions yourself, and treat the generated spreadsheet as untrusted because remote paper metadata can affect its contents.

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)

T08 · Insecure Dependencies

Warning
Location
scripts/fetch_papers.py:7
Finding

Unpinned Dependencies Are Installed Automatically at Runtime

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch_papers.py:7-15, scripts/fetch_papers.py:115-121; installation instructions also appear in SKILL.md:21-24 and SKILL.md:34-35
Vulnerability Type: Supply-chain risk caused by unpinned runtime dependencies
Risk Level: Medium

Vulnerable Code

python
try:
    import openpyxl
    from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
    from openpyxl.utils import get_column_letter
except ImportError:
    print('正在安装 openpyxl...')
    import subprocess
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'openpyxl', '-q'])
    import openpyxl
    from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
    from openpyxl.utils import get_column_letter
python
try:
    from scholarly import scholarly as sc
except ImportError:
    import subprocess
    subprocess.check_call([sys.executable,'-m','pip','install','scholarly','-q'])
    from scholarly import scholarly as sc

The documented installation command is also unpinned and directs users to modify an externally managed Python environment:

bash
pip3 install openpyxl scholarly --break-system-packages -q

Technical Analysis

The script automatically invokes pip when either dependency is unavailable. Neither package is restricted to a reviewed version, integrity hash, trusted artifact, or locked transitive dependency set. The code executed by the project can therefore change without any change to the audited repository.

Python package installation can execute package build hooks and other package-supplied code. A compromised upstream release, package index, distribution account, or transitive dependency could consequently execute code with the privileges of the user running this Skill. The documented use of --break-system-packages also bypasses protections for externally managed Python environments and can al ...[truncated 1255 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove all automatic pip install operations from runtime code. Fail with a clear dependency error instead.
  2. Define dependencies in a lock file using exact reviewed versions, including transitive dependencies.
  3. Require package hashes, such as through pip install --require-hashes -r requirements.txt.
  4. Install dependencies in a dedicated virtual environment during a separate, explicit setup phase.
  5. Avoid --break-system-packages; do not modify externally managed Python environments.
  6. Use a controlled package mirror or other trusted artifact repository where appropriate.
  7. Add dependency vulnerability and provenance checks to the release process.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_papers.py:168
Finding

Remote Paper Metadata Can Be Interpreted as Excel Formulas

Content
View full analysis

Vulnerability Details

File Location: External metadata is collected at scripts/fetch_papers.py:45, scripts/fetch_papers.py:71, scripts/fetch_papers.py:102, and scripts/fetch_papers.py:135; the vulnerable workbook sink is at scripts/fetch_papers.py:168-177
Vulnerability Type: Spreadsheet formula injection
Risk Level: Medium

Vulnerable Code

The script stores metadata obtained from remote services without spreadsheet-specific neutralization:

python
papers.append({'来源':'arXiv','标题':(title.text or '').strip().replace('\n',' ') if title is not None else '','作者':', '.join(author_names),'摘要':(summary.text or '').strip().replace('\n',' ')[:500] if summary is not None else '','发布日期':(published.text or '')[:10] if published is not None else '','分类':category,'链接':link.text.strip() if link is not None else ''})
python
papers.append({'来源':'Semantic Scholar','标题':p.get('title',''),'作者':', '.join(authors),'摘要':(p.get('abstract') or '')[:500],'发布日期':pub_date[:10] if len(pub_date)>=10 else pub_date,'分类':kw,'链接':link})
python
papers.append({'来源':'OpenAlex','标题':title,'作者':', '.join(authors),'摘要':abstract,'发布日期':pub_date[:10],'分类':', '.join(concepts),'链接':link})
python
papers.append({'来源':'Google Scholar','标题':t,'作者':authors,'摘要':bib.get('abstract','')[:500],'发布日期':str(bib.get('pub_year','')),'分类':kw,'链接':pub.get('pub_url','')})

These values are then written directly into cells:

python
for idx,p in enumerate(papers,1):
    row = idx+1
    src = p.get('来源','')
    fill = source_colors.get(src, PatternFill('solid',fgColor='F5F5F5'))
    values = [idx,src,p.get('标题',''),p.get('作者',''),p.get('摘要',''),p.get('发布日期',''),p.get('分类',''),p.get('链接','')]
    for col,val in enumerate(values,1):
        cell = ws.cell(row=row,column=col,value=val)
        cell.fill = fill
        cell.border = border
        cell.alignment = Alignment(vertical='top',wrap_text=(col in [3,
...[truncated 2316 chars]
Remediation
View remediation

Remediation Suggestions

  1. Treat every value obtained from an external API or scraped result as untrusted.
  2. Before writing text to a cell, neutralize values whose first non-whitespace character is =, +, -, or @. Prefixing such values with an apostrophe is a common defense when literal display is required.
  3. Explicitly store untrusted metadata as text rather than allowing automatic formula detection.
  4. Apply the protection to every externally influenced field, including titles, authors, abstracts, dates, categories, and links.
  5. Validate links against an explicit https URL policy. If clickable links are desired, assign validated hyperlinks separately while keeping displayed text non-executable.
  6. Add tests covering formula payloads with leading whitespace, control characters, and each recognized formula prefix.
  7. Review workbook settings and avoid external links or connections that are not required.

A centralized sanitizer can be applied before every cell write:

python
def excel_safe_text(value):
    if not isinstance(value, str):
        return value
    if value.lstrip().startswith(('=', '+', '-', '@')):
        return "'" + value
    return value

cell = ws.cell(row=row, column=col, value=excel_safe_text(val))

T09 · Insecure Skill Coding Practices

Note
Location
scripts/fetch_papers.py:20
Finding

arXiv Metadata Is Retrieved Over Unencrypted HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch_papers.py:20-29
Vulnerability Type: Cleartext transport of remotely supplied report data
Risk Level: Low

Vulnerable Code

python
def fetch_arxiv(max_results=30):
    print('📡 抓取 arXiv q-fin...')
    papers = []
    cats = '+OR+'.join(f'cat:{c}' for c in ARXIV_CATEGORIES)
    query = urllib.parse.quote(f'({cats})')
    url = (f'http://export.arxiv.org/api/query?search_query={query}&sortBy=submittedDate&sortOrder=descending&max_results={max_results}')
    try:
        with urllib.request.urlopen(url, timeout=20) as r:
            xml_data = r.read()

Technical Analysis

The arXiv API request uses plain HTTP rather than HTTPS. HTTP provides neither transport confidentiality nor cryptographic server authentication and response integrity. An attacker positioned on the network path can observe or alter the request and XML response.

Although the query itself is not sensitive, the response becomes trusted input to the generated workbook. A network attacker could consequently change paper titles, abstracts, authors, classifications, or links. Crafted response content could also be combined with the spreadsheet formula-injection weakness described separately.

Attack Path

  1. The user runs the Skill on a network controlled or observable by an attacker, or traffic passes through a compromised intermediary.
  2. The script requests the arXiv feed using http://export.arxiv.org.
  3. The attacker intercepts and modifies the unencrypted XML response.
  4. The script parses the modified response as authentic arXiv metadata.
  5. The attacker-controlled metadata is written into the Excel report.
  6. The user relies on or opens the manipulated report.

Impact Assessment

A network-positioned attacker can compromise the integrity of the arXiv section of the report, including substituting deceptive paper information and links. The request cont ...[truncated 235 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace the endpoint with its HTTPS equivalent:
    python
    url = f'https://export.arxiv.org/api/query?search_query={query}&sortBy=submittedDate&sortOrder=descending&max_results={max_results}'
    
  2. Ensure certificate verification remains enabled and do not introduce permissive TLS contexts.
  3. If redirects occur, verify that the final URL retains HTTPS and uses the expected arXiv hostname.
  4. Continue treating the response as untrusted even after enabling TLS, including applying formula-injection defenses before workbook generation.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (10)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares no explicit tool scope even though its documented behavior requires network access and shell/package installation. Without clear permission boundaries, an agent may invoke broader capabilities than users expect, increasing the risk of unintended network access, package installation, or local file modification.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The trigger phrases are broad enough to overlap with ordinary requests about finance papers or Excel generation, which can cause the skill to activate in situations the user did not specifically intend. Because the skill performs network retrieval and writes files to the desktop, accidental invocation expands the risk from a simple misfire into unintended external access and local side effects.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Installing Python packages during normal operation is not necessary for a simple paper-fetching/reporting skill and constitutes local environment modification. In this context, the skill is expected to collect metadata and write an Excel file, so hidden dependency installation is more dangerous because it exceeds user expectations and introduces avoidable supply-chain exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill installs openpyxl without warning, confirmation, or a consent flow. Silent package installation is dangerous because it changes the host environment and may execute unreviewed third-party code under the user's privileges, which is disproportionate to the stated purpose of generating a report.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
96% confidence
Finding

The script automatically invokes pip to install openpyxl at runtime, which modifies the local Python environment without explicit user approval. Even though the package name is hardcoded and the subprocess call does not use a shell, this still creates supply-chain and environment-integrity risk because execution now depends on downloading and running code from a package index during normal skill execution.

Content

Scanner excerpt · scripts/fetch_papers.py (reported line 12)May include surrounding context.

python
except ImportError:
    print('正在安装 openpyxl...')
    import subprocess
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'openpyxl', '-q'])
    import openpyxl
    from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
    from openpyxl.utils import get_column_letter

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fetch_papers.py (reported line 55)May include surrounding context.

python
for kw in keywords:
        if len(papers) >= max_results: break
        query = urllib.parse.quote(kw)
        url = (f'https://api.semanticscholar.org/graph/v1/paper/search?query={query}&fields=title,authors,abstract,year,externalIds,publicationDate,url&limit=10&sort=publicationDate')
        try:
            req = urllib.request.Request(url, headers={'User-Agent':'finance-paper-bot/1.0'})
            with urllib.request.urlopen(req, timeout=20) as r:

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fetch_papers.py (reported line 82)May include surrounding context.

python
for cid in concept_ids:
        if len(papers) >= max_results: break
        from_date = (datetime.date.today()-datetime.timedelta(days=30)).isoformat()
        url = (f'https://api.openalex.org/works?filter=concepts.id:{cid},from_publication_date:{from_date}&sort=publication_date:desc&per-page=10&mailto=research@example.com')
        try:
            req = urllib.request.Request(url, headers={'User-Agent':'finance-paper-bot/1.0'})
            with urllib.request.urlopen(req, timeout=20) as r:

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The additional runtime installation for scholarly further broadens the skill's capabilities beyond paper retrieval into system modification. Because this code path is triggered by a fetch operation, users may not realize the skill can download and execute third-party package installation logic.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The scholarly package is also installed silently, creating the same unannounced environment-change and supply-chain risks. This is particularly concerning because it is tied to an ancillary data source, making the modification less expected in the skill context.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
97% confidence
Finding

The script also auto-installs scholarly on demand, again altering the local environment during execution and pulling third-party code from the network. This expands the attack surface and introduces package-supply-chain risk, especially because the Google Scholar path is optional and not essential to safely producing an Excel report.

Content

Scanner excerpt · scripts/fetch_papers.py (reported line 116)May include surrounding context.

python
from scholarly import scholarly as sc
        except ImportError:
            import subprocess
            subprocess.check_call([sys.executable,'-m','pip','install','scholarly','-q'])
            from scholarly import scholarly as sc
        keywords = ['quantitative finance 2024','asset pricing machine learning 2024']
        seen = set()

Static analysis

No suspicious patterns detected.