Security posture

What we hold, and what we refuse to.

Ratchet sits in front of your most consequential actions. The smaller its blast radius, the better it does that job — so it is designed to know as little as possible.

Data boundaries

What Ratchet stores

  • A SHA-256 fingerprint of your payload — never the payload
  • Effect type, idempotency key, state, attempt count, timestamps
  • The result you explicitly choose to record for replay
  • Optional agent_id, run_id, and a small request_summary you control
  • Declared costs, in micro-USD
  • An HMAC of each API key secret, keyed by a server-side secret

What Ratchet never has

  • Your vendor credentials, API keys, or tokens
  • The content of the actions it gates
  • Network access to your systems — the gate is inbound only
  • The ability to perform, retry, proxy, or modify any side effect
  • Custody of any funds, yours or your customers'

Because only a fingerprint is stored, Ratchet can tell that a key was reused with different arguments — a real class of bug — without ever being able to reconstruct those arguments.

Implemented controls

Each of these has a test in the suite. Nothing here is aspirational.

Identity and access

  • Keys stored as HMAC-SHA256, peppered with a server secret — a database leak alone yields no usable key
  • Constant-time comparison, run even for unknown prefixes so timing reveals nothing
  • Least-privilege scopes; a gating agent needs only effects:begin and effects:report
  • Immediate revocation, and per-key daily spend ceilings

Tenant isolation

  • Every query is scoped by workspace; there is no unscoped read path
  • A cross-tenant lookup returns 404, never a hint that the record exists
  • A valid lease token from another workspace is still rejected
  • The same idempotency key in two workspaces is two independent effects

Outbound requests (SSRF)

  • Webhook destinations must be https, DNS hostnames, on port 80 or 443
  • Private, loopback, link-local, CGNAT, and cloud-metadata ranges are blocked — IPv4, IPv6, and IPv4-mapped forms
  • DNS is re-resolved on every attempt and the socket is pinned to the checked address, closing the rebinding window
  • A host resolving to any private address is refused outright, not filtered
  • Redirects are never followed; response bodies are capped and discarded

Integrity of state

  • A database-level unique constraint is what enforces at-most-once — not application logic
  • Fencing tokens: a stalled worker cannot overwrite a newer attempt
  • Budget reservations lock every scope before validating any, so parallel workers cannot collectively exceed a ceiling
  • Credit movements are an append-only ledger, deduplicated by event id

Prompt injection

  • Agent-supplied text is treated strictly as data. Nothing in a payload, summary, or result is ever interpreted as an instruction by Ratchet
  • Effect types are pattern-constrained; results are size-capped
  • Decisions come from stored policy and database state — never from request content
  • An injected payload cannot widen a key's scopes, raise a budget, or change a policy

Payments

  • Card details are entered on the provider's own page and never reach Ratchet
  • Credit is applied only on a signed webhook — never because a browser reached a success URL, which is not proof that payment settled
  • Payment webhooks are verified by HMAC over the raw body, with a replay window and event-id deduplication
  • Refunds and disputes reverse credit through a compensating ledger entry, capped at what was actually credited
  • Crypto is non-custodial. No private key is held and no funds are taken into custody; payments go directly to an address the operator controls
  • Crypto quotes are struck in USD, so a price move between quote and settlement cannot mint credit. Underpayment is never rounded up

Rollback safety

  • A compensation is itself a gated effect, so a retried rollback cannot double-refund
  • A group being unwound refuses new forward steps
  • A step with no compensation is reported irreversible; the group settles unwind_failed rather than claiming a clean rollback
  • An effect with an unknown outcome blocks planning around it

Transport and abuse

  • Per-key rate limiting, so tenants cannot exhaust each other
  • Same-origin CORS by default; credentials are never granted to a wildcard origin
  • Unknown request fields are rejected rather than silently dropped
  • Secrets redacted from logs; internal detail never crosses the error boundary
  • Payment webhooks verified by HMAC over the raw body, with a replay window

Retention and deletion

Effect records expire on a per-effect-type schedule you configure, bounded by your plan. Expired records are deleted by the worker — a leased effect is never collected, so live work cannot disappear. Deleting a workspace cascades to its keys, effects, policies, ledger, webhooks, and audit trail.

Reporting a vulnerability

Security reports are welcome and will not be met with legal threats. Include reproduction steps and give a reasonable window before disclosure. Contact details belong in the deployed instance's configuration — this build ships no contact address rather than a fake one.

What we do not claim

No third-party audit has been performed. There is no SOC 2 report, no penetration test, and no compliance certification. The controls above are implemented and covered by automated tests; that is a different and lesser thing than independent verification, and we will not blur the two.