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 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 |
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. 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.2.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 | |
|---|---|---|---|
| langchain_sra_riskgate-0.2.1.tar.gz | 27.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| langchain_sra_riskgate-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.0 kB
Release files / langchain_sra_riskgate-0.2.1.tar.gz
| Download URL | langchain_sra_riskgate-0.2.1.tar.gz |
|---|---|
| Size | 27.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1767a6e5deb11628bf15b0b76cc35430b0ea2e3c5879c7e8819653803dd93103
|
|
BLAKE2b-256 checksum How to use checksums |
d517ca3957295b660e6be23c5d9b7872ee3935a509bf74e8da07ef6a706844cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Release files / langchain_sra_riskgate-0.2.1-py3-none-any.whl
| Download URL | langchain_sra_riskgate-0.2.1-py3-none-any.whl |
|---|---|
| Size | 20.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bc0d15288387c32ffc871841b1ecc81aec4b2d730a18bf1116c8868ac2134390
|
|
BLAKE2b-256 checksum How to use checksums |
8dbadd18bffd9adeb6134927808b7a1dc1ee71ec5f2e6c37e7502e2b5a734fbe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|