Back to skill

Security audit

zotero-enhanced

Security checks across malware telemetry and agentic risk

Overview

This is a disclosed Zotero helper that can upload, read, update, and delete Zotero library data, so users should treat it as powerful but purpose-aligned.

Install only if you are comfortable giving the skill a Zotero API key with access to your library. Use dry-run and confirmation for deletes, avoid --no-confirm unless you have separately approved the exact note key, and treat uploads/read errors as potentially exposing library metadata or document contents to Zotero, Crossref/arXiv, WebDAV, and agent logs.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (15)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly instructs users to execute multiple shell scripts, but the manifest does not declare permissions/capabilities accordingly. This creates a transparency and governance gap: platforms or users may not realize the skill can invoke shell-based operations that access local files, credentials, and network services.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The --backup path writes full note contents to a local file under the user's home directory, which creates a data-at-rest exposure not disclosed in the skill description. In a skill handling library notes, those notes may contain sensitive research material, annotations, or personal data, so undeclared local persistence increases confidentiality risk and surprises downstream operators.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The header comment claims the script only calls the Zotero API, but the code also writes note content to local backup files when --backup is used. Misleading security claims are dangerous because users and agent frameworks may make trust decisions based on them, causing sensitive content handling to be misunderstood.

Intent-Code Divergence

Medium
Confidence
90% confidence
Finding
The help text asserts there are no hidden network calls, but in API-download mode the script retrieves a download URL from attachment metadata and then performs a second fetch to that URL. Even if this is expected in Zotero's protocol, the behavior is less transparent than advertised and could enable outbound requests to an API-supplied endpoint, which matters in constrained or privacy-sensitive environments.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation describes reading local PDFs and sending metadata or files to Zotero, Crossref, arXiv, and optional WebDAV, but it does not present a clear privacy warning or informed-consent notice. Users may unknowingly expose document contents, filenames, identifiers, or credentials to third-party services.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
On failure to find a PDF attachment, the script prints the full children API response to stderr/stdout. That response can contain item metadata, filenames, links, notes, or other library details that may be sensitive and could leak into logs, agent transcripts, or shared terminal history.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
When no download URL is present, the script prints the entire attachment metadata response. This can disclose sensitive library metadata and internal links to logs or upstream callers, especially problematic in agent environments where command output is captured and retained.

External Transmission

Medium
Category
Data Exfiltration
Content
API_URL="https://api.zotero.org/users/$ZOTERO_USER_ID/items"

PARENT_RESPONSE=$(curl -s -f \
  -H "Zotero-API-Key: $ZOTERO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$PARENT_PAYLOAD" \
Confidence
87% confidence
Finding
curl -s -f \ -H "Zotero-API-Key: $ZOTERO_API_KEY" \ -H "Content-Type: application/json" \ -d

External Transmission

Medium
Category
Data Exfiltration
Content
echo "Step 3: Creating attachment record..."
ATTACH_PAYLOAD=$(jq -n --arg title "$FILENAME" --arg filename "$FILENAME" --arg parent "$PARENT_KEY" '[{"itemType": "attachment", "parentItem": $parent, "linkMode": "imported_file", "title": $title, "filename": $filename}]')

ATTACH_RESPONSE=$(curl -s -f \
  -H "Zotero-API-Key: $ZOTERO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$ATTACH_PAYLOAD" \
Confidence
85% confidence
Finding
curl -s -f \ -H "Zotero-API-Key: $ZOTERO_API_KEY" \ -H "Content-Type: application/json" \ -d

External Transmission

Medium
Category
Data Exfiltration
Content
local response
    
    echo "  - Querying Crossref API for DOI: $doi"
    response=$(curl -s -L -H "User-Agent: ZoteroImport/1.0" "https://api.crossref.org/works/$doi")
    
    if echo "$response" | jq -e '.status == "ok"' >/dev/null 2>&1; then
        echo "$response"
Confidence
93% confidence
Finding
https://api.crossref.org/

External Transmission

Medium
Category
Data Exfiltration
Content
language: .language
} | with_entries(select(.value != ""))' | jq -c '[.]')

API_URL="https://api.zotero.org/users/$ZOTERO_USER_ID/items"

PARENT_RESPONSE=$(curl -s -f \
  -H "Zotero-API-Key: $ZOTERO_API_KEY" \
Confidence
88% confidence
Finding
https://api.zotero.org/

Tool Parameter Abuse

High
Category
Tool Misuse
Content
bash scripts/delete_note.sh "NOTE_KEY"

# Delete without confirmation (use with caution):
bash scripts/delete_note.sh --no-confirm "NOTE_KEY"

# Backup before deleting:
bash scripts/delete_note.sh --backup "NOTE_KEY"
Confidence
74% confidence
Finding
--no-confirm

Tool Parameter Abuse

High
Category
Tool Misuse
Content
--help, -h        Show this help
  --version         Show version
  --dry-run         Show steps without deleting
  --no-confirm      Skip confirmation prompt
  --backup          Save note content to file before deleting

Environment variables:
Confidence
72% confidence
Finding
--no-confirm

Tool Parameter Abuse

High
Category
Tool Misuse
Content
Examples:
  $0 ABC12
  $0 --no-confirm ABC12
  $0 --backup ABC12
  $0 --dry-run ABC12
Confidence
72% confidence
Finding
--no-confirm

Tool Parameter Abuse

High
Category
Tool Misuse
Content
DRY_RUN=true
            shift
            ;;
        --no-confirm)
            NO_CONFIRM=true
            shift
            ;;
Confidence
78% confidence
Finding
--no-confirm

VirusTotal

64/64 vendors flagged this skill as clean.

View on VirusTotal

Static analysis

No suspicious patterns detected.