x402-surface-check 0.2.10 → 0.2.11

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 CHANGED
@@ -27,6 +27,7 @@ npx --yes x402-surface-check --endpoint --method POST https://x402.rpc.ankr.com/
27
27
  - Browser CORS allowance for `X-PAYMENT`
28
28
  - Over-broad public method surfaces
29
29
  - Auth, validation, and free/trial responses that appear before a payment challenge, without piling on missing-field findings when no challenge was actually returned
30
+ - Operational health/status endpoints, without treating expected free health checks as paid-route failures
30
31
  - Object-valued document metadata such as facilitator objects, without `[object Object]` report artifacts
31
32
 
32
33
  ## Public Proof
@@ -36,6 +37,8 @@ Recent public no-payment checks have found and verified real launch fixes:
36
37
  - TensorFeed: parameter-required premium routes moved behind canonical x402 V2 challenges, then verified clean. https://github.com/solana-foundation/pay-skills/pull/68#issuecomment-4455360068
37
38
  - x402jp: weather routes that returned 500 now return structured Base x402 challenges. https://github.com/solana-foundation/pay-skills/pull/58#issuecomment-4455401355
38
39
  - Spraay: resource echo and browser payment-header behavior verified clean. https://github.com/solana-foundation/pay-skills/pull/60#issuecomment-4455519760
40
+ - UZPROOF: schemes-style Solana x402 challenge and browser payment-header behavior verified clean. https://github.com/solana-foundation/pay-skills/pull/28#issuecomment-4455613892
41
+ - HYRE Agent: OpenAPI-declared prices found 10x below live 402 challenge prices. https://github.com/solana-foundation/pay-skills/pull/19#issuecomment-4455641258
39
42
  - Agent Trust Bench: live discovery URL and browser-compatibility notes for adversarial agent-payment resources. https://github.com/solana-foundation/pay-skills/pull/23#issuecomment-4455484414
40
43
 
41
44
  Field notes and browser version: https://tateprograms.com/x402-surface-check.html
@@ -501,11 +501,21 @@ function looksLikePlaceholderPayTo(payTo) {
501
501
  return false
502
502
  }
503
503
 
504
+ function entryKey(entry) {
505
+ return `${entry.method ?? 'POST'} ${entry.url}`
506
+ }
507
+
508
+ function looksLikeOperationalHealthEndpoint(result) {
509
+ const value = `${result.name ?? ''} ${new URL(result.url).pathname}`.toLowerCase()
510
+ return /(^|[/_\s-])(health|healthz|ready|readiness|live|liveness|status)([/_\s-]|$)/.test(value)
511
+ }
512
+
504
513
  function findingList(documentResult, challengeResults, preflightResults, entries) {
505
514
  const document = documentResult.body.json ?? {}
506
515
  const findings = []
507
516
  const networks = valueList(document.networks)
508
517
  const challengeNetworks = new Set()
518
+ const challengesByEntry = new Map(challengeResults.map(result => [entryKey(result), result]))
509
519
 
510
520
  if (documentResult.status < 200 || documentResult.status >= 300) {
511
521
  findings.push(`P1 - Document returned HTTP ${documentResult.status}; expected a successful JSON response.`)
@@ -526,7 +536,9 @@ function findingList(documentResult, challengeResults, preflightResults, entries
526
536
 
527
537
  if (result.status !== 402) {
528
538
  if (result.status >= 200 && result.status < 300) {
529
- findings.push(`P3 - ${result.name} returned ${result.status} without a payment challenge for a no-payment ${result.method ?? 'POST'} probe; document this as free/trial access or move the 402 challenge before content.`)
539
+ if (!looksLikeOperationalHealthEndpoint(result)) {
540
+ findings.push(`P3 - ${result.name} returned ${result.status} without a payment challenge for a no-payment ${result.method ?? 'POST'} probe; document this as free/trial access or move the 402 challenge before content.`)
541
+ }
530
542
  }
531
543
  else if (result.status === 400 || result.status === 422) {
532
544
  findings.push(`P1 - ${result.name} returned validation HTTP ${result.status} before a payment challenge for a no-payment ${result.method ?? 'POST'} probe.`)
@@ -569,9 +581,14 @@ function findingList(documentResult, challengeResults, preflightResults, entries
569
581
  }
570
582
 
571
583
  for (const result of preflightResults) {
584
+ const challengeResult = challengesByEntry.get(entryKey(result))
585
+ if (!challengeResult || !hasPaymentChallenge(challengeResult)) continue
572
586
  const allowed = result.headers['access-control-allow-headers'] ?? ''
573
587
  if (allowed !== '*' && !/x-payment/i.test(allowed)) {
574
- findings.push(`P1 - ${result.name} CORS preflight does not allow X-PAYMENT; observed allow headers: ${allowed || 'none'}.`)
588
+ const observed = result.status >= 400
589
+ ? `HTTP ${result.status}; allow headers: ${allowed || 'none'}`
590
+ : `allow headers: ${allowed || 'none'}`
591
+ findings.push(`P1 - ${result.name} CORS preflight does not allow X-PAYMENT; observed ${observed}.`)
575
592
  }
576
593
  const allowedMethods = result.headers['access-control-allow-methods'] ?? ''
577
594
  if (/delete|put|patch/i.test(allowedMethods)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-surface-check",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "No-payment x402 public-surface checker for manifests, OpenAPI specs, and HTTP 402 challenges.",
5
5
  "type": "module",
6
6
  "bin": {