Skip to main content

Security middleware for x402 agentic payments — PII redaction, spending policy, and replay detection before blockchain commit

Project description

presidio-hardened-x402

PyPI version Python GitHub release License: MIT CI

v0.5.0 — OEM embed kit: rail-agnostic screening core + x402 binding layer, partner conformance suite, semver guarantees; plus PII redaction, spending policy, replay detection, audit logging, multi-party authorization, Prometheus metrics, and opt-in remote screening

Security middleware for the x402 payment protocol.

Intercepts x402 payment requests before transmission to servers and facilitators to enforce:

  • PII redaction — Presidio-based detection and redaction of personal data (emails, names, SSNs, credit cards, etc.) from payment metadata fields before they are sent to the payment server or facilitator API
  • Spending policy — per-agent, per-endpoint, and per-time-window budget limits that block or throttle payments before execution
  • Replay detection — HMAC-SHA256 fingerprinting of canonical payment fields to prevent duplicate and replayed payments; case-canonicalised on pay_to and currency (v0.4.0)
  • Audit logging — HMAC-chained JSON-L audit trail for every payment attempt (including blocked ones)
  • Multi-party authorization — n-of-m approval requirement for high-value payments, via webhook or HMAC-SHA256 cryptographic countersignature modes (v0.3.0)
  • Prometheus metrics — structured telemetry for every security control activation (v0.3.0)
  • Remote screening — opt-in remote_screening=True mode offloads PII analysis to the hosted screen.presidio-group.eu service via ScreeningClient; avoids the in-process spaCy dependency (v0.4.0)
  • Per-origin wallet allowlist — per-origin pay_to allowlist blocks payments to attacker-controlled addresses when a DNS-poisoned 402 response substitutes the recipient (chain-06 mitigation) (v0.4.0)
  • Rail-agnostic core + binding layer — the screening pipeline (ScreeningPipeline) is payment-protocol-independent; everything x402-specific lives in bindings/x402. Embed on a different rail by implementing PaymentProtocolBinding — the security guarantees travel with the core (v0.5.0)
  • OEM embed kitsemver/stability guarantees, partner-runnable conformance suite (python -m presidio_x402.conformance, 7 end-to-end checks, no network), and integration quickstarts for Coinbase CDP, LangChain, and CrewAI (v0.5.0)

Part of the presidio-hardened-* toolkit family.


Installation

pip install presidio-hardened-x402

For full NLP-based PII detection (PERSON, ORG, location, etc.):

pip install "presidio-hardened-x402[nlp]"
python -m spacy download en_core_web_sm

For production replay guard with cross-process deduplication:

pip install "presidio-hardened-x402[redis]"

For Prometheus metrics export:

pip install "presidio-hardened-x402[prometheus]"

For policy-as-code schema validation:

pip install "presidio-hardened-x402[schema]"

Quick Start

Before (bare x402 — no security controls)

import httpx

async def pay_and_fetch(url: str, signer) -> httpx.Response:
    async with httpx.AsyncClient() as client:
        resp = await client.get(url)
        if resp.status_code == 402:
            payment_details = parse_402_header(resp.headers)
            # No PII check. No policy check. No replay check.
            payment_token = await signer.sign(payment_details)
            resp = await client.get(url, headers={"X-PAYMENT": payment_token})
        return resp

After (presidio-hardened-x402)

from presidio_x402 import HardenedX402Client

async def my_signer(details):
    # Your existing signing logic (eth-account, solders, CDP SDK, etc.)
    ...

client = HardenedX402Client(
    payment_signer=my_signer,
    policy={
        "max_per_call_usd": 0.10,
        "daily_limit_usd": 5.0,
        "per_endpoint": {"https://api.example.com": 1.0},
    },
    pii_action="redact",          # redact | block | warn
    pii_entities=["EMAIL_ADDRESS", "PERSON", "US_SSN", "CREDIT_CARD"],
    replay_ttl=300,               # seconds
)

response = await client.get("https://api.example.com/resource")

What happens transparently:

  1. Client sends GET /resource → server returns 402 with payment details
  2. PIIFilter scans resource URL, description, and reason fields; redacts any PII
  3. PolicyEngine checks: amount ≤ per-call limit? daily spend within budget? endpoint limit OK?
  4. ReplayGuard checks: have we paid this exact request within the TTL window?
  5. AuditLog records the attempt (pass or block) as a tamper-evident JSON-L entry
  6. If all checks pass, signer is called → payment header sent → resource returned

Configuration

Policy

from presidio_x402 import HardenedX402Client, PolicyConfig

policy = PolicyConfig(
    max_per_call_usd=0.05,         # block if maxAmountRequired > this
    daily_limit_usd=2.00,          # block if 24h aggregate spend would exceed this
    per_endpoint={
        "https://premium-api.io": 0.50,  # per-endpoint daily limit
    },
    window_seconds=86400,          # time window for aggregate limits (default: 24h)
    agent_id="my-agent-v1",        # tag audit events with an agent identifier
)

client = HardenedX402Client(payment_signer=signer, policy=policy)

PII Filter

