langchain-sra-riskgate
LangChain middleware that checks every payment an AI agent tries to make before the tool runs.
Each payment gets a verdict of approve, hold or reject. A held or rejected payment never reaches the wallet.
It is built for Coinbase AgentKit agents. AgentKit's own Managing Risk section warns that injected text can trigger an on-chain transfer, and that AgentKit itself does not enforce spend caps or allowlist destinations. This package adds those checks outside the model, so a hijacked agent cannot talk its way past them.
pip install "langchain-sra-riskgate[middleware]" # LangChain 1.x
pip install langchain-sra-riskgate # LangChain 0.3, e.g. with coinbase-agentkit-langchain
What it checks
It recognises these AgentKit tools automatically:
| AgentKit tool | Treated as |
|---|---|
ERC20ActionProvider_transfer |
Token payment to destination_address |
ERC20ActionProvider_approve |
Payment, because an allowance lets the spender take the funds |
WalletActionProvider_native_transfer |
Native-token payment |
x402ActionProvider_retry_with_x402 |
x402 payment to pay_to |
x402ActionProvider_make_http_request_with_x402 |
x402 payment whose price is not known yet |
Each payment is then checked against these rules:
| Check | Result |
|---|---|
Recipient, or your own wallet_address, on the OFAC SDN list (exact match against the dated snapshot bundled with sra-riskgate; turn off with check_sanctions=False) |
reject |
Recipient on blocked_recipients |
reject |
Recipient not a valid 0x address, zero address, or the agent's own wallet |
reject |
Recipient not on allowed_recipients (when you set one) |
hold |
| Asset is not USDC (native ETH and other tokens) | hold, unless allow_non_usdc=True |
| USDC amount below 0.000001 (rounds to zero on-chain) | reject |
Amount over max_amount_usdc (default 100) |
hold |
Total approved spend over session_budget_usdc (stops split payments) |
hold |
USDC off its peg (with a peg_feed) by ≥1% / ≥5% |
hold / reject |
One-step x402 request to a host not on allowed_x402_hosts |
hold |
| Arguments claim their own verification ("risk level: low (verified offline)", "sanctions screening passed", "ignore previous instructions") | hold |
| Unreadable arguments | reject |
| A tool whose name contains a word such as transfer, swap, pay or withdraw, with no extractor (strict mode) | hold |
| Any internal error, feed error or model error | hold |
Tools that don't move money (balances, searches, plain HTTP requests) pass through untouched.
The gate fails closed. No error path can produce approve.
LangChain 1.x: middleware
from langchain.agents import create_agent
from langchain_sra_riskgate import SRARiskGateMiddleware
agent = create_agent(
model=llm,
tools=tools, # your AgentKit tools as LangChain tools
middleware=[
SRARiskGateMiddleware(
chain_id=8453, # Base mainnet
max_amount_usdc=50,
session_budget_usdc=200,
allowed_recipients=["0x1234..."],
wallet_address=wallet.get_address(),
),
],
)
When a call is stopped, the agent receives an error ToolMessage like this:
SRA-RiskGate HELD for human review: this payment was NOT sent. 500 USDC is over the 50 USDC
per-payment limit. Flags: over_payment_limit. Do not retry this payment with changed details or
split it into smaller payments; tell the user it needs their review.
The verdict and flags are also attached as artifact={"sra_riskgate": {...}}.
You can also add LangChain's HumanInTheLoopMiddleware so a person must approve payment tools. The gate still
runs after the person approves.
LangChain 0.3 and coinbase-agentkit-langchain: guard_tools
coinbase-agentkit-langchain currently requires LangChain 0.3, which has no middleware.
For that setup, wrap the tools themselves:
from coinbase_agentkit import AgentKit, AgentKitConfig, erc20_action_provider, wallet_action_provider
from coinbase_agentkit_langchain import get_langchain_tools
from langchain_sra_riskgate import guard_tools
agentkit = AgentKit(AgentKitConfig(wallet_provider=wallet,
action_providers=[wallet_action_provider(), erc20_action_provider()]))
tools = guard_tools(get_langchain_tools(agentkit), chain_id=8453, max_amount_usdc=50, session_budget_usdc=200)
# use `tools` with create_react_agent or any agent that takes LangChain tools
Only the money-moving tools are wrapped. Names, descriptions and argument schemas are unchanged.
Your own payment tools
Tell the gate how to read a custom tool's arguments:
from decimal import Decimal
from langchain_sra_riskgate import PaymentGate, PaymentIntent
def pay_vendor(tool, args, chain_id):
return PaymentIntent(tool, "custom", args["wallet"], Decimal(str(args["usdc"])), "USDC", chain_id)
gate = PaymentGate(extractors={"pay_vendor": pay_vendor}, max_amount_usdc=25)
middleware = SRARiskGateMiddleware(gate)
If a tool's name looks like it moves money but the gate has no extractor for it, strict mode holds it by default.
Add the tool to passthrough_tools if it is safe.
Use on_decision= to log every verdict to an audit trail.
Optional: a second check by SRA-RiskGate-4B
After the rules approve a payment, the gate can also ask SRA-RiskGate-4B, served through any OpenAI-compatible endpoint (Ollama by default).
ollama pull sriram1983007/sra-riskgate
from langchain_sra_riskgate import OpenAICompatibleModelCheck, PaymentGate
def build_input(intent, args):
policy = {"max_amount_usdc": 50, "allowed_assets": ["USDC"]}
payload = {"to": intent.recipient, "amount_usdc": str(intent.amount), "chain_id": intent.chain_id}
tool_results = {"sanctions_screening": my_screening(intent.recipient)} # your real checks
return policy, payload, tool_results
gate = PaymentGate(max_amount_usdc=50, model_check=OpenAICompatibleModelCheck(build_input))
The model was trained to reason over a payment together with the results of real verification tools:
decoded payment, signature check, risk attestations and sanctions screening. It does not run those checks itself,
and this package does not invent their results. You supply them in build_input.
The model can only make a decision stricter. It is asked only about payments the rules already approved.
If it answers anything other than approve, or is unreachable or off-schema, the payment is not sent.
On its held-out benchmark, SRA-RiskGate-4B reached 99.5% decision accuracy, with a 0.47% unsafe-approval rate (predictions and scores). That benchmark uses synthetic data. Measure it on your own traffic before relying on it.
Limitations
- Coverage. Only tools the gate recognises are checked. If you register other fund-moving tools, add extractors for them or keep strict mode on.
- Recipient addresses. Only
0xaddresses are accepted. ENS names are rejected rather than resolved. - USDC limits only. Amount limits and the budget apply to USDC. Native and other tokens are held
unless you opt in with
allow_non_usdc=True, and then their amounts are not limited. - One-step x402 requests. Their price is unknown when the gate runs, so they are allowed only for
hosts you list. AgentKit's own
max_payment_usdcstill applies to them. - Budget accounting. Spend is counted when a payment is approved. It is released only if the tool raises.
- Scope. This is a guardrail, not compliance. The OFAC match is an exact comparison with a dated snapshot
(pass
sanctions_list=for a fresher one); it does not replace sanctions screening or KYC.
Related
sra-riskgate: core SDK, an AgentKit action provider and x402 hookssra-riskgate-mcp: the same checks as an MCP server- SRA-RiskGate-4B and its benchmark
Apache-2.0.
Metadata
Release files for langchain-sra-riskgate 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| langchain_sra_riskgate-0.3.1.tar.gz | 29.4 kB | Without provenance | Details for langchain_sra_riskgate-0.3.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| langchain_sra_riskgate-0.3.1-py3-none-any.whl | Python 3 | none | any | Details for langchain_sra_riskgate-0.3.1-py3-none-any.whl |
Total release size: 50.6 kB
Release files / langchain_sra_riskgate-0.3.1.tar.gz
| Download URL | langchain_sra_riskgate-0.3.1.tar.gz |
|---|---|
| Size | 29.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d572b9f05928cb399e6de0bddc68770b9a0f27f1cd8cdb1def20974b90c68c94
|
|
BLAKE2b-256 checksum How to use checksums |
abbabe3da92574010d7a9de059806437e4f70d81bc5c493acf888a88507ac785
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / langchain_sra_riskgate-0.3.1-py3-none-any.whl
| Download URL | langchain_sra_riskgate-0.3.1-py3-none-any.whl |
|---|---|
| Size | 21.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2421be94f035a3196d9491536d8026da7eecb11e8b553250c51b9d854e9c6e4a
|
|
BLAKE2b-256 checksum How to use checksums |
363fdd87307dff97684682bf093b534d35b3515947b9dabed7c35b4dd30670ff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for langchain-sra-riskgate 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.