BLA
BLA는 오픈소스 Blue Defense MCP와 CLI로, 소프트웨어 자산을 자동 AI 리버스 엔지니어링으로부터 보호합니다
AI 에이전트를 위한 오픈소스 알파, 검증 가능한 EUDI 지갑 명령과 사용 한도·유효기간을 설정하고 전체 권한 없이 승인합니다
Open source alpha for AI agents: verifiable EUDI Wallet mandates with scope, spending limits and expiry. Authorize agents without giving them full powers. On GitHub and npm.
보안TypeScript · PLpgSQLGitHub @plenipo-net온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Mandates, not full powers: EUDI Wallet-anchored authorisation for AI agents
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Mandates, not full powers. Plenipo lets a person authorise an AI agent from their European Digital Identity Wallet, and lets any service check that authority before the agent acts.
A plenipotentiary is an envoy who acts for someone and presents credentials to prove it. Plenipo gives AI agents the same thing, with one difference: the powers are never full. Every mandate has a scope, limits and an expiry, every sub-delegation can only narrow it, and the person can revoke it at any time.
Status: 0.5, experimental. The cryptography is real; wallets, PID providers and banks in the examples and the sandbox are test doubles. The code went through security reviews by independent AI review agents (two rounds for 0.3, one for 0.5), and their findings are fixed (see CHANGELOG.md); it has not yet been audited by an external security firm. Do not use it to protect real money or real data yet.
The EU Digital Identity (EUDI) Wallet is the state-recognised identity that every EU Member State must offer its citizens under eIDAS 2. It lets a person prove who they are online with the strength of an ID card at a counter, disclose only the data a service needs, and approve a specific piece of content, such as a payment, with that identity.
The wallet assumes the person is present. AI agents act when the person is not, and today they do it with passwords, API keys or saved cards: full powers, with no limits, no expiry, and no way for a service to know who authorised them. Plenipo lets a person approve a mandate in their EUDI Wallet once (allowed actions and counterparties, spending limits, expiry), lets the agent attach proof of that approval to every request, and lets any service verify it before acting. Sub-delegation can only narrow a mandate, and the person can revoke it at any time.
Person's EUDI Wallet Agent Sub-agent Service (MCP tool)
──────────────────── ───── ───────── ──────────────────
approves the mandate ──root──▶ holds mandate ──delegates──▶ narrower mandate
(PID + key binding over signs invocation ──▶ verifies chain,
the mandate hash) limits, revocation
ALLOW / DENY
urn:eudi:sca:emandate:1 type that certified EUDI wallets render, and let a
representative give a mandate on behalf of a company within the powers of their role.The wire formats and verification rules are specified in docs/spec.md, with test vectors for other implementations. The reasons behind them are in docs/design.md.
npm install plenipo
Node 22 or later. ES modules only.
From a clone of this repository:
npm ci
npm test # forged delegations, x5c, CRL/OCSP, status lists, OpenID4VP, TS12, shared stores, test vectors
# (Postgres and Redis tests run when the servers are available, and skip otherwise)
npm run demo # OpenID4VP approval, agent, sub-agent, a rail operator's MCP server
npm run example:gateway # a bank's HTTP API behind the Plenipo gateway
cd sandbox && docker compose up --build # a bank, a wallet, an agent platform and a live dashboard
The sandbox also runs with Node, has 17 scripted scenarios and an MCP bridge that lets Claude Desktop or Claude Code act as the agent. More in examples/.
The demo prints:
Booking bot: Roma-Milano 18 Oct, 89.00 euro
rail.example: ALLOW, acting for Mario Rossi, chain depth 1
Booking bot: Milano-Roma 20 Oct, first class, 120.00 euro
rail.example: DENY LIMIT_PER_OPERATION, amount 12000 exceeds 10000 on mandate 1
...
The person revokes the mandate; the platform flips its entry in the status list.
rail.example: DENY REVOKED, mandate 0 is revoked in its status list
import { createMandate, delegateMandate, createInvocation, verifyAuthorization, generateAgentKey } from 'plenipo';
const agent = await generateAgentKey();
const mandate = createMandate({
agentJwk: agent.publicJwk,
actions: ['travel.*'],
counterparties: ['*.rail.example'],
limits: { currency: 'EUR', per_operation: 15000, total: 30000 },
ttlSeconds: 7 * 24 * 3600,
maxDepth: 1,
});
// The wallet approves `encodeMandateTransactionData(mandate)` and returns the root.
const chain = { root, delegations: [] };
const invocation = await createInvocation(agent.privateKey, {
chain, // the invocation signs the hash of the chain it is presented with
mandateId: mandate.id, action: 'travel.book', counterparty: 'www.rail.example',
amount: { value: 8900, currency: 'EUR' }, aud: 'mcp://rail.example',
});
const decision = await verifyAuthorization(chain, invocation, {
trustAnchors, // CA certificates from the PID provider trusted lists
mandateStatusTrust, // who signs the mandate status lists
audience: 'mcp://rail.example',
nonces, // single-use nonce store, mandatory
ledger, // atomic spending reservations, needed for total limits
expected: { action: 'travel.book', counterparty: 'www.rail.example', amount: { value: 8900, currency: 'EUR' } },
});
// On ALLOW, commit decision.reservation after acting, or release it if you do not act.
To get the root from a real wallet, createMandateRequest builds the OpenID4VP request
(DCQL for the PID, the mandate as transaction data, encrypted response) and
handleMandateResponse turns the wallet's answer into the root. See
docs/interop.md for what wallets need to support.
On an MCP server, wrap a tool with guardTool from plenipo/mcp. The client sends the chain
and the invocation in the request _meta under plenipo/authorization. The guard must say how
it reads the counterparty and the amount from the tool arguments, or pass null when the tool
has none; it never trusts what the agent declares on its own:
const bookTrain = guardTool<{ route: string; price_cents: number }>(handler, {
action: 'travel.book',
counterparty: () => 'www.rail.example',
amount: (a) => ({ value: a.price_cents, currency: 'EUR' }),
trustAnchors, audience: 'mcp://rail.example', nonces, ledger,
});
| Area | Module | Docs |
|---|---|---|
| Mandates, delegation, invocations, verification | plenipo | spec, design |
| Wallet leg: OpenID4VP | plenipo | interop |
| Experimental: Delegate SD-JWT links, TS12 e-mandate roots, legal persons and roles | plenipo/experimental | delegation, root |
| Trust: x5c chains, EU Lists of Trusted Entities (ETSI TS 119 602), CRL and OCSP | plenipo | trust |
Keys in a KMS or HSM (ExternalSigner) | plenipo | this README |
| Shared stores on Postgres and Redis: ledger, nonces, idempotency keys, sessions, revocation | plenipo | stores |
| Idempotent retries: one signed key per intention, at most one attempt runs | plenipo | spec, integration |
| Bank integration: HTTP gateway, problem+json errors, status list service, audit log, OPA and Cedar export | plenipo | integration |
| Project | What it does | Difference |
|---|---|---|
| IETF Delegate SD-JWT (Google draft) | delegation chains for SD-JWT | no attenuation, revocation or required expiry; Plenipo enforces all three |
| Mastercard Verifiable Intent | layered SD-JWT mandates for commerce | anchored to card issuers; Plenipo is anchored to the EUDI Wallet PID |
| KYA Brasil | agent mandates signed with ICP-Brasil certificates | same idea on Brazil's PKI; Plenipo targets eIDAS 2 |
| Wallet4Agent (Talao) | identity and credential wallet for agents | gives agents a wallet; Plenipo gives people a way to authorise agents |
Plenipo aims to stay compatible with these formats rather than add another one.
See ROADMAP.md. Changes by version are in CHANGELOG.md.
plenipo_mandate and a TS12 e-mandate bound to the PID, with a test PID from the sandbox, and the
sandbox bank enforced them (docs/interop.md). No phone wallet yet: the EUDI
reference wallet core declares accepted types since release 0.31.0; IT-Wallet does not accept
custom types.maxStatusAgeSeconds).Contributions are welcome: read CONTRIBUTING.md. Report vulnerabilities privately as described in SECURITY.md, not in public issues.
Apache 2.0, see LICENSE and NOTICE. Copyright 2026 Fabio Lalli and the Plenipo contributors.
| MCP guard | plenipo/mcp | design |
| Test PID provider, wallet and CA (development only) | plenipo/testing | examples |
| Sandbox and walt.id setup | sandbox/ | sandbox, sandbox/README |