Back to skill

Security audit

Scholar Research

Security checks for vulnerabilities and agentic risk

Overview

This academic research skill is mostly purpose-aligned, but it should be reviewed because it can fetch arbitrary PDF URLs, write downloaded content locally without size or type limits, and documents an unsafe placeholder Git install command.

Review this skill before installing. It is not clearly malicious, but only use it with non-sensitive research queries, avoid the placeholder Git install command, and run PDF download/extraction in a restricted environment because arbitrary or malicious PDFs could be fetched and written to disk.

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

T09 · Insecure Skill Coding Practices

Warning
Location
src/scholar_research/search.py:15
Finding
Academic Search Queries Transmitted over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `src/scholar_research/search.py:15, 80-84` **Vulnerability Type**: Plaintext transmission of user-provided search terms **Risk Level**: Medium ### Vulnerable Code ```python SOURCES = { "arxiv": { "base_url": "http://export.arxiv.org/api/query", "search_field": "all", "max_results": 50 }, ``` ```python response = requests.get( SOURCES["arxiv"]["base_url"], params=params, timeout=60 ) ``` The same plaintext endpoint is documented at `references/apis.md:6`: ```markdown - **Base URL**: `http://export.arxiv.org/api/query` ``` ### Technical Analysis The arXiv integration sends the user-provided research query to an API endpoint using unencrypted HTTP. Query parameters, including potentially confidential research interests, are visible to network intermediaries. Because HTTP provides neither transport confidentiality nor server authentication, an on-path attacker can also modify the API response. Network access is necessary for the declared academic-search functionality, but plaintext transport exceeds neither a valid functional requirement nor minimum safe privileges. The other enabled search services already use HTTPS. This is not evidence of intentional exfiltration: the destination is the legitimate arXiv service. It is nevertheless an exploitable confidentiality and integrity flaw. ### Attack Path 1. A user submits a sensitive academic search query. 2. `search_arxiv()` places the query in the `search_query` URL parameter. 3. The request is transmitted to `http://export.arxiv.org/api/query`. 4. An attacker controlling or observing the local network, proxy, gateway, or upstream route reads the query. 5. The attacker may modify the returned XML before it reaches the Skill. 6. Manipulated paper metadata may subsequently be parsed, scored, and presented as legitimate search results. ### Impact Assessment An attacker can obtain the contents of arXiv search quer ...[truncated 322 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace the endpoint with `https://export.arxiv.org/api/query`. - Require HTTPS for every configured source. - Reject redirects that downgrade from HTTPS to HTTP. - Validate each redirect destination before following it. - Add a regression test asserting that all production API endpoints use HTTPS. - Document that user search terms are transmitted to third-party academic services. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/scholar_research/figure_extract.py:175
Finding
Arbitrary PDF URL Retrieval Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `src/scholar_research/figure_extract.py:175-202` **Vulnerability Type**: Server-side request forgery through an unrestricted URL **Risk Level**: High ### Vulnerable Code ```python # Get PDF URL pdf_url = paper.get("pdf_url", "") # Try different sources if not pdf_url: # Try arXiv arxiv_id = paper.get("arxiv_id", "") if arxiv_id: pdf_url = f"https://arxiv.org/pdf/{arxiv_id}.pdf" if not pdf_url: # Try DOI doi = paper.get("doi", "") if doi: pdf_url = f"https://doi.org/{doi}" if not pdf_url: return None # Download try: import requests filename = self._sanitize_filename(paper.get("title", "paper")) + ".pdf" filepath = os.path.join(output_dir, filename) response = requests.get(pdf_url, timeout=60, stream=True) ``` ### Technical Analysis `PDFDownloader.download_pdf()` accepts `paper["pdf_url"]` without validating its scheme, hostname, port, resolved IP address, or redirect chain. The `requests` library follows redirects by default. A caller able to influence the paper dictionary can make the host issue requests to arbitrary destinations, including: - Loopback services such as `127.0.0.1` - Private network addresses - Link-local addresses and cloud instance metadata services - Services exposed through unusual ports - External tracking or attacker-controlled servers - A permitted public host that redirects to a restricted destination The current main presentation path only prints an extraction placeholder and does not automatically call this downloader. Exploitation therefore requires another caller or future workflow to invoke `download_pdf()` with attacker-influenced metadata. The vulnerable public method nevertheless provides the unsafe capability. ### Attack Path 1. An attacker supplies or modifies a paper dictionary consumed by `download_pdf()`. 2. The attacker sets `pdf_url` to an internal target, such as a loopback administration endpoin ...[truncated 1146 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Permit only `https` URLs. - Use an explicit allowlist of trusted scholarly PDF hosts. - Reject URLs containing embedded credentials or unexpected ports. - Resolve the hostname before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved addresses. - Repeat destination validation after every DNS resolution and redirect. - Disable automatic redirects with `allow_redirects=False`, or manually follow only validated HTTPS redirects. - Protect against DNS rebinding by connecting only to the validated address while preserving correct TLS hostname verification. - Consider deriving URLs exclusively from validated arXiv identifiers or DOI resolvers rather than accepting arbitrary URLs. - Run download operations in a restricted network environment with no access to internal services or cloud metadata. - Add tests for IPv4, IPv6, encoded IP addresses, alternate ports, redirects, and DNS rebinding cases. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/scholar_research/figure_extract.py:202
Finding
Remote Downloads Have No Size or File-Type Validation<![CDATA[ ## Vulnerability Details **File Location**: `src/scholar_research/figure_extract.py:202-208` **Vulnerability Type**: Unbounded download and unsafe handling of untrusted remote content **Risk Level**: Medium ### Vulnerable Code ```python response = requests.get(pdf_url, timeout=60, stream=True) if response.status_code == 200: with open(filepath, "wb") as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) return filepath ``` ### Technical Analysis The downloader streams a successful HTTP response directly to disk without enforcing a maximum byte count. The 60-second request timeout does not impose a total response-size limit and may not impose a strict overall transfer deadline while data continues to arrive. The implementation also does not validate: - The `Content-Length` header - The response media type - The PDF magic bytes - Whether the response is actually a regular PDF - Available disk capacity - Whether a partial file should be removed after failure The downloaded file can later be supplied to `pdftotext` and `pdfimages`. A malicious server may therefore provide malformed parser input under a `.pdf` filename. ### Attack Path 1. An attacker controls a supplied PDF URL, a remote server, or a redirect destination. 2. The downloader receives an HTTP 200 response. 3. The server sends a very large or indefinitely generated body. 4. The Skill writes every chunk to disk without a maximum-size check. 5. Storage exhaustion disrupts the Skill or other applications on the same filesystem. 6. Alternatively, the server provides a malformed non-PDF or exploit-oriented PDF. 7. A caller passes the saved file to the local Poppler tools, exposing those parsers to attacker-controlled content. ### Impact Assessment A successful oversized-download attack can exhaust disk space and cause denial of service for the current process or other services sharing the filesystem. Malformed content may trigger vulnerabi ...[truncated 379 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Define a strict maximum PDF size appropriate for the application. - Reject a response when a declared `Content-Length` exceeds the limit. - Count streamed bytes and abort if the actual response exceeds the limit. - Apply an overall transfer deadline in addition to connection and read timeouts. - Require an expected PDF media type while treating it only as a preliminary check. - Validate that the downloaded content begins with a valid PDF signature and perform structural validation before parser invocation. - Write to a uniquely named temporary file using exclusive creation, then atomically rename it only after validation. - Delete partial files on timeout, validation failure, or size-limit violation. - Enforce storage quotas and use a dedicated non-sensitive download directory. - Run PDF parsers in a sandbox with minimal filesystem access, no network access, resource limits, and current security patches. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:16
Finding
Documentation Recommends Installation from an Unpinned Placeholder Git Repository<![CDATA[ ## Vulnerability Details **File Location**: `README.md:16` **Vulnerability Type**: Mutable and unverified source dependency **Risk Level**: Medium ### Vulnerable Code ```bash pip install git+https://github.com/yourusername/scholar-research.git ``` ### Technical Analysis The installation command references the placeholder namespace `yourusername` and does not pin an immutable commit, signed tag, or verified release artifact. A user following this instruction would install whatever code the referenced repository serves at installation time. Python package installation can execute build-backend behavior and installs code that will later run with the user's privileges. Consequently, an attacker who controls or later acquires the placeholder repository can replace the reviewed implementation with arbitrary package content. No evidence shows that this placeholder repository is currently attacker-controlled or that the bundled project intentionally retrieves a malicious package. The flaw is the unsafe and unverifiable installation instruction. ### Attack Path 1. A user follows the Git installation command in the README. 2. The placeholder repository exists or is registered by an attacker. 3. The attacker publishes a Python project containing malicious build or runtime code. 4. `pip` clones the mutable repository and invokes the package build process. 5. The malicious package is installed into the user's environment. 6. Its code executes during a build hook, import, or command invocation with the user's privileges. ### Impact Assessment A malicious package obtained through this path could execute code with all privileges available to the user running `pip`. Depending on those privileges, it could read user files and credentials, alter the Python environment, access the network, or establish persistence. This risk is limited to users who follow the unsafe Git-based installation instruction. The local installation command does not have the same placeh ...[truncated 27 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace the placeholder URL with the verified official repository. - Pin Git installations to an immutable commit hash. - Prefer a signed, versioned release from a trusted package registry. - Publish cryptographic hashes and document hash-verified installation. - Protect repository ownership with multi-factor authentication and restricted release permissions. - Remove the Git installation command until a genuine and controlled repository is available. - Use lock files or constraints with hashes for reproducible application deployments. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (43)

YARA rule 'agent_skill_remote_bootstrap_execution': Remote script or code download followed by execution/bootstrap installation [agent_skills]

High
Category
YARA Match
Content
and analysis tool that queries multiple databases (arXiv, PubMed, OpenAlex, CrossRef), scores papers by relevance/quality, and generates field timelines.

## Features

- 🔍 Search across 4 academic databases
- 📊 Score papers (0-100) based on citations, recency, and credibility
- 📈 Generate field evolution timelines
- 🧪 Comprehensive test coverage

## Installation

```bash
# From GitHub
pip install git+https://github.com/yourusername/scholar-research.git

# Or install locally
pip install -e .
```

## Usage

```bash
# Search for a topic
python -m scholar_research "quantum computing" --top=5

# Search with custom output
python -m scholar_research "machine learning" --top=3 --output json
```

## Supported Topics

- Battery research (sodium ion, zinc ion, lithium, solid state)
- Computing (quantum computing, neural networks, ML)
- Energy (solar cells, fuel cells)
- Health (cancer immunotherapy, CRISPR)

## Development

```bash
# Install dev dependencies
pip install -e ".[dev]"

#
Confidence
85% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The supplied code is only a scoring/analysis module. It calculates credibility scores from paper metadata, sorts papers, computes score distributions/statistics, and includes helper classes that query OpenAlex and CrossRef for author/journal information. That partially aligns with the 'credibility scoring' portion of the description, but most of the declared functionality is not present in this chunk: no search across open-access sources, no paper summarization, no visualization, no timeline creation, and no figure extraction. Additionally, the code makes outbound network requests to OpenAlex and CrossRef despite the declared permissions being empty. This makes the description incomplete/inaccurate relative to the actual behavior of this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code chunk is a search/retrieval component only. Its primary behavior is calling external academic metadata/search APIs and normalizing results. While this partially aligns with the 'search' portion of the description, the broader declared functionality is not represented in this code: there is no paper analysis, no summarization, no credibility scoring, no visualization, no timeline creation, and no figure extraction. Additionally, the declared description emphasizes peer-reviewed papers from open access sources, but the code does not enforce peer-review filtering and includes sources such as arXiv (preprints) and CrossRef/PubMed metadata endpoints that are not themselves guarantees of open-access peer-reviewed full text. Therefore the description materially overstates and mischaracterizes what this code actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The declared description presents a broader research skill that can search, analyze, and summarize academic papers from open-access sources and provide credibility scoring, visualization, timeline generation, and figure extraction. The supplied code only covers a subset: summarization, timeline generation, and text-based visualization over already-provided paper data. It does not perform paper search/retrieval, source access, or figure extraction, and it does not actually score credibility in the main implementation. Because important declared capabilities are absent from the actual behavior of this code chunk, the description does not accurately represent what this chunk does.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill advertises behaviors that inherently require network access, file handling, and possibly shell-capable execution through external tooling, yet it declares no explicit tool scope or permissions. This creates an overprivileged or ambiguously privileged execution model where a host may grant broader access than intended, increasing the chance of unauthorized network requests, file reads, or command execution if the implementation is later added or swapped in.

External Transmission

Medium
Category
Data Exfiltration
Content
- **Rate Limit**: 3 requests per second

### 3. OpenAlex
- **Base URL**: `https://api.openalex.org/`
- **Endpoints**:
  - Works: `/works`
  - Authors: `/authors`
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
- **Rate Limit**: 60 requests/minute

### 5. CrossRef
- **Base URL**: `https://api.crossref.org/`
- **Documentation**: https://www.crossref.org/documentation/retrieve-metadata/rest-api/
- **Rate Limit**: Polite pool (include email)
- **Note**: Requires email for "polite" usage
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
- **Rate Limit**: 100 requests/day (free tier)

### 7. Unpaywall
- **Base URL**: `https://api.unpaywall.org/v2/`
- **Documentation**: https://unpaywall.org/products/api
- **Rate Limit**: 100,000 requests/day
- **Note**: Requires email
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### pdftotext (Poppler)
```bash
# Install
sudo apt install poppler-utils

# Extract text
pdftotext paper.pdf -
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""Extract text from PDF"""
        try:
            # Use pdftotext if available
            result = subprocess.run(
                ["pdftotext", pdf_path, "-"],
                capture_output=True,
                text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The module executes the external `pdftotext` command on user-supplied PDF paths, which is a subprocess operation covered by the warning requirement for code files. Although the purpose is inferable, this file provides no user-facing notice, prompt, or explicit warning that external system tools will be executed.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
            # Try using pdfimages (Poppler)
            base_name = os.path.join(output_dir, "fig")
            subprocess.run(
                ["pdfimages", "-list", "-png", pdf_path, base_name],
                capture_output=True,
                timeout=30
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The code invokes the external `pdfimages` utility to extract images from the PDF, which is a subprocess action and also causes output files to be created in the output directory. This file does not include a confirmation, user-visible log, or explicit warning describing that behavior.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
The manifest describes a skill for searching, analyzing, summarizing papers, and extracting figures from open-access sources, but this file also includes a standalone PDFDownloader that fetches remote URLs and writes PDFs into a local downloads directory. Network retrieval may support the broader skill, but bundling download-and-store behavior inside the figure extraction module goes beyond the narrower behavior claimed by this module's own documentation and the manifest's emphasis on analysis outputs.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code fetches remote content and writes it directly to a local PDF file, which affects user storage and system state. In this file there is no confirmation prompt, user-facing notice before the write, or explanatory comment/docstring warning about the download-and-save behavior.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_author_info(self, author_name: str) -> Dict:
        """Get author info from OpenAlex"""
        try:
            url = f"https://api.openalex.org/authors?search={author_name}&per_page=1"
            response = requests.get(url, timeout=10)
            data = response.json()
Confidence
88% confidence
Finding
This function performs an outbound request to OpenAlex using user-influenced input, creating an external transmission path. In the context of a research skill, such network access is expected, but it still represents a real privacy boundary crossing and could leak user-supplied names or research context to a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_journal_info(self, journal_name: str) -> Dict:
        """Get journal info from CrossRef"""
        try:
            url = f"https://api.crossref.org/journals/{journal_name}"
            response = requests.get(url, timeout=10)
            data = response.json()
Confidence
87% confidence
Finding
This function sends a user-controlled journal identifier to CrossRef over the network, which is a real external transmission of potentially sensitive query context. The skill's purpose makes this behavior functionally relevant rather than suspicious, so the primary risk is privacy/compliance exposure rather than code execution or direct compromise.

External Transmission

Medium
Category
Data Exfiltration
Content
"db": "pubmed"
    },
    "openalex": {
        "base_url": "https://api.openalex.org/works",
        "per_page": 50
    },
    "doaj": {
Confidence
85% confidence
Finding
The skill is designed to send search queries and metadata to external academic services such as OpenAlex. In context this is expected functionality rather than malicious exfiltration, but it still creates a real data-transmission surface that can leak sensitive user queries if not disclosed and controlled.

External Transmission

Medium
Category
Data Exfiltration
Content
"base_url": "https://doaj.org/api/v2/search/articles"
    },
    "core": {
        "base_url": "https://api.core.ac.uk/v3/works"
    },
    "semantic_scholar": {
        "base_url": "https://api.semanticscholar.org/graph/v1/paper/search",
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"base_url": "https://doaj.org/api/v2/search/articles"
    },
    "core": {
        "base_url": "https://api.core.ac.uk/v3/works"
    },
    "semantic_scholar": {
        "base_url": "https://api.semanticscholar.org/graph/v1/paper/search",
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"base_url": "https://api.core.ac.uk/v3/works"
    },
    "semantic_scholar": {
        "base_url": "https://api.semanticscholar.org/graph/v1/paper/search",
        "limit": 50
    },
    "biorxiv": {
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"base_url": "https://api.core.ac.uk/v3/works"
    },
    "semantic_scholar": {
        "base_url": "https://api.semanticscholar.org/graph/v1/paper/search",
        "limit": 50
    },
    "biorxiv": {
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"base_url": "https://api.core.ac.uk/v3/works"
    },
    "semantic_scholar": {
        "base_url": "https://api.semanticscholar.org/graph/v1/paper/search",
        "limit": 50
    },
    "biorxiv": {
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"base_url": "https://api.core.ac.uk/v3/works"
    },
    "semantic_scholar": {
        "base_url": "https://api.semanticscholar.org/graph/v1/paper/search",
        "limit": 50
    },
    "biorxiv": {
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"limit": 50
    },
    "biorxiv": {
        "base_url": "https://api.biorxiv.org/details/biorxiv"
    },
    "medrxiv": {
        "base_url": "https://api.biorxiv.org/details/medrxiv"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.