# regex mode (default, zero-setup): catches structured PII
client = HardenedX402Client(
    payment_signer=signer,
    pii_mode="regex",
    pii_entities=["EMAIL_ADDRESS", "PHONE_NUMBER", "US_SSN", "CREDIT_CARD"],
    pii_action="redact",
)

# nlp mode: full spaCy NER (requires: pip install presidio-hardened-x402[nlp])
client = HardenedX402Client(
    payment_signer=signer,
    pii_mode="nlp",
    pii_entities=["EMAIL_ADDRESS", "PERSON", "LOCATION", "US_SSN"],
    pii_action="block",     # raise PIIBlockedError instead of redacting
)

Replay Guard

# In-memory (default, single-process)
client = HardenedX402Client(payment_signer=signer, replay_ttl=300)

# Redis-backed (production, cross-process)
client = HardenedX402Client(
    payment_signer=signer,
    replay_ttl=300,
    redis_url="redis://localhost:6379/0",
)

Audit Log

import sys
from presidio_x402 import HardenedX402Client
from presidio_x402.audit_log import StreamAuditWriter

client = HardenedX402Client(
    payment_signer=signer,
    audit_writer=StreamAuditWriter(sys.stdout),   # write JSON-L to stdout
)

Multi-Party Authorization (v0.3.0)

For high-value payments that require human or system oversight before execution:

from presidio_x402 import HardenedX402Client
from presidio_x402.mpa import MPAConfig, MPAApproverConfig, MPAEngine

mpa = MPAEngine(MPAConfig(
    threshold=2,               # require 2 of 3 approvals
    min_amount_usd=1.00,       # only for payments ≥ $1.00
    timeout_seconds=30,
    approvers=[
        MPAApproverConfig("alice", mode="webhook",
                          webhook_url="https://approvals.internal/alice"),
        MPAApproverConfig("bob",   mode="webhook",
                          webhook_url="https://approvals.internal/bob"),
        MPAApproverConfig("charlie", mode="webhook",
                          webhook_url="https://approvals.internal/charlie"),
    ],
))

client = HardenedX402Client(payment_signer=signer, mpa_engine=mpa)

Approval endpoints receive a POST with payment details and must return {"approved": true}. For machine-to-machine approvals, use mode="crypto" with HMAC-SHA256 countersignatures and pass them via mpa_signatures={"approver_id": "hex_sig", ...} in the request kwargs.


Prometheus Metrics (v0.3.0)

from presidio_x402 import HardenedX402Client
from presidio_x402.metrics import MetricsCollector

collector = MetricsCollector()
client = HardenedX402Client(payment_signer=signer, metrics_collector=collector)

# Expose /metrics endpoint (e.g., FastAPI)
from prometheus_client import generate_latest, CONTENT_TYPE_LATEST

@app.get("/metrics")
def metrics():
    return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)

Available metrics: x402_payments_total, x402_payment_amount_usd (histogram), x402_pii_detections_total, x402_policy_violations_total, x402_replay_detections_total, x402_mpa_events_total.


Policy-as-Code (v0.3.0)

Define spending policy in a TOML or JSON file and validate it against the x402 policy JSON Schema:

# policy.toml
max_per_call_usd = 0.10
daily_limit_usd  = 5.00
agent_id         = "my-agent"

[per_endpoint]
"https://premium-api.io" = 0.50

[mpa]
threshold       = 2
min_amount_usd  = 1.00
timeout_seconds = 30

[[mpa.approvers]]
approver_id = "alice"
mode        = "webhook"
webhook_url = "https://approvals.internal/alice"
from presidio_x402.x402_policy_schema import load_policy_file

policy = load_policy_file("policy.toml")
client = HardenedX402Client(payment_signer=signer, policy=policy)

Remote Screening (v0.4.0)

Offload PII analysis to the hosted screen.presidio-group.eu service. Useful when you want to keep the agent process small (no in-process spaCy model) and centralise screening policy across many agents.

from presidio_x402 import HardenedX402Client

client = HardenedX402Client(
    payment_signer=signer,
    remote_screening=True,
    screening_api_key="...",   # obtain by registering at screen.presidio-group.eu
)

The free tier serves the regex-mode screening backend at 100 screenings/day per key. Falls back to local regex / NLP modes if the network is unhealthy, so the client never hard-fails on a screening-service outage.

Per-origin wallet allowlist (v0.4.0)

Defence against DNS-poisoning attacks that substitute the recipient wallet in a 402 response. Configure the trusted pay_to addresses per resource origin:

client = HardenedX402Client(
    payment_signer=signer,
    trusted_wallets={
        "https://api.example.com": {"0xAbC...123"},
    },
)

Payments to a pay_to not in the allowlist for the response's origin are blocked before signing.


Kubernetes Deployment (v0.3.0)

Deploy as a sidecar using the bundled Helm chart:

helm install x402 ./helm \
  --set x402.agentId=my-agent \
  --set x402.maxPerCallUsd=0.10 \
  --set x402.dailyLimitUsd=5.00 \
  --set serviceMonitor.enabled=true

