Back to skill

Security audit

Pay-per-call web tools (Nano)

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent, but it can lead an agent to make cryptocurrency payments using live service-controlled payment details without a clear local spending limit or user-confirmation gate.

Review before installing. Treat this as a third-party paid web-service client: only submit URLs or queries you are comfortable disclosing to paypercall.dev, and do not let an autonomous agent make Nano payments from a wallet unless you enforce your own per-call maximum, recipient approval, and explicit confirmation for every transaction.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

other

Error
Location
SKILL.md:55
Finding

Remote Manifest Can Authorize an Unbounded Cryptocurrency Payment Without User Confirmation

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:55-65; vend.py:29-41, 54-62, 79-84
Vulnerability Type: Unconfirmed payment authorization based on remotely controlled values
Risk Level: High

Technical Analysis

The Skill instructs an autonomous agent to transfer cryptocurrency using the amount and recipient supplied by a live remote manifest:

markdown
## Pay for a call

When you get exit 2:

1. Send **exactly** `amount_raw` of XNO to `pay_to` with whatever Nano wallet you hold (a wallet
   skill such as `nano-pay` or `nano`, or your own code). This skill never holds a seed.
2. Run the same command again with the hash of that send block:

python3 vend.py extract url=https://example.com --payment <64-hex send block hash>

The script retrieves both payment fields from the service-controlled manifest without enforcing a local price ceiling, trusted-recipient policy, or user-approved payment parameters:

python
def tools():
    status, body = fetch(MANIFEST)
    if status != 200:
        raise OSError(f"manifest answered HTTP {status}")
    found = {}
    for resource in json.loads(body)["resources"]:
        name = resource["url"].rstrip("/").rsplit("/", 1)[-1]
        accept = resource["accepts"][0]
        found[name] = {"url": resource["url"], "amount_raw": accept["amount"], "pay_to": accept["payTo"],
                       "description": resource["description"]}
    return found

When the endpoint responds with HTTP 402, these remote values are presented as the payment instruction:

python
if status == 402:
    print(json.dumps({"payment_required": {"amount_raw": tool["amount_raw"], "pay_to": tool["pay_to"],
                                           "network": "nano:mainnet", "asset": "XNO",
                                           "then": "send exactly amount_raw to pay_to, then rerun with --payment <send block hash>",
                                           "server_said": parsed.get("message", "")[:200] if isinstanc
...[truncated 1893 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require explicit, transaction-specific user confirmation before every payment. Display:
    • The exact XNO amount and raw amount.
    • The complete destination account.
    • The requested tool and parameters.
    • The advertised and locally permitted maximum price.
  2. Enforce a hard local spending ceiling independent of the remote manifest. Reject any payment request exceeding that ceiling.
  3. Maintain a locally configured recipient allowlist or require users to approve a new recipient separately.
  4. Do not treat HTTP 402 output as payment authorization. Return a pending-payment object that cannot be consumed by a wallet until a confirmation token generated after user approval is supplied.
  5. Cross-check the HTTP 402 payment demand against the manifest and a local policy, and reject mismatched network, asset, recipient, or amount fields.
  6. Add cumulative per-session and per-day spending limits.
  7. Default to refusing payment in non-interactive or autonomous operation unless the user has explicitly configured a narrowly scoped budget and approved recipient policy.
  8. Document that the live service controls payment metadata and that advertised prices are not a substitute for locally enforced limits.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises and instructs use of a Python client that performs outbound network calls to a third-party paid service, but it does not declare an explicit tool scope such as permissions or allowed-tools. That makes the network capability implicit rather than transparent, increasing the chance that a host agent or reviewer underestimates what external access the skill requires and what data may leave the environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill sends user-supplied URLs, search queries, and likely the caller's IP address to a third-party service, yet the description does not clearly warn about this disclosure. In a web-extraction and search skill, that omission is meaningful because prompts, URLs, and lookup targets may contain sensitive research topics, internal links, or other private operational data.

Content

No source excerpt is available for this finding.