x402-surface-check 0.2.13 → 0.2.14
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 +3 -2
- package/bin/x402-surface-check.mjs +29 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npx --yes x402-surface-check --endpoint --method POST https://x402.rpc.ankr.com/
|
|
|
14
14
|
|
|
15
15
|
## What It Checks
|
|
16
16
|
|
|
17
|
-
- Manifest endpoint discovery from `items[]`, `endpoints[]`, `x402Endpoints`, category arrays, resource strings, and OpenAPI paths
|
|
17
|
+
- Manifest endpoint discovery from `items[]`, `endpoints[]`, `resources[]`, `x402Endpoints`, category arrays, resource strings, and OpenAPI paths
|
|
18
18
|
- Linked discovery documents via `discovery_url`, `discoveryUrl`, `resources_url`, `resourcesUrl`, or manifest-level OpenAPI links
|
|
19
19
|
- OpenAPI query/path examples and JSON request-body examples for safer no-payment probes
|
|
20
20
|
- No-payment HTTP 402 challenge shape
|
|
@@ -26,7 +26,7 @@ npx --yes x402-surface-check --endpoint --method POST https://x402.rpc.ankr.com/
|
|
|
26
26
|
- Placeholder recipients such as zero addresses and Solana system-program values
|
|
27
27
|
- Testnet or staging rails such as Base Sepolia and Solana devnet
|
|
28
28
|
- HTTPS resource URLs and stable resource metadata
|
|
29
|
-
- Browser CORS allowance for `X-PAYMENT`
|
|
29
|
+
- Browser CORS allowance for the requesting origin and `X-PAYMENT`
|
|
30
30
|
- Over-broad public method surfaces
|
|
31
31
|
- Auth, validation, and free/trial responses that appear before a payment challenge, without piling on missing-field findings when no challenge was actually returned
|
|
32
32
|
- Operational health/status endpoints, without treating expected free health checks as paid-route failures
|
|
@@ -44,6 +44,7 @@ Recent public no-payment checks have found and verified real launch fixes:
|
|
|
44
44
|
- anchor-x402: multi-rail x402 challenges verified, with browser preflight blockers isolated before merge. https://github.com/solana-foundation/pay-skills/pull/47#issuecomment-4455678163
|
|
45
45
|
- Agent Trust Bench: linked discovery URL and browser-compatibility notes verified clean for adversarial agent-payment resources. https://github.com/solana-foundation/pay-skills/pull/23#issuecomment-4455722170
|
|
46
46
|
- Solrouter: private LLM inference route verified with HTTPS resource-binding and price-alignment notes. https://github.com/solana-foundation/pay-skills/pull/39#issuecomment-4455800060
|
|
47
|
+
- Tetrac: Solana market-data payment gates verified, with browser payment-header preflight blocker isolated. https://github.com/solana-foundation/pay-skills/pull/32#issuecomment-4455923744
|
|
47
48
|
|
|
48
49
|
Field notes and browser version: https://tateprograms.com/x402-surface-check.html
|
|
49
50
|
|
|
@@ -294,17 +294,32 @@ function endpointEntries(document, sourceUrl, limit) {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
for (const resource of document.resources ?? []) {
|
|
297
|
-
if (typeof resource
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
297
|
+
if (typeof resource === 'string') {
|
|
298
|
+
const match = resource.match(/^(GET|POST|PUT|PATCH|DELETE)\s+(\S+)/i)
|
|
299
|
+
if (!match) continue
|
|
300
|
+
const [, method, rawPath] = match
|
|
301
|
+
const url = rawPath.startsWith('http')
|
|
302
|
+
? rawPath
|
|
303
|
+
: new URL(rawPath, document.baseUrl ?? sourceUrl).toString()
|
|
304
|
+
entries.push({
|
|
305
|
+
name: rawPath.split('/').filter(Boolean).at(-1) ?? rawPath,
|
|
306
|
+
url,
|
|
307
|
+
method: method.toUpperCase(),
|
|
308
|
+
})
|
|
309
|
+
continue
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (!resource || typeof resource !== 'object') continue
|
|
313
|
+
const rawPath = resource.url ?? resource.endpoint ?? resource.resource ?? resource.path
|
|
314
|
+
if (!rawPath) continue
|
|
304
315
|
entries.push({
|
|
305
|
-
name:
|
|
306
|
-
|
|
307
|
-
|
|
316
|
+
name: resource.id
|
|
317
|
+
?? resource.name
|
|
318
|
+
?? resource.title
|
|
319
|
+
?? String(resource.path ?? rawPath).split('/').filter(Boolean).at(-1)
|
|
320
|
+
?? String(rawPath),
|
|
321
|
+
url: endpointUrl(rawPath, baseUrl, sourceUrl),
|
|
322
|
+
method: String(resource.method ?? 'GET').toUpperCase(),
|
|
308
323
|
})
|
|
309
324
|
}
|
|
310
325
|
|
|
@@ -669,6 +684,10 @@ function findingList(documentResult, challengeResults, preflightResults, entries
|
|
|
669
684
|
for (const result of preflightResults) {
|
|
670
685
|
const challengeResult = challengesByEntry.get(entryKey(result))
|
|
671
686
|
if (!challengeResult || !hasPaymentChallenge(challengeResult)) continue
|
|
687
|
+
const allowedOrigin = result.headers['access-control-allow-origin'] ?? ''
|
|
688
|
+
if (!allowedOrigin) {
|
|
689
|
+
findings.push(`P1 - ${result.name} CORS preflight does not allow the requesting origin; observed allow-origin: none.`)
|
|
690
|
+
}
|
|
672
691
|
const allowed = result.headers['access-control-allow-headers'] ?? ''
|
|
673
692
|
if (allowed !== '*' && !/x-payment/i.test(allowed)) {
|
|
674
693
|
const observed = result.status >= 400
|