See docs/soc2-reference-architecture.md for SOC 2 TSC mapping, GDPR obligations, and deployment patterns.


Exceptions

Exception Raised when
PIIBlockedError PII detected in metadata and pii_action="block"
PolicyViolationError Payment amount or aggregate spend exceeds configured limit
ReplayDetectedError Payment fingerprint matches a recent transaction
X402PaymentError Upstream payment signing or network error
MPADeniedError Multi-party authorization required but not enough approvals received
MPATimeoutError Multi-party authorization webhook approval timed out

All exceptions are importable from presidio_x402.


Research Artifacts

Artifact Location Description
Synthetic corpus vstantch/x402-pii-corpus on Hugging Face · corpus/ 2,000 labelled x402 metadata triples; generator (generate.py, seed=42) + metadata (corpus_meta.json); raw JSONL reproducible from seed
Precision/recall sweep experiments/ 42-configuration grid search (run_sweep.py); latency benchmark (run_latency.py)
Dune Analytics queries dune/ 6 Trino SQL queries used to characterise the live x402 ecosystem (20 projects, 96 wallets, 11 chains, ≥79M transactions); see dune/README.md

Roadmap

Version Milestone
v0.1.0 PII redaction + spending policy + replay detection
v0.2.0 Synthetic corpus + 42-configuration precision/recall sweep, LangChain/CrewAI adapters, compliance report · arXiv:2604.11430
v0.2.1 Live ecosystem characterisation via Dune Analytics (20 projects, 96 wallets, 11 chains, ≥79M transactions); IEEE S&P magazine article submitted; IEEE TIFS paper under review · Corpus: v0.2.1/dataport/, Hugging Face, IEEE DataPort (doi:10.21227/kpsz-nq73)
v0.3.0 Multi-party authorization (mpa.py: n-of-m, webhook + crypto modes) · Policy-as-code JSON Schema (IETF draft candidate) · Prometheus metrics exporter · Kubernetes Helm chart + Docker image · SOC2 reference architecture
v0.4.0 Screening API launch — hosted screen.presidio-group.eu free tier (regex mode, 100 req/day) · ScreeningClient + remote_screening=True mode · per-origin pay_to allowlist (chain-06 mitigation) · audit-cycle hardening (F-A/B 2026-05-03, F-C/D/E 2026-05-10, F1/F2/F3 2026-05-17); see CHANGELOG.md
v0.5.0 OEM embed kit — rail-agnostic ScreeningPipeline core + bindings/x402 layer (PaymentProtocolBinding protocol, hedge against rail fragmentation: ACP/Tempo, AP2) · SEMVER.md stability guarantees · partner conformance suite (python -m presidio_x402.conformance) · CDP/LangChain/CrewAI quickstarts · SBOM in CI · freshness-bound MPA countersignatures (F-8) — current
v0.6.0 Multi-tenant key scoping · enterprise-tier remote audit sinks (S3 / Splunk / Datadog) · third-party security audit · SLSA L3 hardened build worker · hard startup-gates for PRESIDIO_X402_*_KEY env vars
v0.7.0 SLO payment broker — x402 micropayments as runtime infrastructure bids; presidio-hardened-arch-translucency integration

See PRESIDIO-REQ.md for full deliberation and rationale.


License

MIT


SDLC

This repository is developed under the Presidio hardened-family SDLC: https://github.com/presidio-v/presidio-hardened-docs/blob/main/sdlc/sdlc-report.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

presidio_hardened_x402-0.5.0.tar.gz (508.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

presidio_hardened_x402-0.5.0-py3-none-any.whl (73.2 kB view details)

Uploaded Python 3

File details

Details for the file presidio_hardened_x402-0.5.0.tar.gz.

File metadata

  • Download URL: presidio_hardened_x402-0.5.0.tar.gz
  • Upload date:
  • Size: 508.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for presidio_hardened_x402-0.5.0.tar.gz
Algorithm Hash digest
SHA256 54c1f1a22e844984125dd1dee26059ee6635a29bd1d18816fc1271f20570a4d9
MD5 d344092aff3c5e92ff16b3569621cb4b
BLAKE2b-256 c36dc24b35c433291e14356a8887c07a2a9b71343c68d5ba71d36d2442980f25

See more details on using hashes here.

Provenance

The following attestation bundles were made for presidio_hardened_x402-0.5.0.tar.gz:

Publisher: publish.yml on presidio-v/presidio-hardened-x402

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file presidio_hardened_x402-0.5.0-py3-none-any.whl.

File metadata

File hashes

Hashes for presidio_hardened_x402-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 de92fc9322ff1168fbf7733b3b0372e71d8ebe22223b7986dfd4f0d0ca86e6cc
MD5 3422c4e38c89bddd821538795805e895
BLAKE2b-256 af52467ad08f85ca372db9519f2e28a054b0524cbe2bd3ec7d12ecff26664daf

See more details on using hashes here.

Provenance

The following attestation bundles were made for presidio_hardened_x402-0.5.0-py3-none-any.whl:

Publisher: publish.yml on presidio-v/presidio-hardened-x402

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page