@paystage/preflight 0.2.0 → 0.2.2

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
@@ -87,8 +87,24 @@ CAIP-2 identifiers.
87
87
  | `review` | Allowed but above a human threshold — ask a human before paying. |
88
88
  | `do_not_pay` | Violates policy (network, asset, payTo, amount, timeout, or malformed). |
89
89
 
90
+ ## Supply chain and access
91
+
92
+ Socket.dev scores this package on what it *can* do, not what it does with it, so the
93
+ flags it raises are worth explaining rather than removing:
94
+
95
+ | Flag | Why it is there |
96
+ | --- | --- |
97
+ | Filesystem access | Reads the policy JSON you point it at (`policy_path` / `PAYSTAGE_POLICY_PATH`). Nothing is written. |
98
+ | Environment variable access | `PAYSTAGE_POLICY_PATH` only (and `PAYSTAGE_RPC_URL` via `auth-watch`). |
99
+ | Network access, URL strings | None in this package. The RPC endpoints you may see in the tree belong to `@paystage/auth-watch`. |
100
+
101
+ No shell, no `eval`, no telemetry, no key custody. The full table is in
102
+ [SECURITY.md](../../SECURITY.md); the deny list is published with a citation per
103
+ entry in [KNOWN_DRAINERS.md](./KNOWN_DRAINERS.md).
104
+
90
105
  ## Links
91
106
 
92
107
  - Website: <https://paystage.xyz>
108
+ - X: <https://x.com/paystage_xyz>
93
109
  - Source: <https://github.com/base-buzz/paystage>
94
110
  - License: MIT
@@ -34,5 +34,12 @@ export interface EvaluateResult {
34
34
  summary: string;
35
35
  dailyCapNote?: string;
36
36
  }
37
- export declare function evaluatePayment(pr: PaymentRequest, policy: Policy): EvaluateResult;
37
+ export interface EvaluateOptions {
38
+ /**
39
+ * Which agent is asking. Required when the policy declares per-agent budgets:
40
+ * a policy with agents must never fall back to the loosest rules in the file.
41
+ */
42
+ agentId?: string;
43
+ }
44
+ export declare function evaluatePayment(pr: PaymentRequest, policy: Policy, options?: EvaluateOptions): EvaluateResult;
38
45
  //# sourceMappingURL=evaluate.d.ts.map
package/dist/evaluate.js CHANGED
@@ -1,4 +1,4 @@
1
- import { humanToAtomic, atomicToHuman, } from "@paystage/policy";
1
+ import { humanToAtomic, atomicToHuman, resolveAgentPolicy, } from "@paystage/policy";
2
2
  import { isKnownDrainer } from "./known-drainers.js";
3
3
  function eq(a, b) {
4
4
  return a.toLowerCase() === b.toLowerCase();
@@ -88,7 +88,20 @@ function cheapest(accepts) {
88
88
  return a.maxTimeoutSeconds - b.maxTimeoutSeconds;
89
89
  })[0];
90
90
  }
