Security

The agent proposes. Software decides.

A language model is a useful thing to have proposing payments and a dangerous thing to have authorising them. Paygente’s security posture follows from that one division: everything creative happens before the decision, and the decision itself is deterministic, bounded and recorded.


Controls

Deterministic authorization

The policy engine is a pure function with no I/O, no randomness, no clock of its own and no model. Its inputs are snapshotted alongside the decision, so any past decision can be re-explained exactly.

No reusable credentials

An agent never receives a private key, a card number or a reusable payment credential. It receives a decision. There is nothing for an injection to exfiltrate.

No dynamic code from policies

A policy is a closed set of named rules stored as columns. There is no expression language, so a policy cannot loop, cannot fail to terminate and cannot execute.

Tenant isolation

Every query is scoped by organization. Another tenant’s record is reported as not found, with the same status and the same message as one that does not exist.

Idempotent execution

Four independent mechanisms refuse a second payment: the state machine, a row lock, a database unique index and the rail’s own replay memory.

Kill switch

An Owner or Admin can stop every execution in the organization immediately, without revoking anything. Approvals survive; execution does not resume until the switch does.

Append-only audit

Audit events are written in the same transaction as the change they describe. UPDATE, DELETE and TRUNCATE are refused by a database trigger — for the application too.

Sanitised records

Audit metadata and logs pass through a redaction layer that strips anything credential-shaped and bounds the size. Raw request bodies are never stored.


Threat model

What we expect to go wrong, and what stops it. Where a control does not yet exist, it says so.

T-01

Prompt injection

Scenario

Content an agent reads instructs it to pay an attacker, or to raise its own limit.

Control

An agent can only propose. Approval, execution, revocation and policy changes are outside its permission set entirely, so a persuaded agent has nothing to escalate to. A proposal to an unapproved recipient is denied by the policy engine, which reads data rather than instructions.

T-02

Malicious recipient substitution

Scenario

An attacker persuades an agent — or a careless operator — to pay a lookalike destination.

Control

Recipients are registered ahead of time, carry a verification status and a risk classification, and a policy can restrict an agent to a named allow-list. Changing a recipient’s verification status is a privileged, audited act. After execution, the identifier the rail actually paid is compared with the one the mandate authorised, and a mismatch is recorded as a mismatch.

T-03

Duplicate execution

Scenario

A retry after a timeout, or two operators acting at once, pays twice.

Control

Four independent refusals: the state machine forbids re-entering execution once an attempt has succeeded; the mandate row is locked for the transaction; a partial unique index permits at most one succeeded payment attempt per mandate; and the rail replays the original result for a repeated idempotency key.

T-04

Approval impersonation

Scenario

Someone approves a payment they are not entitled to approve — including their own.

Control

Approval requires the permission server-side; the UI never decides. A unique index allows exactly one decision per mandate. When the organization requires a separate approver, the person who proposed a payment cannot approve it.

T-05

Cross-tenant access

Scenario

A caller reads or acts on another organization’s mandate.

Control

Every query is scoped by organization in the data layer, and every service takes an explicit actor rather than reading ambient state. A record belonging to another tenant returns 404 — identical to one that does not exist — so status codes cannot be used to enumerate.

T-06

Compromised API key

Scenario

A credential leaks and an attacker calls the API as the customer.

Control

The blast radius is the policy, not the bank account: an attacker can propose payments, but every one is bounded by amount, recipient, asset and expiry, and anything above the threshold still needs a person. An administrator can stop all execution instantly with the kill switch. Phase 1 issues no API keys at all — see the boundary below.

T-07

Replay attacks

Scenario

A captured request is resent to cause a second effect.

Control

Mutating requests carry an idempotency key whose uniqueness is a database constraint. The same key with the same body replays the original result; with a different body it is refused rather than silently accepted.

T-08

Partner webhook spoofing

Scenario

A forged callback claims a payment settled that never did.

Control

No inbound webhook endpoint exists in this release, because no partner does. The design is documented: signed payloads with a shared secret, timestamp tolerance, replay rejection by event id, and — decisively — a partner claim is never trusted on its own. Settlement is confirmed by reading back from the rail, not by believing what arrived.

T-09

Agent hallucination

Scenario

An agent invents a supplier, an invoice or an amount.

Control

An invented recipient does not exist and cannot be paid. An invented amount is still bounded by the policy. An invented purpose is recorded verbatim and read by whoever approves. The agent’s claim about what happened is never the record — the audit trail is.

T-10

Insider misuse

Scenario

A privileged user raises a limit and spends against it.

Control

Roles are separated: an Approver cannot create mandates or change policies; an Operator cannot approve or change limits; only an Owner can change who holds which role. Every policy change is audited with the before and after values, and the audit table cannot be edited by anyone, including the application.

T-11

Reconciliation failure

Scenario

What a rail did diverges from what was authorised, and nobody notices.

Control

After every execution the amount and destination the rail reports are compared against the mandate, and the result is written as an explicit audit event — matched or mismatched. A mismatch is surfaced on the mandate rather than smoothed over.


What this release does not have

Naming the gaps is part of the security posture. A control that is claimed but absent is worse than one that is missing and known.

  • No authentication

    The sandbox uses a clearly labelled local development identity that names a seeded demo user. It is not a login, issues no token and is not a security control. The authorization boundary above it is real and is what an enterprise identity provider will plug into.

  • No API keys

    No credential is issued, so none can leak. Machine access in production will need scoped, revocable keys with their own rate limits.

  • Rate limiting is per-process

    A fixed window held in memory. It defines where the limit belongs; it does not hold across a fleet and resets when the process does. A shared store or an edge proxy replaces it.

  • No partner webhooks

    There is no inbound callback endpoint, because there is no partner. The signing strategy is designed and documented, not implemented.

  • Spend windows are UTC for everyone

    A daily limit means a UTC day regardless of where an organization operates. Per-organization timezones are deliberately deferred: getting them wrong silently widens a limit, which is worse than being uniform.

  • No sanctions or KYB screening

    Recipient verification is a status a person sets. It is not a screening result and must not be presented as one.

The regulatory boundary