Back to skill

Security audit

UpNote

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward UpNote automation wrapper, with one limited URL-encoding weakness that users should be aware of.

Install only if you are comfortable letting the agent open UpNote and create or navigate notes on your behalf. Avoid using untrusted note or notebook IDs with special URL characters until the script encodes all URL parameters consistently.

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
scripts/upnote.sh:59
Finding
Custom URL Query Parameter Injection Through Unencoded User Input<![CDATA[ ## Vulnerability Details **File Location**: `scripts/upnote.sh:59`, `scripts/upnote.sh:74`, `scripts/upnote.sh:100`, and `scripts/upnote.sh:109-118` **Vulnerability Type**: Custom URL query parameter injection **Risk Level**: Medium ### Vulnerable Code ```bash open) shift NOTE_ID="$1" NEW_WINDOW="${2:-false}" if [[ -z "$NOTE_ID" ]]; then echo "Usage: upnote open <noteId> [true|false]" exit 1 fi open "upnote://x-callback-url/openNote?noteId=$NOTE_ID&new_window=$NEW_WINDOW" ;; ``` ```bash open) shift NOTEBOOK_ID="$1" if [[ -z "$NOTEBOOK_ID" ]]; then echo "Usage: upnote notebook open <notebookId>" exit 1 fi open "upnote://x-callback-url/openNotebook?notebookId=$NOTEBOOK_ID" ;; ``` ```bash filter) shift FILTER_ID="$1" if [[ -z "$FILTER_ID" ]]; then echo "Usage: upnote filter <filterId>" exit 1 fi open "upnote://x-callback-url/openFilter?filterId=$FILTER_ID" ;; ``` ```bash view) shift MODE="$1" URL="upnote://x-callback-url/view?mode=$MODE" shift while [[ $# -gt 0 ]]; do case $1 in --note-id) URL+="&noteId=$2"; shift 2 ;; --notebook-id) URL+="&notebookId=$2"; shift 2 ;; --tag-id) URL+="&tagId=$2"; shift 2 ;; --filter-id) URL+="&filterId=$2"; shift 2 ;; --space-id) URL+="&spaceId=$2"; shift 2 ;; --query) URL+="&action=search&query=$(urlencode "$2")"; shift 2 ;; *) echo "Unknown option: $1"; exit 1 ;; esac done open "$URL" ;; ``` ### Technical Analysis The script constructs `upnote://x-callback-url` URLs by directly concatenating several user-controlled values into the query string. The affected values include: - Note IDs - Notebook IDs - Filter IDs - Tag IDs - Space IDs - View modes - The `new_window` argument Unlike note titles, note content, notebook names, tag names, and search queries, the ...[truncated 2776 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. URL-encode every dynamic query parameter before adding it to a callback URL: ```bash open "upnote://x-callback-url/openNote?noteId=$(urlencode "$NOTE_ID")&new_window=$(urlencode "$NEW_WINDOW")" open "upnote://x-callback-url/openNotebook?notebookId=$(urlencode "$NOTEBOOK_ID")" open "upnote://x-callback-url/openFilter?filterId=$(urlencode "$FILTER_ID")" ``` 2. Apply the same protection to all view parameters: ```bash URL="upnote://x-callback-url/view?mode=$(urlencode "$MODE")" case $1 in --note-id) [[ $# -ge 2 ]] || { echo "Missing value for --note-id"; exit 1; } URL+="&noteId=$(urlencode "$2")" shift 2 ;; --notebook-id) [[ $# -ge 2 ]] || { echo "Missing value for --notebook-id"; exit 1; } URL+="&notebookId=$(urlencode "$2")" shift 2 ;; --tag-id) [[ $# -ge 2 ]] || { echo "Missing value for --tag-id"; exit 1; } URL+="&tagId=$(urlencode "$2")" shift 2 ;; --filter-id) [[ $# -ge 2 ]] || { echo "Missing value for --filter-id"; exit 1; } URL+="&filterId=$(urlencode "$2")" shift 2 ;; --space-id) [[ $# -ge 2 ]] || { echo "Missing value for --space-id"; exit 1; } URL+="&spaceId=$(urlencode "$2")" shift 2 ;; esac ``` 3. Validate view modes against the documented allowlist: ```bash case "$MODE" in all_notes|quick_access|templates|trash|notebooks|tags|filters|all_notebooks|all_tags) ;; *) echo "Invalid view mode: $MODE" exit 1 ;; esac ``` 4. Restrict boolean arguments to accepted values: ```bash case "$NEW_WINDOW" in true|false) ;; *) echo "new_window must be true or false" exit 1 ;; esac ``` 5. Add regression tests using values containing `&`, `=`, `#`, spaces, percent signs, Unicode characters, and missing option arguments. Verify that each supplied value remains confined to exactl ...[truncated 24 chars]
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

Static analysis

No suspicious patterns detected.