Security

What is secret, what is public, and how Yebo protects execution.


What You Need to Keep Secret

| Credential | Where it lives | What it does | |------------|---------------|--------------| | ent_... API key | Server only — never client-side | Routes requests to your enterprise policy backend | | STRIPE_SECRET_KEY | Server only — environment variable | Real payment execution | | YEBO_RP_ID / YEBO_RP_ORIGIN | Server config | WebAuthn relying party — must match your domain | | Signing key private material | Managed by Yebo gateway — never exposed | Signs PAIs and CARs |

None of the cryptographic signing keys are accessible to your application code. The gateway manages all key material internally. You receive receipts and signatures — you never handle keys.


What Is Public and Safe to Share

| Item | Why it is safe | |------|---------------| | signer_public_key in receipts | Public key — needed for independent verification | | GET /authorization-receipt/keys | Public key registry — intentionally public | | mandate_id | A hash — reveals nothing about the action | | receipt_id | A random UUID | | CAR bundles | Designed for sharing with partners, auditors, regulators | | pai_token | A signed proof — reveals no secrets, safe to log |


The Authorization Chain

Every executed action in Yebo carries a chain of five interlocking proofs. Removing or forging any one breaks the chain.

Passkey Session
  → AP2 Mandate (sealed, immutable)
    → Proof of Authorized Intent (PAI, ECDSA-signed)
      → Sentinel (12 invariant checks)
        → Enterprise Policy
          → Execution
            → CAR Receipt (ECDSA-signed)

No action can skip any step. Sentinel enforces this at the code level — it is not a policy, it is a cryptographic invariant enforcer.


AP2 Mandate

The mandate is the atomic authorization unit. It is:

  • Sealed at creation with Object.freeze() — no fields can be modified
  • Content-addressedmandate_id is a SHA-256 hash of its fields; tampering changes the ID
  • Time-limited — expires 5 minutes after issuance
  • Nonce-protected — each mandate contains a 128-bit random nonce that prevents replay
mandate_hash = SHA-256(
  mandate_id + subject_identity + capability + policy_hash +
  amount + currency + nonce + issued_at + expires_at
)

This hash is embedded in the PAI and re-verified by Sentinel before every execution.


Proof of Authorized Intent (PAI)

The PAI is an ECDSA P-256 signed token that proves:

  1. A specific human authorized a specific action
  2. The mandate was not tampered with
  3. The authorization happened at a specific time
  4. The authorization has not been replayed
pai_payload = {
  mandate_id, mandate_hash, identity_id,
  policy_hash, nonce, issued_at, expires_at
}

pai_token = "PAI." + base64url(payload) + "." + base64url(ECDSA_sign(SHA256(payload)))

PAI tokens are safe to log, share with partners, and store alongside transaction records. The signature proves authenticity; there is no secret embedded in the token itself.


Sentinel — 12 Invariant Checks

Sentinel runs before every execution. All 12 must pass. If any fails, execution stops unconditionally.

| # | Invariant | What it checks | |---|-----------|----------------| | INV-01 | mandate_integrity | mandate_id matches the hash of mandate contents | | INV-02 | mandate_not_expired | mandate expires_at has not passed | | INV-03 | capability_authorized | capability matches the PAI's declared scope | | INV-04 | policy_hash_consistent | policy_hash in mandate matches policy_hash in PAI | | INV-05 | agent_cannot_self_authorize | agent DID ≠ authorizing identity DID | | INV-06 | nonce_uniqueness | this nonce has never been used before (replay prevention) | | INV-07 | pai_signature_valid | PAI ECDSA signature verifies against the orchestration key | | INV-08 | mandate_hash_in_pai | mandate_hash embedded in PAI matches computed hash | | INV-09 | subject_identity_consistent | identity_id in session matches identity_id in mandate | | INV-10 | execution_requires_human | execution path was initiated from an authenticated session | | INV-11 | pai_not_expired | PAI expires_at has not passed | | INV-12 | integrity_threshold_met | identity integrity score meets minimum threshold for the capability |

Any SENTINEL_BLOCK response from the gateway means one of these invariants failed. Do not retry. Log the event and investigate.


Cryptographic Authorization Receipts (CAR)

Every completed action produces a CAR. It is:

  • ECDSA P-256 signed using the gateway's persisted signing key
  • Portable — contains the signing public key, so anyone can verify without contacting Yebo
  • Tamper-evident — any field modification invalidates the signature
  • Chain-linkable — can reference prior receipts, disputes, and settlements

Offline Verification

Anyone with the CAR can verify it using only standard cryptographic primitives:

# Using the Yebo CLI verifier
npx car-verify verify receipt.json

# Output:
# ✓ Structure valid
# ✓ Signature valid (ECDSA-P256-SHA256)
# ✓ Key ID: skey-abc123
# ✓ Authorized by: did:yebo:user-abc
# ✓ Capability: payment
# RESULT: VALID

Or verify a portable bundle:

npx car-verify verify-bundle bundle.json

Key Rotation

Signing keys are rotated periodically. When a key is rotated:

  1. The old key is kept in the registry indefinitely — old receipts remain verifiable
  2. New receipts are signed with the new key
  3. Rotated keys are still returned by GET /authorization-receipt/keys with status: "rotated"

Old receipts never become unverifiable due to key rotation.


Challenge & Continuation Tokens

When the capability kernel returns decision: "challenge", a continuation token is required to resume execution.

Continuation tokens:

  • Are ECDSA P-256 signed using the same signing infrastructure as CARs
  • Cover all action parameters — amount, merchant, capability, policy_hash
  • Are tamper-evident — any field modification invalidates the signature
  • Expire after 15 minutes
  • Cannot be replayed — each token has a unique token_id
  • Require a valid passkey session from the approving human

An attacker cannot inflate a $10 approved payment into a $10,000 execution — the amount is cryptographically bound in the token signature.


Integrity Score

Every identity has an integrity score (0–1000) that reflects their behavioral history:

| Tier | Score | What it enables | |------|-------|----------------| | Bronze | 0–399 | Basic actions, low amounts | | Silver | 400–649 | Standard commerce, moderate amounts | | Gold | 650–849 | High-value actions, enterprise workflows | | Platinum | 850–1000 | Unrestricted within policy |

The integrity score is calculated from the audit ledger — Sentinel violations, successful executions, session patterns. It is read-only — your application cannot set it; it is derived from behavior.


What Yebo Cannot Do

These guarantees are architectural, not just policy:

  • Cannot execute without a human session — Sentinel INV-10 enforces this
  • Cannot bypass Sentinel — invariants are checked in-process before any adapter call
  • Cannot replay a mandate — nonce registry is append-only, INV-06
  • Cannot tamper with a receipt after signing — ECDSA signature covers all fields
  • Cannot recover a private key — key material is managed by the gateway process, never returned via API

Security Contact

For vulnerability reports or security questions: security@yebo.dev

We operate a responsible disclosure policy. Do not publish vulnerabilities publicly before notifying us.


Get Started

npx create-yebo    # see Yebo's authorization control in action

Enterprise →  |  Start a pilot →  |  Contact security team →