Back to skill

Security audit

Nevermined Payments

Security checks for vulnerabilities and agentic risk

Overview

This skill is a high-impact but coherent Nevermined payments integration guide that clearly discloses its use of API keys, payment tokens, spending delegations, and external Nevermined APIs.

Install only if you intend to let the agent handle Nevermined payment operations. Use sandbox first, keep API keys and payment-signature tokens out of logs, set tight delegation spending limits and short durations, pin package versions for production, avoid the global CLI where possible, and do not use the documented global settlement accessor in multi-tenant services.

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

T08 · Insecure Dependencies

Warning
Location
SKILL.md:831
Finding
Unpinned Third-Party Package Installation Creates a Supply-Chain Execution Risk## Vulnerability Details **File Location**: `SKILL.md:831` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash # 1. Install CLI npm install -g @nevermined-io/cli ``` Equivalent unpinned installation instructions also appear at: - `SKILL.md:366,371,386` - `references/a2a-integration.md:22,28` - `references/express-integration.md:8` - `references/fastapi-integration.md:8` - `references/langchain-integration.md:8,144,225` - `references/mcp-paywall.md:8` - `references/strands-integration.md:8` These include commands such as: ```bash npm install @nevermined-io/payments pip install payments-py pip install payments-py[fastapi] pnpm add @nevermined-io/payments @langchain/core @langchain/langgraph @langchain/openai ``` ### Technical Analysis The installation instructions do not specify exact package versions, integrity hashes, or a reviewed lockfile. Consequently, package managers resolve the latest compatible releases and their transitive dependencies at installation time. The code that is ultimately installed can therefore differ from the code reviewed during this audit. Package installation may execute lifecycle scripts, and imported packages can execute initialization code within the application process. The global CLI command is especially sensitive because it modifies the user-wide executable environment and may expose the installed package to broader use than the current project. The package names are consistent with the Skill's declared Nevermined payment functionality, and there is no evidence that they are currently malicious or typosquatted. The vulnerability is the uncontrolled trust in mutable future package versions. ### Attack Path 1. An attacker compromises a named package, one of its transitive dependencies, or the relevant package registry account. 2. The attacker publishes a malicious release under the existing pac ...[truncated 1118 chars]
Remediation
## Remediation Suggestions 1. Replace mutable installation commands with reviewed exact versions, for example: ```bash npm install --save-exact @nevermined-io/payments@<reviewed-version> pip install "payments-py[fastapi]==<reviewed-version>" ``` 2. Commit package lockfiles and require immutable installation modes such as `npm ci`, `pnpm install --frozen-lockfile`, or hash-verified Python requirements. 3. For Python deployments, generate requirements with hashes and install using `pip install --require-hashes -r requirements.txt`. 4. Avoid global CLI installation. Prefer a project-local pinned development dependency invoked through the package manager. 5. Review lifecycle scripts and transitive dependencies before updating pins. 6. Run package installation in a restricted build environment without production API keys or payment credentials. 7. Apply dependency scanning and registry provenance verification in CI. 8. Periodically update exact versions only after security and compatibility review.

T09 · Insecure Skill Coding Practices

Warning
Location
references/langchain-integration.md:127
Finding
Process-Global Settlement State Can Leak Billing Data Across Concurrent Tenants## Vulnerability Details **File Location**: `references/langchain-integration.md:127-140` **Vulnerability Type**: Shared mutable state and cross-request data exposure **Risk Level**: Medium ### Vulnerable Code ```python from payments_py.x402.langchain import last_settlement result = agent.invoke( {"messages": [("human", QUERY)]}, config={"configurable": {"payment_token": token}}, ) receipt = last_settlement() if receipt: print(f"credits redeemed: {receipt.credits_redeemed}") print(f"remaining balance: {receipt.remaining_balance}") print(f"transaction: {receipt.transaction}") ``` The documentation identifies the underlying unsafe state model: ```text Single-tenant only. The slot is process-global — in multi-tenant servers (concurrent settlements), the value reflects whichever invocation settled most recently. Use a callback or observability layer for multi-tenant scenarios. ``` The equivalent TypeScript limitation is documented at `references/langchain-integration.md:325`. ### Technical Analysis `last_settlement()` reads from a module-level process-global slot rather than request-local or invocation-local state. Concurrent operations share this mutable location, and every successful settlement can overwrite the receipt left by another invocation. The call to `agent.invoke()` and the later call to `last_settlement()` are not an atomic operation. Another request can settle during that interval. As a result, the caller has no reliable guarantee that the returned receipt belongs to its own invocation. This is a time-of-check/time-of-use race involving billing records. The documentation warns that the API is single-tenant only, but the example remains unsafe if copied into a concurrent web server, worker, or multi-agent runtime. ### Attack Path 1. Tenant A invokes a paid operation and completes settlement. 2. The SDK stores tenant A's receipt in the process-global settl ...[truncated 1199 chars]
Remediation
## Remediation Suggestions 1. Do not use `last_settlement()` in multi-tenant or concurrent applications. 2. Return the settlement receipt directly from the protected invocation or deliver it through an invocation-specific callback. 3. Store receipts in request-local context using Python `contextvars` or Node.js `AsyncLocalStorage`. 4. Associate each receipt with an unguessable invocation identifier and verify that identifier before exposing or persisting the receipt. 5. Ensure receipt retrieval is atomic with respect to the corresponding settlement. 6. If the SDK cannot provide request-local receipt handling, use the documented observability or callback mechanism rather than the global accessor. 7. Add concurrency tests that interleave settlements from multiple tenants and assert that no receipt crosses request boundaries. 8. Update the documentation example to fail closed outside explicitly configured single-tenant mode and place the warning before, rather than after, the sample.
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (61)

