Potential paywall bypass: weak payment proof can unlock paid resources
Hi, I noticed a possible payment-flow issue while reviewing the current repository state. This is a conservative report based on the visible code path, and I may be missing deployment-specific guards outside this repository.
Reviewed HEAD: c7212544f347
What I observed
In the visible payment path, I observed:
Paid blob gate accepts any non-empty paymentProof; TODO notes JWT verification missing, so ?paymentProof=anything bypasses 402
Relevant code locations:
worker/src/index.ts
docs/api.md
docs/adr/004-payment-protocol.md
docs/scaling-revenue.md
Relevant code excerpts
worker/src/index.ts:394-418
394 'X-Payment-Currency': 'USD',
395 'X-Payment-Methods': 'lightning,stripe',
396 ...corsHeaders,
397 },
398 }
399 );
400 }
401
402 // TODO: Validate payment proof (JWT verification)
403 // For now, accept any non-empty proof for testing
404 }
405
406 // Fetch from R2
407 const object = await env.VNSH_STORE.get(id);
408
409 if (!object) {
410 // R2 object missing but metadata exists - inconsistent state
411 await env.VNSH_META.delete(`blob:${id}`);
412 return errorResponse('NOT_FOUND', 'Blob not found', 404, request);
413 }
414
415 // Track read analytics
416 const source = getClientSource(request);
417 trackStat(env, 'reads', ctx);
418 trackStat(env, `source:${source}:reads`, ctx);
docs/api.md:54-78
54 ```http
55 GET /api/blob/a1b2c3d4-e5f6-7890-abcd-ef1234567890 HTTP/1.1
56 ```
57
58 **Query Parameters:**
59
60 | Parameter | Type | Description |
61 |-----------|------|-------------|
62 | `paymentProof` | string | JWT token proving payment (for paid blobs) |
63
64 **Response (200 OK):**
65
66 ```http
67 HTTP/1.1 200 OK
68 Content-Type: application/octet-stream
69 Content-Length: 1234
70 Cache-Control: private, no-store, no-cache
71 X-Content-Type-Options: nosniff
72 X-Opaque-Expires: 2024-01-25T12:00:00.000Z
73
74 <binary encrypted data>
75 ```
76
77 **Errors:**
78
docs/adr/004-payment-protocol.md:27-51
27 **Cons:**
28 - Requires account setup
29 - High fees for micropayments
30 - Server must store payment state
31
32 #### Lightning Network (Bitcoin L2)
33
34 **Pros:**
35 - Instant settlement
36 - Low fees (< 1%)
37 - No account needed
38 - Proof of payment (preimage)
39
40 **Cons:**
41 - Requires Lightning wallet
42 - Volatile exchange rates
43 - Learning curve
44
45 #### x402 Protocol Standard
46
47 **Pros:**
48 - HTTP-native (402 status code)
49 - Method-agnostic
50 - Emerging standard
51 - Self-describing payments
docs/scaling-revenue.md:118-142
118 This is what makes vnsh different from every other pastebin. AI agents can pay for content programmatically via the HTTP 402 Payment Required standard.
119
120 See also: [architecture-x402-payment-proposal.md](architecture-x402-payment-proposal.md), [ADR 004](adr/004-payment-protocol.md)
121
122 ### 3.1 Complete x402 Payment Flow
123
124 The scaffolding exists in `worker/src/index.ts`. The upload endpoint accepts `?price=X` and the read endpoint returns 402 with payment headers. What's missing:
125
126 1. **JWT verification**: The current code accepts any non-empty `paymentProof` string. Implement HS256 JWT verification with `JWT_SECRET` env var.
127 2. **Stripe Checkout for per-blob payments**: New endpoint `POST /api/pay/:id` creates a one-time Stripe Checkout session.
128 3. **Split URL model**: Upload with `?price=1.00` returns both:
129 - `payUrl`: `vnsh.dev/pay/{id}` (no encryption key, shareable publicly)
130 - `secretUrl`: `vnsh.dev/v/{id}#secret...` (full key, kept private by creator)
131 - Buyer visits `payUrl` → pays → receives signed JWT → redirect to `secretUrl`
132 4. **Revenue split**: Platform 10%, Stripe 2.9% + $0.30, creator ~87%.
133
134 ### 3.2 MCP `vnsh_pay` Tool
135
136 New tool in the MCP server for programmatic agent payments:
137
138 ```
139 Tool: vnsh_pay
140 Description: Pay for and retrieve content behind a vnsh paywall
141 Input: { url: string, max_price: number }
142 Behavior: detect 402 → create payment → submit proof → return decrypted content
Why this may matter
A weak or simulated payment proof can become an access token for a paid capability, especially when the proof is not cryptographically tied to the request.
Suggested check
Consider making the paid-resource path depend on server-trusted payment requirements and a completed payment state. In particular, re-check recipient/payTo, amount, asset, network, nonce/idempotency, resource binding, and settlement result at the exact point where the protected API/tool/content is released.
Conservative caveat
I only reviewed the code visible in this repository at the HEAD above. If deployment-specific middleware or an upstream service enforces the missing binding/settlement invariant, this may already be mitigated there.
Potential paywall bypass: weak payment proof can unlock paid resources
Hi, I noticed a possible payment-flow issue while reviewing the current repository state. This is a conservative report based on the visible code path, and I may be missing deployment-specific guards outside this repository.
Reviewed HEAD:
c7212544f347What I observed
In the visible payment path, I observed:
Relevant code locations:
worker/src/index.tsdocs/api.mddocs/adr/004-payment-protocol.mddocs/scaling-revenue.mdRelevant code excerpts
worker/src/index.ts:394-418docs/api.md:54-78docs/adr/004-payment-protocol.md:27-51docs/scaling-revenue.md:118-142Why this may matter
A weak or simulated payment proof can become an access token for a paid capability, especially when the proof is not cryptographically tied to the request.
Suggested check
Consider making the paid-resource path depend on server-trusted payment requirements and a completed payment state. In particular, re-check recipient/payTo, amount, asset, network, nonce/idempotency, resource binding, and settlement result at the exact point where the protected API/tool/content is released.
Conservative caveat
I only reviewed the code visible in this repository at the HEAD above. If deployment-specific middleware or an upstream service enforces the missing binding/settlement invariant, this may already be mitigated there.