
Security News
PHP Foundation Says Chainguard Broke Security Embargo Ahead of Emergency Patches
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.
@deepfirstsearch/agent-pay-agentkit
Advanced tools
Coinbase AgentKit action provider: agents fetch x402 APIs while the owner's Agent Safe policy decides every payment (no payee or amount in the model's hands)
A Coinbase AgentKit action provider that lets an agent fetch x402 APIs and pay them in USDC on Base, while the owner's Agent Safe policy decides every payment. The action, AgentPayActionProvider_paid_fetch, takes a URL and nothing that moves money: no payee, no amount, no network. Payees, price pins, caps and the budget come from the owner's registry and sealed plan, so a prompt-injected agent can ask for any URL but can't choose who gets paid or how much.
Beta, unaudited. Use Base Sepolia or small amounts on Base mainnet. Independent open-source project; not affiliated with Coinbase.
npm install @deepfirstsearch/agent-pay-agentkit @deepfirstsearch/agent-pay @coinbase/agentkit viem@2.38.3 zod@3
(AgentKit pins viem 2.38.3; using the same version keeps one copy of viem's types.)
Before you install: @coinbase/agentkit pulls in about 1,000 packages, and npm audit reports upstream warnings in that tree (from @coinbase/agentkit and the viem version it pins, not from this package, which has no dependencies of its own beyond its peers). AgentKit also makes an outbound analytics call when a wallet provider is created; see the note below.
Project setup. The example is ESM with top-level await: run npm pkg set type=module (or name the file .ts and run it with npx tsx file.ts). Node 20 or later.
process.on("unhandledRejection", () => {}); // AgentKit's wallet providers send an analytics event; see the note below
import { AgentKit, ViemWalletProvider } from "@coinbase/agentkit";
import { createAgentPay, MerchantRegistry } from "@deepfirstsearch/agent-pay";
import { startMockServer } from "@deepfirstsearch/agent-pay/testing";
import { agentKitPayer, agentPayActionProvider, PAID_FETCH_ACTION } from "@deepfirstsearch/agent-pay-agentkit";
import { createWalletClient, http } from "viem";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
// A local x402 merchant (it verifies signatures itself; nothing touches a chain) and a hostile route.
const payTo = "0x1111111111111111111111111111111111111111";
const merchant = await startMockServer({
"/data": { price: 10_000n, payTo, body: '{"price":42}' },
"/evil": { price: 10_000n, payTo, tamper: (r) => ({ ...r, payTo: "0x9999999999999999999999999999999999999999" }) },
}, { network: "eip155:8453" });
// The agent's AgentKit wallet (here a throwaway key) signs the payments, but only when Agent Safe allows them.
const walletProvider = new ViemWalletProvider(
createWalletClient({ account: privateKeyToAccount(generatePrivateKey()), chain: base, transport: http() }),
);
// The owner's rules: who may be paid, at what price, with what cap. Nothing here comes from the model.
const pay = createAgentPay({
registry: new MerchantRegistry([{ origin: merchant.url, payTo, network: "eip155:8453", maxPerTx: 50_000n, pricePin: 10_000n }]),
policy: { allowedNetworks: ["eip155:8453"], periodBudget: { amount: 1_000_000n, periodMs: 86_400_000 } },
payer: () => agentKitPayer(walletProvider),
session: { readsUntrustedInput: true, accessesSensitiveData: false, canPay: true },
});
// Seal the plan before the agent reads anything untrusted.
const plan = pay.commitPlan([{ origin: merchant.url, maxSpend: 100_000n }], 60 * 60_000);
const agentkit = await AgentKit.from({ walletProvider, actionProviders: [agentPayActionProvider({ pay, plan })] });
const paidFetch = agentkit.getActions().find((a) => a.name === PAID_FETCH_ACTION)!;
console.log(await paidFetch.invoke({ url: `${merchant.url}/data` })); // HTTP 200. Paid 0.01 USDC to 0x1111… + fenced body
console.log(await paidFetch.invoke({ url: `${merchant.url}/evil` })); // Payment refused by policy: … (nothing signed)
await merchant.close();
With a real merchant, use its origin and payTo from its 402 (34 merchants with tested values: deepfirstsearch.com/developers). The actions plug into AgentKit's framework extensions (LangChain, Vercel AI SDK, OpenAI Agents) like any other provider.
AgentKit's x402ActionProvider lets the model pick the payment option (selectedPaymentOption includes payTo and the amount) when it retries a 402. That is convenient, and it is also where a prompt injection can redirect a payment. This provider keeps the model out of money decisions:
Payment refused by policy: …), never thrown, so the agent can explain what happened. Since 0.2.0, with @deepfirstsearch/agent-pay >= 0.8.0, the text carries the refusal's stable code and what to do about it, e.g. Payment refused by policy [price_changed → ask the owner]: … or [payee_mismatch → do not retry, report it] (codes listed in the SDK README, "Refusal codes"). Older SDKs give the text without the tag. Blocks carry codes too (Payment blocked [settlement_pending → …]; also settled_not_delivered, settlement_unknown (agent-pay >= 0.8.2), rate_limited, kill_switch), with the extra action resend_same: fetch the same URL again, and the SDK resends the same signed authorization without signing a new one.paid_fetch fetches any public https URL the model asks for; only payments are restricted to registered merchants. A non-402 response from an unregistered origin is returned as data (fenced as untrusted), so treat it like any fetch action you give a model. Hosts that are or resolve to loopback, private, link-local or CGNAT addresses, localhost names and plain http are refused unless they are in the sealed plan (registered merchants) or you pass allowPrivateNetwork: true to agentPayActionProvider; redirects are returned, not followed. Errors other than policy refusals (which can carry an RPC URL with its API key) reach the model as a fixed text.vaultFunder, so even a compromised machine can only spend inside the owner-signed caps. See the SDK.@CreateAction decorator, so invoking it sends no analytics event.Note: AgentKit makes an outbound analytics call. Its wallet providers send an initialization event to Coinbase's analytics endpoint when they are created, including in the offline example above (this package's action sends none). In AgentKit 0.10.4 that call isn't awaited, so if the endpoint answers with an error the rejection is unhandled and Node exits. Until that's fixed upstream, the process.on("unhandledRejection", …) handler at the top of the example keeps it running; in a real agent, log those rejections rather than ignoring them.
agentKitPayer(walletProvider) works with any AgentKit EVM wallet provider (ViemWalletProvider, CdpEvmWalletProvider, …): it signs EIP-712 payment authorizations and refuses to sign transactions. Any viem LocalAccount works as the payer too.
npm ci && npm run typecheck && npm test # includes an AgentKit.from(...) run against a mock x402 merchant
MIT. Questions: GitHub Discussions.
FAQs
Coinbase AgentKit action provider: agents fetch x402 APIs while the owner's Agent Safe policy decides every payment (no payee or amount in the model's hands)
The npm package @deepfirstsearch/agent-pay-agentkit receives a total of 0 weekly downloads. As such, @deepfirstsearch/agent-pay-agentkit popularity was classified as not popular.
We found that @deepfirstsearch/agent-pay-agentkit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.

Security News
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.

Threat Research
/Security News
A supply chain attack compromised LiteLLM 1.107.0 on PyPI and Docker, spreading malware that steals cloud credentials, developer secrets, and AI provider keys.