Credential Access

High
Category
Privilege Escalation
Content
- **No `billingModel` at all?** The deployment predates the discriminator — apply the `credits` rule, never pay-as-you-go.
- **Card budget caveat:** a card settle may not immediately move the delegation's `amountSpentCents`/`remainingBudgetCents` — use the settle receipt + the A5 plan balance as the source of truth for card spend, not the delegation budget.

**Calling a protected agent directly** (the common case): just send the access token as the `payment-signature` header to the agent's endpoint — the agent's own `402` response **is** your `paymentRequired`, and the agent verifies + settles for you. You only call `/settle` yourself when topping up a plan with no protected endpoint to hit.

> A dedicated `orderPlan` / `POST /protocol/plans/{id}/order` endpoint exists for an explicit, upfront stablecoin purchase, but **x402 above is the default for both rails — use `/order` only when specifically requested.**
Confidence
80% confidence
Finding
The skill instructs sending the x402 access token in the `payment-signature` header to protected agents, which is expected protocol behavior but creates a real credential-handling risk if those agents, proxies, or observability systems log headers. Since the token authorizes spend/settlement, leakage could enable replay or unauthorized paid requests until expiry or exhaustion.

Credential Access

High
Category
Privilege Escalation
Content
| Header | Direction | Description |
|---|---|---|
| `payment-signature` | Client → Server | x402 access token |
| `payment-required` | Server → Client (402) | Base64-encoded JSON with plan requirements |
| `payment-response` | Server → Client (200) | Base64-encoded JSON settlement receipt |
Confidence
82% confidence
Finding
By standardizing `payment-signature` as the carrier for x402 access tokens, the skill establishes a sensitive credential transit path that can be unintentionally exposed through default HTTP header logging in servers, reverse proxies, or debugging tools. The context makes this more dangerous because these tokens directly authorize paid access and potential spending, even if only for short periods.

Credential Access