91
- export function evaluatePayment(pr, policy) {
91
+ export function evaluatePayment(pr, policy, options = {}) {
92
+ // Rule 0: per-agent budgets. Resolve first — every later rule must run against the
93
+ // narrowed policy, not the global one, or a cheap agent could be judged by the
94
+ // expensive agent's ceiling.
95
+ const resolution = resolveAgentPolicy(policy, options.agentId);
96
+ if (!resolution.ok) {
97
+ return {
98
+ decision: "do_not_pay",
99
+ acceptResults: [],
100
+ reasons: [resolution.reason],
101
+ summary: "Agent identity could not be resolved against the policy.",
102
+ };
103
+ }
104
+ const effective = resolution.policy;
92
105
  // Rule 1: malformed
93
106
  if (!pr || pr.x402Version !== 2) {
94
107
  return {
@@ -106,7 +119,7 @@ export function evaluatePayment(pr, policy) {
106
119
  summary: "Payment request has no acceptable payment options.",
107
120
  };
108
121
  }
109
- const acceptResults = pr.accepts.map((a) => evaluateAccept(a, policy));
122
+ const acceptResults = pr.accepts.map((a) => evaluateAccept(a, effective));
110
123
  const payAccepts = acceptResults
111
124
  .filter((r) => r.status === "pay")
112
125
  .map((r) => r.accept);
@@ -46,6 +46,16 @@ export const SOURCES = [
46
46
  url: "https://www.0xcert.com/advisory/0xCERT-2026-0303",
47
47
  retrieved: "2026-11-05",
48
48
  },
49
+ {
50
+ name: "0xCERT advisory 0xCERT-2026-0314 (Loopscale attack campaign; EVM addresses named by Loopscale)",
51
+ url: "https://www.0xcert.com/advisory/0xCERT-2026-0314",
52
+ retrieved: "2026-11-07",
53
+ },
54
+ {
55
+ name: "0xCERT advisory 0xCERT-2026-0309 (CoreVault exploit; attacker EOA and exploit contract, BNB Chain per CertiK)",
56
+ url: "https://www.0xcert.com/advisory/0xCERT-2026-0309",
57
+ retrieved: "2026-11-07",
58
+ },
49
59
  ];
50
60
  /**
51
61
  * Small curated subset. Do not add addresses without a public citation.
@@ -101,6 +111,16 @@ export const KNOWN_DRAINERS = Object.freeze([
101
111
  // also flagged on Base/Arbitrum/Optimism (0xCERT-2026-0308, per Bitquery)
102
112
  // https://www.0xcert.com/advisory/0xCERT-2026-0303
103
113
  "0xe485e7a70b1131216cb47ca4555c4bbb2c742478",
114
+ // --- Added 2026-11-07 NZDT ---
115
+ // Loopscale attack campaign, EVM addresses named by Loopscale (0xCERT-2026-0314; chain not stated by the feed)
116
+ // https://www.0xcert.com/advisory/0xCERT-2026-0314
117
+ "0xb7ec7ef24fd73f3000c651ca9d0fa45b61dcf854",
118
+ "0xb8959aca4e4c796a3bada66833eae60b1bc0bfb2",
119
+ // CoreVault exploit, BNB Chain: attacker EOA (sender) and the exploit contract it created
120
+ // (0xCERT-2026-0309; CertiK-cited transaction, on-chain)
121
+ // https://www.0xcert.com/advisory/0xCERT-2026-0309
122
+ "0xd3565b191b28b49cc517189b984dacdb1ff05304",
123
+ "0xc28cfeee046e1421e9dbfb2cf689074bf9f387e2",
104
124
  ]);
105
125
  const SET = new Set(KNOWN_DRAINERS.map((a) => a.toLowerCase()));
106
126
  export function isKnownDrainer(addr) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paystage/preflight",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Evaluate x402 PaymentRequired against a local spending policy before an agent pays",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -13,7 +13,7 @@
13
13
  }
14
14
  },
15
15
  "bin": {
16
- "paystage-preflight": "./dist/cli.js"
16
+ "paystage-preflight": "dist/cli.js"
17
17
  },
18
18
  "files": [
19
19
  "dist",
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@modelcontextprotocol/server": "^2.4.0",
56
- "@paystage/policy": "0.2.0",
56
+ "@paystage/policy": "0.2.1",
57
57
  "zod": "^4.6.7"
58
58
  },
59
59
  "devDependencies": {
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "xyz.paystage/preflight",
4
4
  "title": "PayStage Preflight",
5
5
  "description": "Evaluate x402 PaymentRequired against a local spending policy before an agent pays",
6
- "version": "0.2.0",
6
+ "version": "0.2.2",
7
7
  "websiteUrl": "https://paystage.xyz",
8
8
  "repository": {
9
9
  "url": "https://github.com/base-buzz/paystage",
@@ -15,7 +15,7 @@
15
15
  "registryType": "npm",
16
16
  "registryBaseUrl": "https://registry.npmjs.org",
17
17
  "identifier": "@paystage/preflight",
18
- "version": "0.2.0",
18
+ "version": "0.2.2",
19
19
  "transport": {
20
20
  "type": "stdio"
21
21
  },