pop-pay 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -322
- package/dashboard/dashboard.css +193 -0
- package/dashboard/dashboard.js +135 -0
- package/dashboard/index.html +89 -0
- package/dist/cli-dashboard.d.ts +3 -0
- package/dist/cli-dashboard.d.ts.map +1 -0
- package/dist/cli-dashboard.js +28 -0
- package/dist/cli-dashboard.js.map +1 -0
- package/dist/cli-main.d.ts +7 -0
- package/dist/cli-main.d.ts.map +1 -0
- package/dist/cli-main.js +81 -0
- package/dist/cli-main.js.map +1 -0
- package/dist/dashboard.d.ts +9 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +122 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/engine/injector.d.ts.map +1 -1
- package/dist/engine/injector.js +60 -10
- package/dist/engine/injector.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -9,220 +9,28 @@
|
|
|
9
9
|
# Point One Percent — pop-pay
|
|
10
10
|
<p align="left"><i>it only takes <b>0.1%</b> of Hallucination to drain <b>100%</b> of your wallet.</i></p>
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
The runtime security layer for AI agent commerce. Card credentials are injected directly into the browser DOM via CDP — they never enter the agent's context window. One hallucinated prompt can't drain a wallet it can't see.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
## Getting Started
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
<img src="assets/runtime_demo.gif" alt="Point One Percent — live CDP injection demo" width="800">
|
|
18
|
-
</p>
|
|
19
|
-
|
|
20
|
-
pop-pay is an open-source (MIT) runtime security layer that protects AI agents during online purchases. It works with OpenClaw, NemoClaw, Claude Code, OpenHands, and any MCP-compatible framework.
|
|
21
|
-
|
|
22
|
-
## Architecture: Five Security Primitives
|
|
23
|
-
|
|
24
|
-
| Primitive | What it does |
|
|
25
|
-
|-----------|-------------|
|
|
26
|
-
| **Context Isolation Layer** | Card credentials are injected directly into the browser DOM via CDP — they never enter the agent's process or LLM context window. Prompt injection can't steal what the agent doesn't have. |
|
|
27
|
-
| **Intent Verification Engine** | Hybrid keyword + LLM guardrail evaluates whether a purchase *should* happen — not just whether it *can*. [95% accuracy on 20-scenario benchmark.](./docs/GUARDRAIL_BENCHMARK.md) |
|
|
28
|
-
| **Human Trust Anchor** | Configurable human-in-the-loop approval for high-value or unrecognized transactions. |
|
|
29
|
-
| **Zero-Knowledge Card Surface** | Agent only sees masked tokens (`****-4242`). Real data is stored in an AES-256-GCM encrypted vault. |
|
|
30
|
-
| **Ephemeral Authorization Scope** | Each payment approval is single-use with TOCTOU domain guard — an approved session can't be redirected to a malicious merchant. |
|
|
31
|
-
|
|
32
|
-
> See [THREAT_MODEL.md](./docs/THREAT_MODEL.md) for the full STRIDE analysis and [COMPLIANCE_FAQ.md](./docs/COMPLIANCE_FAQ.md) for enterprise compliance details.
|
|
33
|
-
|
|
34
|
-
## Guardrail Benchmark
|
|
35
|
-
|
|
36
|
-
| Layer | Score | Notes |
|
|
37
|
-
|-------|-------|-------|
|
|
38
|
-
| Keyword only | 14/20 (70%) | Fast, zero-cost, catches obvious violations |
|
|
39
|
-
| **Hybrid (Keyword + LLM)** | **19/20 (95%)** | LLM resolves 5 of 6 keyword failures |
|
|
40
|
-
|
|
41
|
-
| Feature | AgentPayy | AgentWallet | Prava | **pop-pay** |
|
|
42
|
-
|---------|-----------|-------------|-------|------------|
|
|
43
|
-
| Enforcement | Mock alert() | Rule-based | Spending limits | **Semantic validation** |
|
|
44
|
-
| Intent check | None | Agent-provided text | None | **Context-aware LLM** |
|
|
45
|
-
| Injection-proof | No | No | No | **Yes** |
|
|
46
|
-
|
|
47
|
-
## Two Deployment Modes
|
|
48
|
-
|
|
49
|
-
### BYOC — Bring Your Own Card (Local)
|
|
50
|
-
The agent **never** receives the true card number — it only sees `****-4242`. When checkout is reached, the Context Isolation Layer attaches via CDP, traverses all cross-origin iframes (Stripe Elements, Adyen, etc.), and injects credentials directly into the DOM. Runs entirely on your machine via Node.js — no SaaS, no login, no external account.
|
|
51
|
-
|
|
52
|
-
### Enterprise — Stripe Issuing
|
|
53
|
-
For cloud-hosted AI fleets: programmatically issue single-use virtual cards via Stripe API, with per-agent budgets and full audit trails.
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## Ecosystem Position
|
|
58
|
-
|
|
59
|
-
pop-pay is the agent's **Policy Enforcement Point** — it evaluates, approves, and injects. It does NOT navigate websites or solve CAPTCHAs — that's the browser agent's job.
|
|
60
|
-
|
|
61
|
-
### The Handshake: How Point One Percent and Browser Agents Work Together
|
|
62
|
-
|
|
63
|
-
The real power emerges when Point One Percent is paired with a browser automation agent (e.g., OpenHands, browser-use, Skyvern). The workflow is a clean division of labor:
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
1. [Browser Agent] Navigates to a site, scrapes product info, reaches checkout.
|
|
67
|
-
│
|
|
68
|
-
│ (Hit a paywall / payment form)
|
|
69
|
-
▼
|
|
70
|
-
2. [Browser Agent → POP MCP] Calls request_virtual_card(amount, vendor, reasoning)
|
|
71
|
-
│
|
|
72
|
-
│ (Point One Percent evaluates: budget OK? vendor approved? no hallucination?)
|
|
73
|
-
▼
|
|
74
|
-
3. [POP] Issues a one-time virtual card (Stripe mode) or uses BYOC vault credentials.
|
|
75
|
-
Full card credentials handled only by the local trusted process —
|
|
76
|
-
never exposed to the agent or LLM context.
|
|
77
|
-
│
|
|
78
|
-
▼
|
|
79
|
-
4. [POP] Injects real credentials into the checkout form via CDP.
|
|
80
|
-
The agent receives only a transaction confirmation — no card details.
|
|
81
|
-
│
|
|
82
|
-
▼
|
|
83
|
-
5. [Browser Agent] Clicks the submit button to complete the transaction.
|
|
84
|
-
│
|
|
85
|
-
▼
|
|
86
|
-
6. [The Vault] Logs the transaction. Card session is immediately burned.
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Supported Integrations
|
|
90
|
-
|
|
91
|
-
| Integration path | Works with |
|
|
92
|
-
|---|---|
|
|
93
|
-
| **MCP Tool** | Claude Code, OpenClaw, NemoClaw, OpenHands, any MCP-compatible host |
|
|
94
|
-
| **Node.js SDK** | Custom Playwright scripts, Puppeteer automation, gemini-cli |
|
|
95
|
-
|
|
96
|
-
> **Any browser-capable agent** (Claude Code, OpenClaw, browser-use, Skyvern, etc.) gets full CDP injection — card is auto-filled into the payment form, the agent only ever sees the masked confirmation (`****-****-****-4242`). See the **[Integration Guide](./docs/INTEGRATION_GUIDE.md)** for setup instructions and System Prompt templates.
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## Installation
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
npm install pop-pay
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Quick Start for Claude Code / OpenHands
|
|
107
|
-
|
|
108
|
-
If you're using Claude Code, OpenHands, or any MCP-compatible agentic framework, you can get Point One Percent running in under 2 minutes:
|
|
109
|
-
|
|
110
|
-
### Step 1: Initialize the Credential Vault
|
|
111
|
-
|
|
112
|
-
Credentials are stored in an AES-256-GCM encrypted vault — no plaintext `.env` required.
|
|
16
|
+
### 1. Initialize the credential vault
|
|
113
17
|
|
|
114
18
|
```bash
|
|
115
|
-
npx pop-init-vault
|
|
19
|
+
npx -y pop-pay pop-init-vault
|
|
116
20
|
```
|
|
117
21
|
|
|
118
|
-
This
|
|
22
|
+
This encrypts your card credentials into `~/.config/pop-pay/vault.enc` (AES-256-GCM). The MCP server decrypts automatically at startup.
|
|
119
23
|
|
|
120
|
-
|
|
24
|
+
For stronger protection (recommended — blocks agents with shell access):
|
|
121
25
|
|
|
122
26
|
```bash
|
|
123
|
-
npx pop-init-vault --passphrase # one-time setup
|
|
124
|
-
npx pop-unlock # run once before each
|
|
27
|
+
npx -y pop-pay pop-init-vault --passphrase # one-time setup
|
|
28
|
+
npx -y pop-pay pop-unlock # run once before each session
|
|
125
29
|
```
|
|
126
30
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
**Security levels (lowest → highest):**
|
|
130
|
-
|
|
131
|
-
| Mode | Protects against |
|
|
132
|
-
|---|---|
|
|
133
|
-
| `.env` file (legacy) | Nothing — plaintext on disk |
|
|
134
|
-
| Vault, machine key, OSS source | File-read agents |
|
|
135
|
-
| Vault, machine key, `npm install pop-pay` | File-read agents + casual shell inspection |
|
|
136
|
-
| Vault + passphrase | File-read agents + shell agents |
|
|
137
|
-
| Stripe Issuing (commercial) | All local threats — no credentials stored |
|
|
138
|
-
|
|
139
|
-
> **Policy & non-credential config** (allowed vendors, spending limits, CDP URL) is still read from `~/.config/pop-pay/.env`. Only card credentials moved to the vault.
|
|
140
|
-
|
|
141
|
-
### Step 2: Launch Chrome & Get MCP Commands
|
|
142
|
-
|
|
143
|
-
```bash
|
|
144
|
-
npx pop-launch --print-mcp
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
This launches Chrome with CDP enabled and prints the exact `claude mcp add` commands to run.
|
|
148
|
-
|
|
149
|
-
### Step 3: Add to Claude Code
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
claude mcp add pop-pay -- npx pop-pay launch-mcp
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
> `--scope user` (optional) stores the registration in `~/.claude.json` — available in every Claude Code session.
|
|
156
|
-
|
|
157
|
-
### Step 4: Configure Policy
|
|
158
|
-
|
|
159
|
-
Edit `~/.config/pop-pay/.env` to set your spending limits and allowed vendors:
|
|
160
|
-
|
|
161
|
-
| Variable | Default | Description |
|
|
162
|
-
|---|---|---|
|
|
163
|
-
| `POP_ALLOWED_CATEGORIES` | `["aws","cloudflare"]` | Vendors the agent is allowed to pay — see [Categories Cookbook](./docs/CATEGORIES_COOKBOOK.md) |
|
|
164
|
-
| `POP_MAX_PER_TX` | `100.0` | Max $ per transaction |
|
|
165
|
-
| `POP_MAX_DAILY` | `500.0` | Max $ per day |
|
|
166
|
-
| `POP_BLOCK_LOOPS` | `true` | Block hallucination/retry loops |
|
|
167
|
-
| `POP_AUTO_INJECT` | `true` | Enable CDP card injection |
|
|
168
|
-
| `POP_GUARDRAIL_ENGINE` | `keyword` | Guardrail engine: `keyword` (zero-cost, default) or `llm` (semantic, two-layer) — see [Guardrail Mode](#guardrail-mode-keyword-vs-llm) |
|
|
169
|
-
| `POP_BILLING_FIRST_NAME` / `POP_BILLING_LAST_NAME` | _(empty)_ | Auto-fill name fields on checkout pages |
|
|
170
|
-
| `POP_BILLING_EMAIL` | _(empty)_ | Auto-fill email |
|
|
171
|
-
| `POP_BILLING_PHONE` | _(empty)_ | E.164 format — auto-fill combined phone input |
|
|
172
|
-
| `POP_BILLING_PHONE_COUNTRY_CODE` | _(empty)_ | ISO code (`"US"`) or dial prefix (`"+1"`) — fills country code dropdown |
|
|
173
|
-
| `POP_BILLING_STREET` / `POP_BILLING_CITY` / `POP_BILLING_STATE` / `POP_BILLING_COUNTRY` / `POP_BILLING_ZIP` | _(empty)_ | Auto-fill address fields; state and country matched fuzzily |
|
|
174
|
-
| `POP_ALLOWED_PAYMENT_PROCESSORS` | `[]` | Extra third-party payment processor domains to trust (pop-pay ships with 20 built-in) |
|
|
175
|
-
| `POP_WEBHOOK_URL` | _(empty)_ | Webhook URL for Slack/Teams/PagerDuty notifications |
|
|
176
|
-
|
|
177
|
-
> **After editing `.env`, fully close and reopen Claude Code.** The MCP server loads configuration at startup — `!claude mcp list` alone is not sufficient to pick up `.env` changes.
|
|
178
|
-
|
|
179
|
-
#### Guardrail Mode: Keyword vs LLM
|
|
180
|
-
|
|
181
|
-
Point One Percent ships with two guardrail engines. You switch between them with a single env var:
|
|
182
|
-
|
|
183
|
-
| | `keyword` (default) | `llm` |
|
|
184
|
-
|---|---|---|
|
|
185
|
-
| **How it works** | Blocks requests whose `reasoning` string contains suspicious keywords (e.g. "retry", "failed again", "ignore previous instructions") | Sends the agent's `reasoning` to an LLM for deep semantic analysis |
|
|
186
|
-
| **What it catches** | Obvious loops, hallucination phrases, prompt injection attempts | Subtle off-topic purchases, logical inconsistencies, policy violations that keyword matching misses |
|
|
187
|
-
| **Cost** | Zero — no API calls, instant | One LLM call per `request_virtual_card` invocation |
|
|
188
|
-
| **Dependencies** | None | Any OpenAI-compatible endpoint |
|
|
189
|
-
| **Best for** | Development, low-risk workflows, cost-sensitive setups | Production, high-value transactions, untrusted agent pipelines |
|
|
190
|
-
|
|
191
|
-
> **Tip:** `keyword` mode requires no extra config. To enable LLM mode, see the [full configuration reference in the Integration Guide §1](./docs/INTEGRATION_GUIDE.md#guardrail-mode-configuration).
|
|
192
|
-
|
|
193
|
-
### Step 5: Use It
|
|
194
|
-
|
|
195
|
-
Your agent now has access to these tools:
|
|
196
|
-
|
|
197
|
-
| Tool | When to use |
|
|
198
|
-
|---|---|
|
|
199
|
-
| `request_purchaser_info` | Billing/contact info page (name, email, phone, address) — no card fields visible yet |
|
|
200
|
-
| `request_virtual_card` | Payment page — card fields are visible. Prompt injection scan runs automatically inside this call. |
|
|
201
|
-
|
|
202
|
-
**Single-page checkout** (e.g. Wikipedia donate): agent calls `request_virtual_card`.
|
|
203
|
-
**Two-page checkout** (e.g. billing info → payment): agent calls `request_purchaser_info` first, then `request_virtual_card`.
|
|
204
|
-
|
|
205
|
-
When it encounters a paywall:
|
|
206
|
-
|
|
207
|
-
```
|
|
208
|
-
Agent: "I need to purchase an API key from AWS for $15 to continue."
|
|
209
|
-
[Tool Call] request_virtual_card(amount=15.0, vendor="AWS", reasoning="Need API key for deployment")
|
|
210
|
-
[POP] Payment approved. Card Issued: ****4242, Expiry: 12/25, Amount: 15.0
|
|
211
|
-
Agent: "Purchase successful, continuing workflow."
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
If the agent hallucinates or tries to overspend:
|
|
215
|
-
```
|
|
216
|
-
Agent: "Let me retry buying compute... the previous attempt failed again."
|
|
217
|
-
[Tool Call] request_virtual_card(amount=50.0, vendor="AWS", reasoning="failed again, retry loop")
|
|
218
|
-
[POP] Payment rejected. Reason: Hallucination or infinite loop detected in reasoning
|
|
219
|
-
```
|
|
31
|
+
### 2. Add to your MCP client
|
|
220
32
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
## Setup
|
|
224
|
-
|
|
225
|
-
**Standard config** works across most MCP-compatible tools:
|
|
33
|
+
Standard config for any MCP-compatible client:
|
|
226
34
|
|
|
227
35
|
```json
|
|
228
36
|
{
|
|
@@ -231,123 +39,50 @@ Agent: "Let me retry buying compute... the previous attempt failed again."
|
|
|
231
39
|
"command": "npx",
|
|
232
40
|
"args": ["-y", "pop-pay", "launch-mcp"],
|
|
233
41
|
"env": {
|
|
234
|
-
"POP_CDP_URL": "http://localhost:9222"
|
|
235
|
-
"POP_ALLOWED_CATEGORIES": "[\"aws\",\"cloudflare\"]",
|
|
236
|
-
"POP_MAX_PER_TX": "100.0",
|
|
237
|
-
"POP_MAX_DAILY": "500.0",
|
|
238
|
-
"POP_GUARDRAIL_ENGINE": "keyword"
|
|
42
|
+
"POP_CDP_URL": "http://localhost:9222"
|
|
239
43
|
}
|
|
240
44
|
}
|
|
241
45
|
}
|
|
242
46
|
}
|
|
243
47
|
```
|
|
244
48
|
|
|
245
|
-
[<img src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20MCP%20Server&color=0098FF" alt="Install in VS Code">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522pop-pay%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522pop-pay%2522%252C%2522launch-mcp%2522%255D%252C%2522env%2522%253A%257B%2522POP_CDP_URL%2522%253A%2522http%253A%252F%252Flocalhost%253A9222%2522%257D%257D) [<img alt="Install in VS Code Insiders" src="https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20MCP%20Server&color=24bfa5">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522pop-pay%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522pop-pay%2522%252C%2522launch-mcp%2522%255D%252C%2522env%2522%253A%257B%2522POP_CDP_URL%2522%253A%2522http%253A%252F%252Flocalhost%253A9222%2522%257D%257D)
|
|
49
|
+
[<img src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20MCP%20Server&color=0098FF" alt="Install in VS Code">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522pop-pay%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522pop-pay%2522%252C%2522launch-mcp%2522%255D%252C%2522env%2522%253A%257B%2522POP_CDP_URL%2522%253A%2522http%253A%252F%252Flocalhost%253A9222%2522%257D%257D) [<img alt="Install in VS Code Insiders" src="https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20MCP%20Server&color=24bfa5">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522pop-pay%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522pop-pay%2522%252C%2522launch-mcp%2522%255D%252C%2522env%2522%253A%257B%2522POP_CDP_URL%2522%253A%2522http%253A%252F%252Flocalhost%253A9222%2522%257D%257D) [<img src="https://img.shields.io/badge/Cursor-Cursor?style=flat-square&label=Install%20MCP%20Server&color=5C2D91" alt="Install in Cursor">](cursor://anysphere.cursor-deeplink/mcp/install?name=pop-pay&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBvcC1wYXkiLCJsYXVuY2gtbWNwIl0sImVudiI6eyJQT1BfQ0RQX1VSTCI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyMiJ9fQ==)
|
|
246
50
|
|
|
247
51
|
<details>
|
|
248
52
|
<summary>Claude Code</summary>
|
|
249
53
|
|
|
250
|
-
|
|
251
|
-
claude mcp add pop-pay -- npx -y pop-pay launch-mcp
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
To configure spending limits and allowed vendors, set environment variables:
|
|
54
|
+
Claude Code uses its own CLI — the JSON config above is not needed.
|
|
255
55
|
|
|
256
56
|
```bash
|
|
257
|
-
claude mcp add pop-pay
|
|
258
|
-
-e POP_CDP_URL=http://localhost:9222 \
|
|
259
|
-
-e POP_ALLOWED_CATEGORIES='["aws","cloudflare"]' \
|
|
260
|
-
-e POP_MAX_PER_TX=100.0 \
|
|
261
|
-
-e POP_MAX_DAILY=500.0 \
|
|
262
|
-
-e POP_GUARDRAIL_ENGINE=keyword \
|
|
263
|
-
-- npx -y pop-pay launch-mcp
|
|
57
|
+
claude mcp add --scope user pop-pay -- npx -y pop-pay launch-mcp
|
|
264
58
|
```
|
|
265
59
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
</details>
|
|
269
|
-
|
|
270
|
-
<details>
|
|
271
|
-
<summary>Cursor</summary>
|
|
272
|
-
|
|
273
|
-
[<img src="https://img.shields.io/badge/Cursor-Cursor?style=flat-square&label=Install%20MCP%20Server&color=5C2D91" alt="Install in Cursor">](cursor://anysphere.cursor-deeplink/mcp/install?name=pop-pay&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBvcC1wYXkiLCJsYXVuY2gtbWNwIl0sImVudiI6eyJQT1BfQ0RQX1VSTCI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTIyMiJ9fQ==)
|
|
274
|
-
|
|
275
|
-
Or add manually to `~/.cursor/mcp.json`:
|
|
276
|
-
|
|
277
|
-
```json
|
|
278
|
-
{
|
|
279
|
-
"mcpServers": {
|
|
280
|
-
"pop-pay": {
|
|
281
|
-
"command": "npx",
|
|
282
|
-
"args": ["-y", "pop-pay", "launch-mcp"],
|
|
283
|
-
"env": {
|
|
284
|
-
"POP_CDP_URL": "http://localhost:9222",
|
|
285
|
-
"POP_ALLOWED_CATEGORIES": "[\"aws\",\"cloudflare\"]",
|
|
286
|
-
"POP_MAX_PER_TX": "100.0",
|
|
287
|
-
"POP_MAX_DAILY": "500.0",
|
|
288
|
-
"POP_GUARDRAIL_ENGINE": "keyword"
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
```
|
|
60
|
+
`--scope user` makes it available across all projects. To remove: `claude mcp remove pop-pay`
|
|
294
61
|
|
|
295
62
|
</details>
|
|
296
63
|
|
|
297
64
|
<details>
|
|
298
|
-
<summary>Windsurf</summary>
|
|
299
|
-
|
|
300
|
-
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
65
|
+
<summary>Cursor / Windsurf / VS Code</summary>
|
|
301
66
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
"command": "npx",
|
|
307
|
-
"args": ["-y", "pop-pay", "launch-mcp"],
|
|
308
|
-
"env": {
|
|
309
|
-
"POP_CDP_URL": "http://localhost:9222",
|
|
310
|
-
"POP_ALLOWED_CATEGORIES": "[\"aws\",\"cloudflare\"]",
|
|
311
|
-
"POP_MAX_PER_TX": "100.0",
|
|
312
|
-
"POP_MAX_DAILY": "500.0",
|
|
313
|
-
"POP_GUARDRAIL_ENGINE": "keyword"
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
```
|
|
67
|
+
Add the JSON config above to:
|
|
68
|
+
- **Cursor**: `~/.cursor/mcp.json`
|
|
69
|
+
- **Windsurf**: `~/.codeium/windsurf/mcp_config.json`
|
|
70
|
+
- **VS Code (Copilot)**: `.vscode/mcp.json` in project root
|
|
319
71
|
|
|
320
72
|
</details>
|
|
321
73
|
|
|
322
74
|
<details>
|
|
323
|
-
<summary>
|
|
75
|
+
<summary>OpenClaw / NemoClaw</summary>
|
|
324
76
|
|
|
325
|
-
|
|
77
|
+
OpenClaw has its own CLI — the JSON config above is not needed.
|
|
326
78
|
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
"mcpServers": {
|
|
330
|
-
"pop-pay": {
|
|
331
|
-
"command": "npx",
|
|
332
|
-
"args": ["-y", "pop-pay", "launch-mcp"],
|
|
333
|
-
"env": {
|
|
334
|
-
"POP_CDP_URL": "http://localhost:9222",
|
|
335
|
-
"POP_ALLOWED_CATEGORIES": "[\"aws\",\"cloudflare\"]",
|
|
336
|
-
"POP_MAX_PER_TX": "100.0",
|
|
337
|
-
"POP_MAX_DAILY": "500.0",
|
|
338
|
-
"POP_GUARDRAIL_ENGINE": "keyword"
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
79
|
+
```bash
|
|
80
|
+
openclaw mcp add pop-pay -- npx -y pop-pay launch-mcp
|
|
343
81
|
```
|
|
344
82
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
<details>
|
|
348
|
-
<summary>OpenClaw / NemoClaw</summary>
|
|
83
|
+
Or add to `~/.openclaw/mcp_servers.json` using the JSON config above.
|
|
349
84
|
|
|
350
|
-
|
|
85
|
+
For System Prompt templates and NemoClaw sandbox setup, see [Integration Guide §4](./docs/INTEGRATION_GUIDE.md).
|
|
351
86
|
|
|
352
87
|
</details>
|
|
353
88
|
|
|
@@ -358,57 +93,71 @@ pop-pay works as an MCP tool with OpenClaw and NemoClaw. Use the standard config
|
|
|
358
93
|
docker-compose up -d
|
|
359
94
|
```
|
|
360
95
|
|
|
361
|
-
Runs
|
|
96
|
+
Runs the MCP server + headless Chromium with CDP. Mount your encrypted vault from the host.
|
|
362
97
|
|
|
363
98
|
</details>
|
|
364
99
|
|
|
365
|
-
|
|
100
|
+
### 3. Launch Chrome with CDP and start using
|
|
366
101
|
|
|
367
|
-
|
|
102
|
+
```bash
|
|
103
|
+
npx -y pop-pay launch
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Restart your MCP client. The agent now has access to pop-pay's MCP tools.
|
|
368
107
|
|
|
369
108
|
## MCP Tools
|
|
370
109
|
|
|
371
110
|
| Tool | Description |
|
|
372
111
|
|:---|:---|
|
|
373
|
-
| `request_virtual_card` | Issue a
|
|
374
|
-
| `request_purchaser_info` | Auto-fill billing/contact info
|
|
112
|
+
| `request_virtual_card` | Issue a virtual card and inject credentials into the checkout page via CDP. |
|
|
113
|
+
| `request_purchaser_info` | Auto-fill billing/contact info (name, address, email, phone). |
|
|
375
114
|
| `request_x402_payment` | Pay for API calls via the x402 HTTP payment protocol. |
|
|
376
|
-
| `page_snapshot` |
|
|
115
|
+
| `page_snapshot` | Scan a checkout page for hidden prompt injections or anomalies. |
|
|
377
116
|
|
|
378
|
-
##
|
|
117
|
+
## Configuration
|
|
379
118
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
|
383
|
-
|
|
384
|
-
|
|
|
385
|
-
|
|
|
119
|
+
Core variables in `~/.config/pop-pay/.env`. See [ENV_REFERENCE.md](./docs/ENV_REFERENCE.md) for the full list.
|
|
120
|
+
|
|
121
|
+
| Variable | Default | Description |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `POP_ALLOWED_CATEGORIES` | `["aws","cloudflare"]` | Approved vendor categories — see [Categories Cookbook](./docs/CATEGORIES_COOKBOOK.md) |
|
|
124
|
+
| `POP_MAX_PER_TX` | `100.0` | Max USD per transaction |
|
|
125
|
+
| `POP_MAX_DAILY` | `500.0` | Max USD per day |
|
|
126
|
+
| `POP_BLOCK_LOOPS` | `true` | Block hallucination/retry loops |
|
|
127
|
+
| `POP_AUTO_INJECT` | `true` | Enable CDP card injection |
|
|
128
|
+
| `POP_GUARDRAIL_ENGINE` | `keyword` | `keyword` (zero-cost) or `llm` (semantic) |
|
|
386
129
|
|
|
387
|
-
|
|
130
|
+
### Guardrail Mode
|
|
388
131
|
|
|
389
|
-
|
|
132
|
+
| | `keyword` (default) | `llm` |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| **Mechanism** | Keyword matching on reasoning string | Semantic analysis via LLM |
|
|
135
|
+
| **Cost** | Zero — no API calls | One LLM call per request |
|
|
136
|
+
| **Best for** | Development, low-risk workflows | Production, high-value transactions |
|
|
390
137
|
|
|
391
|
-
>
|
|
138
|
+
> To enable LLM mode, see [Integration Guide §1](./docs/INTEGRATION_GUIDE.md#guardrail-mode-configuration).
|
|
392
139
|
|
|
393
|
-
|
|
140
|
+
## Providers
|
|
394
141
|
|
|
395
|
-
|
|
142
|
+
| Provider | Description |
|
|
143
|
+
|:---|:---|
|
|
144
|
+
| **BYOC** (default) | Bring Your Own Card — encrypted vault credentials, local CDP injection. |
|
|
145
|
+
| **Stripe Issuing** | Real virtual cards via Stripe API. Requires `POP_STRIPE_KEY`. |
|
|
146
|
+
| **Lithic** | Multi-issuer adapter (Stripe Issuing / Lithic). |
|
|
147
|
+
| **Mock** | Test mode with generated card numbers for development. |
|
|
396
148
|
|
|
397
|
-
|
|
149
|
+
**Priority:** Stripe Issuing → BYOC Local → Mock.
|
|
398
150
|
|
|
399
|
-
|
|
151
|
+
## Security
|
|
400
152
|
|
|
401
153
|
| Layer | Defense |
|
|
402
154
|
|---|---|
|
|
403
|
-
| **
|
|
404
|
-
| **
|
|
405
|
-
| **
|
|
406
|
-
| **
|
|
407
|
-
| **Repr redaction** | Masked card output in all logs and responses; credentials cannot leak via tracebacks |
|
|
408
|
-
| **Process isolation** | Agent communicates via MCP JSON-RPC as a separate process — cannot access MCP server memory or env vars through the protocol |
|
|
409
|
-
| **Native security layer** | XOR-split salt storage and scrypt key derivation handled in a stripped Rust binary (napi-rs) |
|
|
155
|
+
| **Context Isolation** | Card credentials never enter the agent's context window or logs |
|
|
156
|
+
| **Encrypted Vault** | AES-256-GCM with XOR-split salt and native scrypt key derivation (Rust) |
|
|
157
|
+
| **TOCTOU Guard** | Domain verified at the moment of CDP injection — blocks redirect attacks |
|
|
158
|
+
| **Repr Redaction** | Automatic masking (`****-4242`) in all MCP responses, logs, and tracebacks |
|
|
410
159
|
|
|
411
|
-
See [THREAT_MODEL.md](./docs/THREAT_MODEL.md) for the full STRIDE analysis and
|
|
160
|
+
See [THREAT_MODEL.md](./docs/THREAT_MODEL.md) for the full STRIDE analysis and [COMPLIANCE_FAQ.md](./docs/COMPLIANCE_FAQ.md) for enterprise details.
|
|
412
161
|
|
|
413
162
|
## Architecture
|
|
414
163
|
|
|
@@ -420,10 +169,10 @@ See [THREAT_MODEL.md](./docs/THREAT_MODEL.md) for the full STRIDE analysis and r
|
|
|
420
169
|
## Documentation
|
|
421
170
|
|
|
422
171
|
- [Threat Model](docs/THREAT_MODEL.md) — STRIDE analysis, 5 security primitives, 10 attack scenarios
|
|
423
|
-
- [Guardrail Benchmark](docs/GUARDRAIL_BENCHMARK.md) — 95% accuracy across 20 test scenarios
|
|
424
|
-
- [Compliance FAQ](docs/COMPLIANCE_FAQ.md) —
|
|
172
|
+
- [Guardrail Benchmark](docs/GUARDRAIL_BENCHMARK.md) — 95% accuracy across 20 test scenarios
|
|
173
|
+
- [Compliance FAQ](docs/COMPLIANCE_FAQ.md) — PCI DSS, SOC 2, GDPR details
|
|
425
174
|
- [Environment Reference](docs/ENV_REFERENCE.md) — All POP_* environment variables
|
|
426
|
-
- [Integration Guide](docs/INTEGRATION_GUIDE.md) —
|
|
175
|
+
- [Integration Guide](docs/INTEGRATION_GUIDE.md) — Setup for Claude Code, Node.js SDK, and browser agents
|
|
427
176
|
- [Categories Cookbook](docs/CATEGORIES_COOKBOOK.md) — POP_ALLOWED_CATEGORIES patterns and examples
|
|
428
177
|
|
|
429
178
|
## License
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bg-color: #0d1117;
|
|
3
|
+
--card-bg: #161b22;
|
|
4
|
+
--text-primary: #c9d1d9;
|
|
5
|
+
--text-secondary: #8b949e;
|
|
6
|
+
--accent-green: #3fb950;
|
|
7
|
+
--warning-amber: #d29922;
|
|
8
|
+
--danger-red: #f85149;
|
|
9
|
+
--border-color: #30363d;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
* {
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
margin: 0;
|
|
15
|
+
padding: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
body {
|
|
19
|
+
background-color: var(--bg-color);
|
|
20
|
+
color: var(--text-primary);
|
|
21
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
22
|
+
line-height: 1.6;
|
|
23
|
+
padding: 20px 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.container {
|
|
27
|
+
max-width: 1200px;
|
|
28
|
+
margin: 0 auto;
|
|
29
|
+
padding: 0 20px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
header {
|
|
33
|
+
margin-bottom: 40px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
header .container {
|
|
37
|
+
display: flex;
|
|
38
|
+
justify-content: space-between;
|
|
39
|
+
align-items: center;
|
|
40
|
+
border-bottom: 1px solid var(--border-color);
|
|
41
|
+
padding-bottom: 20px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
h1 {
|
|
45
|
+
font-size: 1.5rem;
|
|
46
|
+
font-weight: 700;
|
|
47
|
+
letter-spacing: 1px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.subtitle {
|
|
51
|
+
color: var(--accent-green);
|
|
52
|
+
font-family: 'Courier New', Courier, monospace;
|
|
53
|
+
font-size: 0.9rem;
|
|
54
|
+
margin-left: 10px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.metrics {
|
|
58
|
+
display: grid;
|
|
59
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
60
|
+
gap: 20px;
|
|
61
|
+
margin-bottom: 30px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.card {
|
|
65
|
+
background-color: var(--card-bg);
|
|
66
|
+
border: 1px solid var(--border-color);
|
|
67
|
+
border-radius: 6px;
|
|
68
|
+
padding: 20px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.card h3 {
|
|
72
|
+
color: var(--text-secondary);
|
|
73
|
+
font-size: 0.75rem;
|
|
74
|
+
letter-spacing: 1px;
|
|
75
|
+
margin-bottom: 10px;
|
|
76
|
+
text-transform: uppercase;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.value {
|
|
80
|
+
font-family: 'Courier New', Courier, monospace;
|
|
81
|
+
font-size: 2rem;
|
|
82
|
+
font-weight: 700;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.progress-bar {
|
|
86
|
+
background-color: var(--border-color);
|
|
87
|
+
height: 8px;
|
|
88
|
+
border-radius: 4px;
|
|
89
|
+
margin-top: 15px;
|
|
90
|
+
overflow: hidden;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.progress-fill {
|
|
94
|
+
height: 100%;
|
|
95
|
+
width: 0%;
|
|
96
|
+
background-color: var(--accent-green);
|
|
97
|
+
transition: width 0.5s ease;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.settings {
|
|
101
|
+
margin-bottom: 30px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.input-group {
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: 15px;
|
|
108
|
+
margin-top: 10px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
label {
|
|
112
|
+
font-size: 0.85rem;
|
|
113
|
+
color: var(--text-secondary);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
input[type="number"] {
|
|
117
|
+
background-color: var(--bg-color);
|
|
118
|
+
border: 1px solid var(--border-color);
|
|
119
|
+
color: var(--text-primary);
|
|
120
|
+
padding: 8px 12px;
|
|
121
|
+
border-radius: 4px;
|
|
122
|
+
width: 150px;
|
|
123
|
+
font-family: 'Courier New', Courier, monospace;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.btn {
|
|
127
|
+
background-color: transparent;
|
|
128
|
+
border: 1px solid var(--border-color);
|
|
129
|
+
color: var(--text-primary);
|
|
130
|
+
padding: 8px 16px;
|
|
131
|
+
border-radius: 6px;
|
|
132
|
+
cursor: pointer;
|
|
133
|
+
font-size: 0.85rem;
|
|
134
|
+
font-weight: 600;
|
|
135
|
+
transition: all 0.2s;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.btn:hover {
|
|
139
|
+
background-color: var(--card-bg);
|
|
140
|
+
border-color: var(--text-secondary);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.btn-small {
|
|
144
|
+
padding: 6px 12px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.table-container {
|
|
148
|
+
overflow-x: auto;
|
|
149
|
+
margin-top: 15px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
table {
|
|
153
|
+
width: 100%;
|
|
154
|
+
border-collapse: collapse;
|
|
155
|
+
font-size: 0.85rem;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
th {
|
|
159
|
+
text-align: left;
|
|
160
|
+
padding: 12px;
|
|
161
|
+
border-bottom: 1px solid var(--border-color);
|
|
162
|
+
color: var(--text-secondary);
|
|
163
|
+
text-transform: uppercase;
|
|
164
|
+
cursor: pointer;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
th:hover {
|
|
168
|
+
color: var(--text-primary);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
td {
|
|
172
|
+
padding: 12px;
|
|
173
|
+
border-bottom: 1px solid var(--border-color);
|
|
174
|
+
font-family: 'Courier New', Courier, monospace;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.seals, .rejected {
|
|
178
|
+
margin-bottom: 40px;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.rejected table {
|
|
182
|
+
border: 1px solid var(--danger-red);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.rejected td {
|
|
186
|
+
color: var(--danger-red);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@media (max-width: 768px) {
|
|
190
|
+
.metrics {
|
|
191
|
+
grid-template-columns: 1fr;
|
|
192
|
+
}
|
|
193
|
+
}
|