Dev.to Security 🔐 Cybersecurity 👁 0 📖 3 min read

ATC is now real: Ed25519-signed agent trust cards with working verify + revoke

Yesterday I wrote about 8 security layers for my MCP marketplace. Today I'm shipping the 9th: Agent Trust Cards (ATC) — and this time the cryptography is real, not a mock. What is ATC? ATC = SSL certificates

Yesterday I wrote about 8 security layers for my MCP marketplace. Today I'm shipping the 9th: Agent Trust Cards (ATC) — and this time the cryptography is real, not a mock.

What is ATC?

ATC = SSL certificates for AI agents. MarketNow acts as the Certificate Authority (CA). Every agent gets a cryptographically signed trust card that other agents can verify.

Agent A wants to call Agent B's tools
→ Agent A fetches Agent B's ATC: GET /api/atc?action=verify&card_id=X
→ Verifies the Ed25519 signature with the CA public key
→ Checks: not expired, not revoked, sentinel_score > threshold
→ If valid: trusts Agent B and proceeds
→ If invalid: refuses to interact

This is exactly how SSL works for websites, but for agents.

What's real now (vs what was mock before)

Component Before (mock) Now (real)
CA keypair 'marketnow-ca-public-key-placeholder' Ed25519 generated with crypto.generateKeyPairSync
Signature 'signed_by_marketnow_ca' (literal string) crypto.sign(null, data, privateKey) → 128 hex chars
Verify Always returned valid: true Fetches record from GitHub, verifies signature with crypto.verify, checks expiry + revocation
Revoke Returned "revoked" but didn't persist Updates the persisted record; future verify returns valid: false, reason: 'revoked'
Persistence None (1 hardcoded card) GitHub Contents API → _data/atc/{card_id}.json (public ledger)
Sentinel score Hardcoded 10 Fetched from real Sentinel certificate in _data/sentinel_certificates/

How it works

1. The CA keypair

const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
// Private key → Vercel env var MARKETNOW_ATC_CA_PRIVATE_KEY
// Public key → committed to _data/atc/ca-public-key.json

Anyone can fetch the CA public key:

GET https://marketnow.site/api/atc?action=ca-key

2. Issuing an ATC

POST https://marketnow.site/api/atc
Content-Type: application/json

{
  "action": "issue",
  "agent_id": "agent.example.myagent",
  "public_key": "<Ed25519 public key>",
  "capabilities": ["search", "recommend"],
  "protocol_language": "mcp",
  "skill_id": "mn-mcp-filesystem"
}

Response:

{
  "status": "issued",
  "card_id": "ATC-2026-1115271",
  "agent_id": "agent.example.myagent",
  "trust": {
    "sentinel_score": 4,
    "risk_level": "high",
    "certificate_id": "MN-SC-2026-8393995"
  },
  "signature": {
    "algorithm": "Ed25519 (RFC 8032)",
    "value": "bc79ee606339460a382f3ecc324c629e...",
    "signed_by": "MarketNow Sentinel CA"
  }
}

The signature is over the canonical JSON of the payload:

JSON.stringify(payload, Object.keys(payload).sort())

3. Verifying (independently)

Anyone can verify an ATC without trusting MarketNow's API:

import crypto from 'crypto';

// 1. Fetch the CA public key
const caKeyRes = await fetch('https://marketnow.site/api/atc?action=ca-key');
const { public_key_pem } = await caKeyRes.json();
const publicKey = crypto.createPublicKey(public_key_pem);

// 2. Fetch the ATC record
const atcRes = await fetch('https://marketnow.site/api/atc?action=verify&card_id=ATC-2026-1115271');
const atc = await atcRes.json();

// 3. Verify the signature yourself
const data = Buffer.from(JSON.stringify(atc.payload, Object.keys(atc.payload).sort()));
const signature = Buffer.from(atc.signature.value, 'hex');
const valid = crypto.verify(null, data, publicKey, signature);
// → true

4. Revoking

POST https://marketnow.site/api/atc
{
  "action": "revoke",
  "card_id": "ATC-2026-1115271",
  "reason": "Key compromised"
}

The persisted record is updated: status: 'revoked'. Future verify calls return:

{
  "valid": false,
  "reason": "revoked",
  "revoked_at": "2026-07-16T02:58:57.604Z",
  "revocation_reason": "Key compromised"
}

5. Framework translation (bonus)

ATC also translates between agent frameworks:

POST https://marketnow.site/api/atc
{
  "action": "translate",
  "from": "langchain",
  "to": "mcp",
  "message": {
    "name": "search",
    "description": "Search skills",
    "args_schema": { "type": "object", "properties": { "q": {"type":"string"} } }
  }
}

Returns the MCP-formatted tool schema (inputSchema instead of args_schema). Real schema mapping, not passthrough.

The public ledger

Every ATC is persisted to _data/atc/ in the public GitHub repo. Anyone can:

  • Audit the full ledger: GET /api/atc
  • Verify any card: GET /api/atc?action=verify&card_id=X
  • Check the CA key: GET /api/atc?action=ca-key
  • Clone the repo and verify signatures offline

No database, no proprietary backend. Just signed JSON files in a git repo. That's the transparency layer.

Why this matters

Agents are starting to call each other autonomously. A2A (Google) and MCP (Anthropic) handle the communication. But nobody handles trust.

Without trust:

  • Agent A can't know if Agent B is malicious
  • Agent A can't know if Agent B's tools have been audited
  • Agent A can't know if Agent B has been revoked (key compromised, ToS violation, etc.)

ATC fills that gap. It's the SSL layer for agent commerce.

Try it

# Get the CA public key
curl https://marketnow.site/api/atc?action=ca-key

# Issue a trust card for your agent
curl -X POST https://marketnow.site/api/atc \
  -H "Content-Type: application/json" \
  -d '{"action":"issue","agent_id":"your.agent","public_key":"your-ed25519-pubkey"}'

# Verify it
curl "https://marketnow.site/api/atc?action=verify&card_id=YOUR_CARD_ID"

— Edison Flores, AliceLabs LLC — marketnow.site

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.