x402-surface-check 0.2.35 → 0.2.36

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
@@ -30,6 +30,7 @@ npx --yes x402-surface-check --strict-proof https://api.example.com/openapi.json
30
30
  - No-payment HTTP 402 challenge shape
31
31
  - x402 v1 and v2 price fields, including `accepts[]` and `schemes[]` challenge arrays
32
32
  - MPP `WWW-Authenticate: Payment` and x402 V2 `WWW-Authenticate: X402 requirements=...` challenges
33
+ - MPP descriptor-only 402s that advertise discovery headers but do not return a machine-readable payment retry challenge
33
34
  - Atomic-unit `amount` / `maxAmountRequired` fields, plus legacy decimal `amount` + `token` x402 v1 challenges
34
35
  - `asset` or token metadata, `network`, and `payTo`
35
36
  - OpenAPI-declared `x-payment-info.price.amount` drift versus the live 402 challenge price
@@ -1084,6 +1084,17 @@ function hasMppRetryChallenge(result) {
1084
1084
  return challengeAccepts(result).some(accept => String(accept.scheme ?? '').toLowerCase() === 'mpp')
1085
1085
  }
1086
1086
 
1087
+ function mppDiscoveryHeaders(headers = {}) {
1088
+ return [
1089
+ 'x-mpp-descriptor',
1090
+ 'x-agent-card',
1091
+ ].filter(name => headers[name] !== undefined && headers[name] !== '')
1092
+ }
1093
+
1094
+ function advertisesMppDiscovery(result) {
1095
+ return mppDiscoveryHeaders(result.headers).length > 0
1096
+ }
1097
+
1087
1098
  function allowsAnyHeader(headerValue = '', names = []) {
1088
1099
  return names.some(name => headerListAllows(headerValue, name))
1089
1100
  }
@@ -1160,6 +1171,10 @@ function findingList(documentResult, challengeResults, preflightResults, entries
1160
1171
  }
1161
1172
 
1162
1173
  if (!hasChallenge) {
1174
+ const descriptorHeaders = mppDiscoveryHeaders(result.headers)
1175
+ if (result.status === 402 && descriptorHeaders.length > 0) {
1176
+ findings.push(`P1 - ${result.name} returns 402 and advertises MPP discovery via ${descriptorHeaders.join(', ')}, but does not include a WWW-Authenticate: Payment challenge or machine-readable body challenge; autonomous callers cannot construct a paid retry from this response alone.`)
1177
+ }
1163
1178
  continue
1164
1179
  }
1165
1180
 
@@ -1238,7 +1253,7 @@ function findingList(documentResult, challengeResults, preflightResults, entries
1238
1253
 
1239
1254
  for (const result of preflightResults) {
1240
1255
  const challengeResult = challengesByEntry.get(entryKey(result))
1241
- if (!challengeResult || (!hasPaymentChallenge(challengeResult) && !advertisesPaymentEnforcement(challengeResult.headers))) continue
1256
+ if (!challengeResult || (!hasPaymentChallenge(challengeResult) && !advertisesPaymentEnforcement(challengeResult.headers) && !advertisesMppDiscovery(challengeResult))) continue
1242
1257
  const allowedOrigin = result.headers['access-control-allow-origin'] ?? ''
1243
1258
  if (!allowedOrigin) {
1244
1259
  findings.push(`P1 - ${result.name} CORS preflight does not allow the requesting origin; observed allow-origin: none.`)
@@ -1250,7 +1265,7 @@ function findingList(documentResult, challengeResults, preflightResults, entries
1250
1265
  : `allow headers: ${allowed || 'none'}`
1251
1266
  findings.push(`P1 - ${result.name} CORS preflight does not allow a known x402 retry header (X-PAYMENT or PAYMENT-SIGNATURE); observed ${observed}.`)
1252
1267
  }
1253
- if (hasMppRetryChallenge(challengeResult) && !headerListAllows(allowed, 'authorization')) {
1268
+ if ((hasMppRetryChallenge(challengeResult) || advertisesMppDiscovery(challengeResult)) && !headerListAllows(allowed, 'authorization')) {
1254
1269
  const observed = result.status >= 400
1255
1270
  ? `HTTP ${result.status}; allow headers: ${allowed || 'none'}`
1256
1271
  : `allow headers: ${allowed || 'none'}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-surface-check",
3
- "version": "0.2.35",
3
+ "version": "0.2.36",
4
4
  "description": "No-payment x402 public-surface checker for manifests, OpenAPI specs, and HTTP 402 challenges.",
5
5
  "type": "module",
6
6
  "bin": {