High
Category
Privilege Escalation
Content
As a subscriber (consumer of a paid API/agent), you:
1. Order a payment plan
2. Check your credit balance
3. Generate an x402 access token
4. Send requests with the `payment-signature` header
5. Decode the settlement receipt from the `payment-response` header
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
As a subscriber (consumer of a paid API/agent), you:
1. Order a payment plan
2. Check your credit balance
3. Generate an x402 access token
4. Send requests with the `payment-signature` header
5. Decode the settlement receipt from the `payment-response` header
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
As a subscriber (consumer of a paid API/agent), you:
1. Order a payment plan
2. Check your credit balance
3. Generate an x402 access token
4. Send requests with the `payment-signature` header
5. Decode the settlement receipt from the `payment-response` header
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
As a subscriber (consumer of a paid API/agent), you:
1. Order a payment plan
2. Check your credit balance
3. Generate an x402 access token
4. Send requests with the `payment-signature` header
5. Decode the settlement receipt from the `payment-response` header
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
As a subscriber (consumer of a paid API/agent), you:
1. Order a payment plan
2. Check your credit balance
3. Generate an x402 access token
4. Send requests with the `payment-signature` header
5. Decode the settlement receipt from the `payment-response` header
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```

- **Card payment:** switch `scheme` to `nvm:card-delegation` and `network` to `stripe` (or `braintree`/`visa`) in both calls.
- **Calling a protected agent directly:** skip building `paymentRequired` — send the access token as the `payment-signature` header; the agent settles for you and returns the receipt in the `payment-response` header.
- **Proof of purchase — read `billingModel` first.** On a `credits` plan it is `success: true` and `creditsRedeemed > 0`. On a `pay-as-you-go` plan there is no credit balance, so `creditsRedeemed` and `remainingBalance` are always the string `"0"` even on a successful charge; the proof is `success: true` plus a non-empty `orderTx` (fiat) or `transaction` (crypto). Never gate on `creditsRedeemed` alone — on a card rail it reports a real charge as a decline and invites a retry. If `billingModel` is missing entirely the deployment predates it: apply the `credits` rule.

Full runbook with API-key retrieval, card enrollment, and status checks: `autonomous-operations.md`.
Confidence
75% confidence
Finding
The documentation instructs users to send the access token in a `payment-signature` header directly to an agent, but it does not clearly distinguish trusted server-to-server use from potentially unsafe client-side exposure. Because this is a bearer token tied to payment authorization and delegated spending behavior, exposing it in insecure client environments or logs could enable unauthorized paid requests until expiry or spending limits are reached.

Credential Access

High
Category
Privilege Escalation
Content
## Automatic Credit Top-Ups

When the access token carries a `delegationConfig`, the facilitator tops up the subscriber's credits automatically — no manual balance-check-then-`orderPlan` loop.

- The top-up fires at **settlement** (when a paid request is consumed), **not** when `getX402AccessToken` is called. Generating the token only pre-authorizes the spend; no credits are bought until the balance is actually short.
- **Crypto (`nvm:erc4337`)**: the facilitator executes an on-chain `order` against the subscriber's smart account.
Confidence
84% confidence
Finding
This section documents automatic top-ups driven by a delegation attached to an access token, which materially increases the consequences of token leakage. If an attacker obtains such a token or a broadly scoped delegation, they may trigger unauthorized paid requests and consume delegated spending up to the configured limit before expiration.

Exfiltration Commands

High
Category
Prompt Injection
Content
**Token redaction.** LangChain auto-captures every key in `config["configurable"]` into the parent tool span's metadata, which child spans inherit. The decorator strips `payment_token` from the parent span before opening any `nvm:*` child, so the full credential never reaches a Nevermined-emitted attribute. The abbreviated `nvm.payment_token` (`<first 16>…<last 4>`) remains for correlation. To cover non-configurable channels (custom callbacks, tool args, etc.) set `LANGSMITH_HIDE_INPUTS=true` for blanket coverage.

Observability failures are silently logged and dropped — the payment flow itself is never interrupted, and `last_settlement()` continues to return the on-chain receipt even if span emission fails.

## Decorator Configuration
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Credential Access

High
Category
Privilege Escalation
Content
## Client Usage

### Get Access Token

```typescript
const delegation = await paymentsClient.delegation.createDelegation({
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
| Header | Direction | Description |
|---|---|---|
| `payment-signature` | Client → Server | x402 access token |
| `payment-required` | Server → Client (402) | Base64-encoded payment requirements |
| `payment-response` | Server → Client (200) | Base64-encoded settlement receipt |
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
| Header | Direction | Description |
|---|---|---|
| `payment-signature` | Client → Server | x402 access token |
| `payment-required` | Server → Client (402) | Base64-encoded payment requirements |
| `payment-response` | Server → Client (200) | Base64-encoded settlement receipt |
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
| Header | Direction | Description |
|---|---|---|
| `payment-signature` | Client → Server | x402 access token |
| `payment-required` | Server → Client (402) | Base64-encoded payment requirements |
| `payment-response` | Server → Client (200) | Base64-encoded settlement receipt |
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
| Header | Direction | Description |
|---|---|---|
| `payment-signature` | Client → Server | x402 access token |
| `payment-required` | Server → Client (402) | Base64-encoded payment requirements |
| `payment-response` | Server → Client (200) | Base64-encoded settlement receipt |
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
| Header | Direction | Description |
|---|---|---|
| `payment-signature` | Client → Server | x402 access token |
| `payment-required` | Server → Client (402) | Base64-encoded payment requirements |
| `payment-response` | Server → Client (200) | Base64-encoded settlement receipt |
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

External Transmission

Medium
Category
Data Exfiltration
Content
## A2 · Check your payment methods

```bash
curl -H "Authorization: Bearer $NVM_API_KEY" \
  https://api.sandbox.nevermined.app/api/v1/payment-methods
# → [ { id, type, brand, last4, provider, status, ... } ]
```
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
If you operate an **organization**, provision Nevermined accounts for *your* customers from your backend — no member seat, recorded in your Customers CRM, and returning a **scoped key** you use to pay for your agents on their behalf. One endpoint, distinguished by `as: 'customer'`:

```bash
curl -s -XPOST -H "Authorization: Bearer $ORG_ADMIN_API_KEY" -H "Content-Type: application/json" \
  -d '{"email":"customer@example.com","as":"customer"}' \
  https://api.sandbox.nevermined.app/api/v1/organizations/account
# New / returning customer → 201, walletResult.nvmApiKey (+ userId, userWallet, isCustomer, customerRecorded) — the USABLE key
Confidence
83% confidence
Finding
This workflow provisions customer accounts and returns a usable scoped API key to backend callers, which means the skill instructs handling and transmission of newly issued credentials. While this is intended product behavior, it is security-sensitive because improper storage, logging, or overbroad backend access could leak customer-scoped keys or enable unauthorized purchases on their behalf.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
curl -s -XPOST -H "Authorization: Bearer $ORG_ADMIN_API_KEY" -H "Content-Type: application/json" \
  -d '{"email":"customer@example.com","as":"customer"}' \
  https://api.sandbox.nevermined.app/api/v1/organizations/account
# New / returning customer → 201, walletResult.nvmApiKey (+ userId, userWallet, isCustomer, customerRecorded) — the USABLE key
# Email owned by a non-customer account → 202, walletResult.consentRequired=true (consent email sent; no key or identity disclosed)
```
Confidence
84% confidence
Finding
This onboarding flow explicitly returns a usable customer API key in the response payload, creating a clear risk of credential exposure if response bodies are logged, cached, or made accessible to unauthorized operators. Because the endpoint is designed for backend automation, accidental overuse or weak authorization around who may invoke it could lead to unauthorized account provisioning and spending authority.

External Transmission

Medium
Category
Data Exfiltration
Content
--delegation-duration-secs 604800

# 6. Test against your running server
curl -X POST http://localhost:3000/chat \
  -H "Content-Type: application/json" \
  -H "payment-signature: $TOKEN" \
  -d '{"message": "Hello"}'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Medium
Confidence
89% confidence
Finding
The document explicitly states that A2A requests are authorized and charged using bearer payment tokens, but the Python client example sends requests without showing token acquisition or attachment. In a payments/authentication integration guide, this omission can cause implementers to build clients that skip authorization, misunderstand security requirements, or rely on insecure defaults if the SDK permits them.

External Transmission

Medium
Category
Data Exfiltration
Content
How an AI agent operates on Nevermined **on its own behalf** using the REST API — get an API key, enroll a card, create a delegation, purchase plans via x402, and check status. Every call here is plain HTTPS; no SDK install is required. This is the heavy-detail companion to **Track A** in `SKILL.md`.

> All bodies and response shapes below are verified against the live sandbox OpenAPI (`https://api.sandbox.nevermined.app/api/v1/rest/docs-json`). Send `Authorization: Bearer $NVM_API_KEY` on every call unless noted.
>
> Also send `Nevermined-Version: <MAJOR.MINOR>` on every call to pin the wire shape across platform releases — discover the supported range with `GET /api/v1/meta/versions` and default to its `current`. Never silently change a key's stored pin.
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
How an AI agent operates on Nevermined **on its own behalf** using the REST API — get an API key, enroll a card, create a delegation, purchase plans via x402, and check status. Every call here is plain HTTPS; no SDK install is required. This is the heavy-detail companion to **Track A** in `SKILL.md`.

> All bodies and response shapes below are verified against the live sandbox OpenAPI (`https://api.sandbox.nevermined.app/api/v1/rest/docs-json`). Send `Authorization: Bearer $NVM_API_KEY` on every call unless noted.
>
> Also send `Nevermined-Version: <MAJOR.MINOR>` on every call to pin the wire shape across platform releases — discover the supported range with `GET /api/v1/meta/versions` and default to its `current`. Never silently change a key's stored pin.
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
How an AI agent operates on Nevermined **on its own behalf** using the REST API — get an API key, enroll a card, create a delegation, purchase plans via x402, and check status. Every call here is plain HTTPS; no SDK install is required. This is the heavy-detail companion to **Track A** in `SKILL.md`.

> All bodies and response shapes below are verified against the live sandbox OpenAPI (`https://api.sandbox.nevermined.app/api/v1/rest/docs-json`). Send `Authorization: Bearer $NVM_API_KEY` on every call unless noted.
>
> Also send `Nevermined-Version: <MAJOR.MINOR>` on every call to pin the wire shape across platform releases — discover the supported range with `GET /api/v1/meta/versions` and default to its `current`. Never silently change a key's stored pin.
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
How an AI agent operates on Nevermined **on its own behalf** using the REST API — get an API key, enroll a card, create a delegation, purchase plans via x402, and check status. Every call here is plain HTTPS; no SDK install is required. This is the heavy-detail companion to **Track A** in `SKILL.md`.

> All bodies and response shapes below are verified against the live sandbox OpenAPI (`https://api.sandbox.nevermined.app/api/v1/rest/docs-json`). Send `Authorization: Bearer $NVM_API_KEY` on every call unless noted.
>
> Also send `Nevermined-Version: <MAJOR.MINOR>` on every call to pin the wire shape across platform releases — discover the supported range with `GET /api/v1/meta/versions` and default to its `current`. Never silently change a key's stored pin.
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/customer-onboarding.md:65

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/express-integration.md:186

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/fastapi-integration.md:284

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/langchain-integration.md:371

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/strands-integration.md:220