Security Architecture
AGLedger produces one object: a signed record spanning the full lifecycle of a piece of automated work - the intent and authority at the start, the delegation in the middle, the result at the end, and the verdict when the work is gated. This whitepaper is written for security teams, compliance officers, and procurement reviewers: how the record is signed, what the signature covers, where the trust boundaries fall, how the software itself is built and signed, and how a third party confirms a chain offline. Every claim below is checkable offline against the exported bytes and a pin of the vault key taken from the operator, with no AGLedger account.
One signing key per Server instance. A single instance vault key (VAULT_SIGNING_KEY, Ed25519 by default) signs every entry in that Server’s chain; during a key change the outgoing and incoming keys overlap until the old one is retired (§6). There is no per-principal and no per-agent key. The signature is the notary’s.
Attribution lives inside the signature. The accountable principal (principal_agent_id) and the acting credential are named inside the signed payload, so the signature covers the attribution. This is notary-attested, tamper-evident attribution - not principal-held non-repudiation: the principal does not sign, and we do not represent that it did.
Self-hosted by design. AGLedger runs in your infrastructure and sends nothing to AGLedger LLC. Data leaves it only where you point it: webhooks to your endpoints, federation to peers you name, optional external anchoring, and on AWS Marketplace deployments the entitlement check with AWS License Manager. Federation carries only signed bytes.
Zero content inspection. AGLedger records accountability metadata - who notarized what, who delivered, who accepted. It never inspects, stores, or processes your business data, prompts, or model outputs.
Standards-based. COSE_Sign1 (RFC 9052, tag 18) over an in-toto v1 Statement payload, deterministic CBOR (RFC 8949 §4.2.1), Ed25519 + SHA-256, CWT Claims (RFC 8392 / RFC 9597), HMAC-SHA256, RFC 9421 HTTP Message Signatures, RFC 8785 JSON canonicalization, RFC 9457 problem details. No bespoke primitives.
1. The signed record - what the signature covers
The agent reports with its key; the notary signs what it reported. The agent (or any caller) makes the API call that records a stage of the work. The Server - not the caller - assembles the entry, encodes it, and signs it with the instance vault key. The authority being recorded is the principal’s; the signature is the notary’s.
Because the attribution rides inside the signed payload, an entry cannot be re-pointed at a different principal without invalidating the signature. The protected header carries the actor identity as a CWT private claim ({ key_id, role, owner_id }); any delegation context rides in the in-toto Statement predicate as on_behalf_of. Both are covered by the Ed25519 signature. To the auditor, the claim is exact: the chain proves what was reported, signed, and recorded, and that the attribution has not been altered since.
Agents are not required to hold signing keys. The default path needs no client-side cryptography from the agent: it authenticates and reports, and the notary signs. An optional per-request attestation path (X-Agent-Signature / X-Agent-Signature-Content-Hash), a no-op by default, lets a cert-bound caller co-sign its own request; the co-signature is carried into the envelope as predicate.on_behalf_of.agent_signature and honored only when the caller authenticated with an ephemeral cert (§7).
2. Deployment model and trust boundaries
AGLedger is software you deploy, not a service you send data to. One role: Server. Every install is the same binary. A Server is a sovereign domain: its own database, auth, agents, contracts, signing key, and chain. Federation participation is a per-record / per-contract / global flag, not a deployment mode.
AGLedger records accountability metadata in your infrastructure. Your data stays where it is, your traffic goes where it went, and a record reaches another organization only when its share flag is set. Topology, sizing, and the air-gapped install are on the install page.
3. Data classification and lifecycle
| Category | Storage | Sensitivity |
|---|---|---|
| Accountability metadata | PostgreSQL (your DB) | Business-sensitive |
| Audit vault | PostgreSQL (your DB) | Integrity-critical |
| API credentials | PostgreSQL (your DB) | Secret |
| Webhook secrets | PostgreSQL (your DB) | Secret |
Not stored, not inspected
Model prompts, completions, or training data
Business document content - AGLedger validates structure, never value
PII beyond what customers include in record metadata (customer-controlled)
Payment card data or banking credentials
All data resides in the PostgreSQL instance you provision. No external data stores, no phone-home: AGLedger does not collect product usage information.
Retention and deletion. The customer controls retention as the database operator. The audit vault is append-only by design, which is in deliberate tension with deletion regulations (GDPR Article 17, CCPA): Signed Statements hold accountability metadata, while record criteria and completion evidence live in separate tables that can be archived or purged. In encrypted mode (§4) the server stores only the encrypted evidence envelope and an evidence hash, so destroying the encryption key renders the content irrecoverable while chain integrity is preserved - cryptographic erasure.
4. Cryptographic architecture
| Layer | Standard | Purpose |
|---|---|---|
| Credential storage | HMAC-SHA256 | API keys stored as hashes, never plaintext |
| Webhook signing | HMAC-SHA256 · Ed25519 (RFC 9421) | Delivery integrity by default; RFC 9421 signatures for non-repudiable Settlement Signal payloads, verifiable against the published Server keys |
| Federation transport | Ed25519 per-request signing; RFC 8785 (JCS) | Peer authentication with per-instance keys over a domain-separated sign input addressed to the receiving Server; canonical JSON for body hashes and schema digests |
| Audit envelope | COSE_Sign1 (RFC 9052, tag 18) + Ed25519 | Signed Statement envelope; the COSE_Sign1 bytes feed the SHA-256 hash chain |
| Payload format | in-toto v1 Statement, CBOR per RFC 8949 §4.2.1 | Deterministic encoding of the audit payload |
| Identity in header | CWT Claims, RFC 8392 (label 15) / RFC 9597 | Issuer, subject, and actor named in the signed protected header |
| Data at rest | SHA-256 hash chain / AES-256-GCM | Vault tamper evidence; secret storage |
| Client-side encryption | AES-256-GCM / AES-256-GCM-SIV | Server-blind completion evidence: the server stores the encrypted envelope and an evidence hash; criteria stays server-readable |
Independent keys. The vault signing key and the federation signing key are separate per-instance keys, generated independently and never derived from each other.
Algorithm identifiers everywhere. Every artifact carries its alg, so verification dispatches on the recorded algorithm instead of assuming one (§15).
Domain-separated derivation. Where keys are derived, HKDF-SHA256 with purpose-specific labels keeps them cryptographically independent.
Federation payloads are signed, not encrypted. Every federation message carries an Ed25519 signature from the sending Server; there is no application-layer encryption and no key exchange for one, so transport privacy is TLS. What crosses the boundary is limited by schema (§8).
5. Audit vault integrity and offline verification
The audit vault is the core primitive: an append-only ledger of every accountability event. Each entry surfaces to customers as a Signed Statement:
| Tampering | Mechanism | Detection |
|---|---|---|
| Insertion | Hash chain breaks previous_hash link | CHAIN_LINK_BROKEN |
| Deletion | Sequential chain_position gap | CHAIN_POSITION_GAP |
| Modification | Recomputed hash mismatch | CHAIN_HASH_MISMATCH |
| Payload edit | Visible payload jsonb diverges from signed bytes | CHAIN_PAYLOAD_BINDING_MISMATCH |
| Forgery | Signature fails against the key the entry names | CHAIN_SIGNATURE_INVALID |
| Re-attribution | Row actor fields diverge from the signed actor claim | CHAIN_ACTOR_ATTRIBUTION_MISMATCH |
| Key substitution | Entry signed by a key no signed key statement links to the auditor’s pin | CHAIN_SIGNING_KEY_UNANCHORED |
Enforcement layers
Database: UPDATE and DELETE are revoked on the vault tables; partition-level TRUNCATE is blocked by trigger. A DDL event trigger (agledger_block_audit_drop) refuses an in-band DROP of the audit vault, its partitions, the admin-read tables, and the signing-key registry; creating it is the one privileged step in an install, because CREATE EVENT TRIGGER is superuser-only and the migration role needs a one-time superuser-equivalent grant (rds_superuser on Aurora). Startup and post-restore checks confirm the runtime role privileges and the trigger before the server accepts traffic. A privileged operator who edits the human-readable payload jsonb is caught at verification: the audit export reports chainIntegrityReason: 'payload_drift' and the offline verifier reports the same finding as CHAIN_PAYLOAD_BINDING_MISMATCH. The signed envelope, not the visible copy, is the source of truth.
Application: vault writes occur inside the same transaction as the state change - the entry exists if and only if the state change committed.
Cryptographic: the hash chain and signatures provide tamper evidence independent of database access controls.
Operational: signed checkpoints on a configurable cadence (6 hours by default). Optional external anchoring to S3-compatible storage with COMPLIANCE-mode object lock.
Offline verification
Verification means one thing in this document: checking the cryptography. Three properties are independently checkable: the signatures are genuine under keys that signed key statements link to a key you pinned, the hash chain recomputes end to end (a break is located at the exact position it occurs), and the visible payload has not drifted from the signed bytes. A pass does not prove the claim inside a record was true or the work behind it good - the principal renders that verdict at the Gate, and verification confirms the verdict is authentic and untampered like every other entry.
GET /v1/records/{id}/audit-export exports a record’s chain as a self-contained signed bundle for verification on a machine that never talks to AGLedger. The export carries the signing keys and the signed key statements that admit them: a genesis for the install’s first key, a succession signed by the old and new key at each rotation, a closure at each retirement. The one external input is a pin, the SHA-256 of a vault key’s SPKI (sha256:<hex>), which the installer prints and the operator hands the auditor out of band. The same keys are served unauthenticated at GET /v1/verification-keys and GET /.well-known/agledger-vault-keys.json: anchored keys only, retired ones included with their signed windows, each with its statements, plus anchoredFrom, the serving process’s own pin, to compare against yours. A key document is only as trustworthy as whatever served it, which is why the pin and not the document decides trust. The standalone verifier, the CLI, the SDKs, and the MCP server all check the same exported bytes; step-by-step commands are in the offline verification guide.
The verifier is deliberately small, so that trusting it is not the same as trusting the Server: @agledger/verify-core has a single runtime dependency, a CBOR codec. A pin goes in as --trust-anchor sha256:<hex>, and the verifier walks the key statements from it, so a chain re-signed wholesale under a key written into the database, or shipped inside the export, fails with CHAIN_SIGNING_KEY_UNANCHORED. Each run reports a verdict: trusted (clean, every signing key anchored to the pin), unanchored (clean, no pin given), or failed. A run without a pin passes flagged as not anchored and never as trusted. Where a key came from is not whether it is trusted: --keys supplies keys from elsewhere and --require-supplied-keys refuses the export’s own, but keys fetched from the Server come from the same database an attacker would write to, and only the pin anchors them. Exit codes separate verified (0, with the verdict saying whether it was anchored), verification failed (1), and could-not-verify (2, malformed or missing input including a mistyped pin), so an inconclusive run never reads as a pass.
No AGLedger code is required on the verification path. Every entry is a standard COSE_Sign1 envelope, so a stock COSE library can confirm a chain on its own; our verifier is a convenience, not a dependency. The chain also exports as DSSE envelopes wrapped in Sigstore Bundle format (v0.3, BYO-key), verifiable with cosign in private-infrastructure mode. Where the Transparency Service is enabled, an export can include SCITT Receipts - RFC 9162 Merkle inclusion proofs in COSE, opt-in via ?receipts=true - proving an entry was admitted to the transparency log at a known position, independent of the chain itself.
Because verification needs nothing but the bytes and the published keys, an auditor, a counterparty, a regulator, or a court can confirm a chain years later - with the Server shut down, the license lapsed, or the vendor gone. The proof outlives the vendor.
6. Key management and rotation
The vault signing key is held outside the database, and the chain’s trust starts there. It is supplied as VAULT_SIGNING_KEY - required in production and customer-held: AGLedger LLC never possesses it. The customer protects the private key with their own secrets manager (§13). The install script generates the keypair locally, on your machine, and prints its pin. At boot the key is read from an environment variable or a file, or fetched from AWS SSM Parameter Store (SecureString) or HashiCorp Vault KV v2; it can instead stay in AWS KMS (VAULT_SIGNING_KEY_KMS_ARN), where the private half never leaves KMS.
The key registry holds public keys only, and is append-only in the same way the chain is. DELETE and TRUNCATE are refused by trigger, and the single UPDATE the trigger permits is the active-to-retired transition: key material, algorithm, and activation instant are immutable once written. A registry row alone is trusted for nothing. A key counts only when a signed key statement (genesis, succession, or closure, kept in an append-only table of its own) links it to a key a process holds outside the database, so a key row written with database access alone is absent from the published keys and every entry it signs breaks as unanchored. Retired keys stay published with the activation and retirement instants their statements sign, and the offline verifier checks each entry’s write time against the validity window of the key that signed it.
Zero-downtime rotation
Rotation needs no downtime and no re-signing, and it is two separate steps. Staging is a restart: a process started on the new VAULT_SIGNING_KEY with VAULT_SIGNING_KEY_PREVIOUS set to the key in use registers the new key and writes a succession statement signed by both keys, which is what carries an auditor’s pin forward. A process on a new key that nothing links to the registry’s history registers nothing and signs nothing. Staging retires nothing, so both keys are active while processes roll, and each keeps signing inside its own published window.
Retirement is an explicit call, POST /v1/admin/vault/signing-keys/{keyId}/retire, sent to a process holding a different anchored key. It writes a closure statement over the retirement instant; after it, an entry under the retired key is a chain break, and entries written before it stay valid. POST /v1/admin/vault/signing-keys/rotate performs the staging on demand and answers already_active once the restart has done it.
The procedure is in the day-2 operations runbook, and the compromise order in the signing-key compromise runbook.
Key loss does not invalidate history. Verification uses the public keys and the key statements that sign them, not the private key in the environment. Losing the private key stops new signing; it does not retroactively break the existing chain. A replacement that nothing links to that history registers only when the operator pins the history it vouches for in VAULT_TRUST_ANCHORS; it starts under a fresh genesis, and auditors take its pin. The registry supports unlimited rotations and records an algorithm per key, so a chain spanning two algorithms verifies entry by entry against the key that signed it (§15).
7. Authentication and access control
Two authentication paths, same protocol on the wire. Enterprise installs lead with OIDC-bound ephemeral signing certificates: agents exchange a JWT from the customer’s own identity provider (Auth0, Okta, Azure AD, Keycloak, GCP WIF, K8s service-account tokens) for a short-lived AGLedger cert via POST /v1/auth/oidc/cert - 10 minutes by default, configurable per issuer up to one hour - and present it as the Bearer credential. No agent holds a long-lived key; blast radius on credential compromise is minutes.
Long-lived API keys remain fully supported for development, the quickstart, and single-operator installs. Keys are never stored in plaintext - the server computes HMAC-SHA256 and looks up the hash. Both credential types produce the same chain envelope, and the actor identity each carries is named inside the signed payload (§1). Only asymmetric algorithms are accepted: HS* and none are excluded, with per-issuer overrides available on the trusted issuer. The HMAC secret behind key storage rotates without downtime through a previous-secret window. The provenance of an OIDC validation (the key thumbprint and the instant it was validated) is recorded into the signed chain alongside the record it authorized. Trust anchors are configured per-org via POST /v1/admin/trusted-issuers - one row per IdP per purpose with an applies_to discriminator (agent / principal / admin / any); JWKS endpoints are auto-discovered via OIDC well-known. See the Authentication guide.
| Role | Capabilities | Typical user |
|---|---|---|
| Platform | System administration, enterprise provisioning, vault management (cross-org by design) | AGLedger operator |
| Admin | Configuration, oversight, compliance exports, key management | Org administrator |
| Agent | Record lifecycle operations scoped to authorized actions | AI agent, RPA bot, service |
Each API key carries a scope list, and anti-escalation prevents creating keys with broader scopes than the creating key. Roles are enforced by middleware with scope checks layered on top, so a scope cannot stand in for a role. Agent and admin access is org-scoped - the platform role is the one deliberate cross-org identity, held by the operator. Additional controls: per-key IP allowlisting, key expiration, and the optional per-request agent signature (§1).
Admin actions are themselves evidence. Privileged operations - key creation and revocation, configuration changes, queue interventions - are written to the chain as signed entries, so the audit trail covers its own administration.
8. Federation and privacy boundary
Across organizations, federation is peer-to-peer signed-message transport over TLS. Each Server signs every request with its own per-instance Ed25519 key over a domain-separated sign input addressed to the receiving Server (its instance id, then method, path, RFC 8785-canonical body hash, timestamp, nonce), so a message signed for one peer does not verify at another; there is no shared key and no central coordinator.
Crosses the boundary
Server identity + public keys
Agent IDs
Record ID, contract type
State transitions (state, timestamp, signature)
Gate verdict (accept/reject)
Settlement Signal payload (SETTLE/HOLD/RELEASE)
Never crosses
Record criteria (actual acceptance terms)
Completion evidence (work product)
Audit vault entries
Prompts, context, or business logic
API keys or auth credentials
Webhook URLs or delivery payloads
Each Server remains sovereign: it records the signed bytes a peer sent, verifies them against the peer’s published key, and never holds the peer’s underlying business data. Transport mechanics live on the Federation page.
9. Application security
Schema-first validation. Every endpoint declares request and response JSON Schemas enforced by the framework. Unknown fields rejected, no implicit type coercion. 1 MiB global request limit, 65 KiB record limit, 20-level JSON depth cap.
SQL injection prevention. All queries use parameterized SQL. Sort and filter columns are validated against explicit whitelists.
Webhook SSRF protection. Layered validation: private IP ranges, loopback, cloud metadata endpoints, alternative IP encodings, DNS re-resolution at connect time (TOCTOU), internal hostname suffixes, embedded credentials, HTTPS-only.
Customer-supplied patterns are budgeted. Gate-rule regexes and JSON Schema patterns run under a hard 250 ms wall-clock budget in an isolated node:vm context. Pattern and subject are passed as context values and never interpolated into source, and a budget overrun is its own outcome, never folded into a non-match.
Encrypted evidence binds to its record. The server validates envelope shape and never decrypts. Envelopes bind to their record id, so replaying a valid envelope against a different record is rejected.
Expression engine sandboxing. jsep AST parser (not eval). 50 AST nodes, depth 10, 1,000 operations max. No access to global scope, prototype chain, or Node.js APIs.
Rate limiting. Every authenticated key shares one per-key budget of 1,000 requests/min by default; platform keys, as root credentials, are effectively exempt (a 100,000/min ceiling applies). Unauthenticated traffic is IP-keyed with its own budget, and hot write routes carry tighter caps beneath the per-key budget (POST /v1/records is 200/min). State is in-memory per instance by default, with a PostgreSQL store option for multi-replica consistency. Errors return as RFC 9457 problem details.
10. Infrastructure hardening
Container
Red Hat UBI 10 minimal base (RPM-managed Node and OpenSSL, updated every build)
Node permission model grants filesystem read and nothing else (§11)
Non-root user (UID 65532)
Read-only filesystem + tmpfs for /tmp
512 MiB memory, 1.0 CPU limits
Liveness + readiness health probes
File-based secrets injection
Database
Separated identities: a least-privilege runtime role, a read-only monitor role, and a distinct owner connection used only for migrations
TLS required in production (sslmode=verify-full recommended)
Advisory-locked, checksummed migrations
Zero PostgreSQL extensions required, so managed Postgres needs no extension-allowlist negotiation (validated on Aurora and stock PostgreSQL)
Direct connections: transaction-mode poolers (PgBouncer, RDS Proxy) are incompatible, because the job queue uses LISTEN/NOTIFY
AWS RDS CA bundle shipped in the image
Node.js 24 LTS, pinned dependencies
11. Supply chain and release integrity
Every release is built and signed in CI; nothing is published by hand. Each artifact traces back to the commit and the workflow that produced it, checkable with stock tooling and no AGLedger account.
| Artifact | What ships with it |
|---|---|
| Container image | SLSA Build Level 3 provenance, keyless cosign signature, CycloneDX SBOM, OpenVEX, and a ClamAV malware-scan attestation with a staleness positive-control |
| Helm chart | Keyless cosign signature |
| npm packages | Publish provenance via Trusted Publishing, stated as L2-equivalent: OIDC-bound and non-forgeable, without the isolated-builder guarantee that earns L3. SDK, CLI, MCP server, and the verifiers |
| Python SDK | PyPI Trusted Publishing with PEP 740 signed attestations |
| GitHub release | SBOM, VEX, and the signed conformance corpus |
Signing is keyless. GitHub OIDC to Fulcio to the public Rekor transparency log, so the signing identity is the workflow that built the artifact rather than a key a person holds. Image provenance is generated by the isolated slsa-github-generator reusable workflow, which signs in a build the release job itself cannot reach.
Publication is gated. VEX-aware Trivy scanning at CRITICAL and HIGH on both architectures, boot gates on both architectures, and a FIPS-mode boot gate all pass before an image publishes.
CI actions are SHA-pinned, with one deliberate exception: the SLSA builder workflow is tag-pinned, because its verifier resolves the trusted builder by tag.
Verification is yours to run. The deployment repository’s SECURITY.md carries the exact commands per artifact: cosign for image and chart signatures, the attestation checks worth asserting, and slsa-verifier for provenance. The installers verify signatures when cosign is present; set AGLEDGER_REQUIRE_VERIFY=true and a run that cannot verify refuses to install. Marketplace and ECR mirrors are checked by digest equality against the authoritative image.
Runtime image. Red Hat UBI 10 minimal with Node 24, built from a digest-pinned build stage and running as a non-root user. Node’s permission model grants the application filesystem read and nothing else: writes, child processes, native addons, the inspector, WASI, and worker threads are all denied. Dependency updates run continuously (Dependabot) and Semgrep SAST runs before each release.
12. Threat model
| Threat | Controls |
|---|---|
| Audit trail tampering | Hash chain + signatures + DB enforcement (UPDATE/DELETE revoked, TRUNCATE blocked) + external checkpoints; payload edits surface as payload_drift |
| Attribution forgery | Principal and acting credential are inside the signed payload; re-pointing an entry invalidates the signature |
| Cross-tenant access | Org-scoped agent and admin access; scoped API keys; principal enforcement |
| API key compromise | HMAC-hashed storage; IP allowlisting; expiration; scopes limit blast radius; ephemeral certs cap exposure at minutes |
| Webhook SSRF | Layered validation including DNS re-resolution; HTTPS-only |
| Federation MITM | TLS + per-request Ed25519 signing with per-instance keys |
| Signing key compromise | Forced retirement stops chain appends under the key the instant it commits and revokes the certificates it minted; VAULT_DISTRUSTED_KEYS makes what it signs from the leak count for nothing; external anchors bound what it signed before |
| Rogue signing key (database write access) | A key is trusted only through signed key statements linking it to a key held outside the database; an auditor’s pin decides trust offline |
| Denial of service | Tiered rate limiting; size caps; depth limits; handler timeouts |
Explicitly out of scope
Compromised principals. If the entity creating records is malicious, AGLedger faithfully records what they reported. We attest accountability, not truthfulness - the chain proves what was said and signed, not that it was correct.
Content-level threats. AGLedger validates structure, not business content; zero content inspection is the boundary the product is designed around.
Infrastructure compromise. OS, network, and physical security are the customer’s responsibility.
13. Privacy, data protection, and shared responsibility
AGLedger is self-hosted software: in the typical deployment, AGLedger LLC is neither a data processor nor a data controller. Residency follows the customer’s database placement, license validation is an offline Ed25519 check, and no AGLedger LLC system sits in the data path. Zero sub-processors for Customer Personal Data in the standard deployment; no international transfers when sharing is off; encrypted mode enables cryptographic erasure (§3).
AGLedger provides
Application security (validation, SSRF, SQLi prevention)
Cryptographic integrity (hash chain, signatures, agility)
Access control (RBAC, scoping, rate limiting)
Secret handling (HMAC, AES-256-GCM, log redaction)
Container hardening (non-root, read-only filesystem)
Database role separation
Customer provides
Infrastructure security (network, OS, physical)
Database encryption at rest
TLS certificate management
Vault signing key protection (secrets manager)
Backup and disaster recovery
Monitoring, alerting, and SIEM integration
14. Compliance mapping
AGLedger captures signed records, delegation chains, and cross-org evidence transport regardless of regulation; downstream, these map to the obligations below. Detailed crosswalks live on the dedicated pages.
EU AI Act: Article 12 - automatic event logging. Article 14 is a boundary, not a mapping: AGLedger records that a halt was requested, and the interrupt itself lives in the systems that run the agent.
NIST AI RMF: GOVERN, MAP, MEASURE, MANAGE
ISO 42001: Capability crosswalk
ISO 27001:2022: Annex A theme A.5 organizational (supplier and ICT supply-chain controls, evidence collection, protection of records) and theme A.8 technological (access control, cryptography, logging, secure development). Themes A.6 people and A.7 physical sit with whoever operates the deployment.
NIST 800-53: AC, AU, IA, SC, SI families
Cyber Resilience Act: Readiness assessment, maintained alongside the coordinated vulnerability disclosure policy (§17)
The EU AI Act mapping reaches into the engine: it ships the Act’s risk-tier taxonomy (Article 5, Annex III, Article 50) as first-class record vocabulary, so the tier a system claims is recorded inside the signed payload rather than tracked beside it.
SOC 2: not a certification - AGLedger is self-hosted software, not a service organization, so your deployment runs under your existing certifications.
15. Algorithm agility and post-quantum readiness
All algorithms are current NIST-approved. NIST finalized post-quantum standards in August 2024 (ML-KEM / FIPS 203, ML-DSA / FIPS 204, SLH-DSA / FIPS 205).
Per-key algorithm registry. The signing-key registry derives the algorithm from the key material at registration, and verification dispatches on it rather than assuming one. Ed25519 is the default; ECDSA P-256 (ES256) is the second shipped algorithm, enabled by explicit opt-in for hosts whose crypto provider excludes EdDSA (see FIPS 140 hosts). Adding a third is a registry entry and a verifier release, not a format change.
No re-signing required. New entries use the new algorithm; old entries remain valid against the retired key that signed them. A chain spanning two algorithms is continuous.
Hybrid (classical + PQC) signatures are expected industry-wide in 2027–2028; the registry design means adopting them requires no customer action today.
16. Continuity and releases
As self-hosted software, RPO and RTO depend on the customer’s infrastructure and backup strategy. AGLedger provides the tooling: backup.sh, restore.sh, support-bundle.sh, and health probes for orchestrator-level recovery. The chain is self-verifying: after restoring from any backup, run the vault integrity check to confirm continuity.
Failover behavior. On a PostgreSQL failover the queue listeners reconnect with backoff and export a failure counter as a metric; while disconnected, caches degrade to TTL expiry rather than going stale silently. In-flight queue work is recovered by per-queue active-job timeouts, after which the job is re-fired, and the migration runner retries the error classes a failover produces.
Platform. PostgreSQL 17 or later, with 18 recommended and validated including Aurora 18. The bundled postgres:18-alpine container is production-capable: running production on it is licensed under Developer Edition and supported by the software, with every feature available. Connecting to an external or managed database instead, such as Aurora, RDS, or Cloud SQL, is what triggers an Enterprise license.
Upgrades. Releases use semantic versioning and ship at most one migration each. Shipped migrations are immutable and checksum-verified, and the runner refuses to start if one has been altered. The upgrade script takes a backup first and writes a rollback marker; rollback is a documented restore. Within a major version the schema is safe in both directions across the upgrade window. A new major is not: 2.0 does not upgrade a 1.x database. The migration and the upgrade script refuse one before changing anything, as does a 2.0 Helm chart over a release a 1.x chart installed on the bundled PostgreSQL, so 2.0 installs against a new, empty database and the 1.x database stays with the 1.x install that wrote it. Release signing and provenance are covered in §11.
Security fixes ship as new versions with CVE-referenced advisories.
17. Incident response and coordinated vulnerability disclosure
Detected tampering
If vault integrity verification detects tampering, the failure is logged with full context (chain position, expected vs. actual hash, signing key ID). Failed entries are flagged but never modified - the evidence of tampering is itself part of the audit record.
AGLedger Coordinated Vulnerability Disclosure Policy
Version: 1.6 Effective Date: June 4, 2026 Last Updated: September 15, 2026 Contact: security@agledger.ai
This is the canonical coordinated vulnerability disclosure ("CVD") policy for the AGLedger software product (the self-hosted Licensed Software, SDKs, CLI, MCP server, container images, Helm charts, and release artifacts). It is the policy referenced by the
SECURITY.mdandsecurity.txtfiles distributed with the software and published atagledger.ai/security, and by Software License Agreement § 6.6.AGLedger's public online resources (the website, the documentation, and the registries from which the software is distributed) are governed by the Acceptable Use Policy, which sets out in § 6 how to report a vulnerability in those resources and provides that good-faith research conducted in compliance with that section does not breach the AUP. The safe harbor, good-faith conditions, disclosure timeline, and recognition terms in this policy apply to research on the software product.
1. Scope
In scope:
- The AGLedger Licensed Software (server) and its container images, Helm charts, air-gap bundles, and GitHub Release artifacts.
- The public AGLedger packages published on npm and PyPI.
- The cryptographic chain, signing/verification, federation, gate, and webhook (Notify) surfaces of the product.
- The integrity of our software supply chain (image signatures, build provenance, SBOM).
Out of scope:
- Findings that require a compromised host, a malicious privileged database administrator, or physical access already assumed in our threat model.
- Self-inflicted misconfiguration of a customer's own deployment (e.g., exposing the database, disabling TLS).
- Vulnerabilities in third-party dependencies that are already publicly disclosed and for which we have shipped, or are within the Support Terms window of shipping, a fix.
- Volumetric denial-of-service, social engineering of AGLedger staff, and findings against software versions outside the Supported Version window stated in the Support Terms. These may be reported but are triaged best-effort.
2. How to report
Email security@agledger.ai, or report privately through GitHub private vulnerability reporting on any public agledger-ai repository. If your report contains sensitive detail, say so in your first email without including the detail, and we will agree an encrypted channel with you before you send it. We do not currently publish a PGP key.
Please include:
- The affected component and version (and image digest, if applicable).
- A description of the vulnerability and its impact.
- Reproduction steps or proof-of-concept (minimal; see §3).
- Any suggested remediation.
- Whether you intend to disclose publicly, and on what timeline.
We aim to acknowledge receipt promptly and to provide an initial assessment as soon as practicable.
3. Safe harbor for good-faith research
If you make a good-faith effort to comply with this policy during your research, AGLedger will:
- consider your research authorized under the Computer Fraud and Abuse Act and analogous laws, and will not pursue or support legal action against you for it;
- work with you to understand and resolve the issue promptly; and
- recognize your contribution (with your permission) once the issue is resolved.
Good-faith research means you:
(a) report promptly and do not exploit the vulnerability beyond the minimum proof-of-concept necessary to demonstrate it; (b) do not access, modify, exfiltrate, or destroy data that is not your own, beyond minimal proof-of-concept evidence; (c) do not degrade, disrupt, or impair the availability of any system or any other party's deployment; (d) test only against your own deployment or systems you are authorized to test, and never against another customer's deployment; (e) give us a reasonable opportunity to remediate before any public disclosure (see §5); and (f) comply with all applicable law.
This safe harbor is a statement of how AGLedger will treat good-faith research; it does not authorize action against third parties and does not waive any third party's rights.
4. Our handling process
- Triage: confirm, reproduce, and assign a severity (CVSS-aligned).
- Remediate: develop and test a Security Fix. Remediation targets for licensed customers are in the Support Terms; they are targets, not guarantees, and are made to customers, not to reporters.
- Distribute: release the fix as signed artifacts through the public distribution channels, without authentication or entitlement checks. The contractual commitment to provide Security Fixes is made to Enterprise Edition Licensees under License Agreement §§ 6.2 and 6.4.
- Notify: inform affected customers and, where the law requires (including the EU Cyber Resilience Act reporting cadence for actively exploited vulnerabilities and severe incidents), notify the competent authorities (the CSIRT-coordinator and ENISA) within the required 24-hour / 72-hour / 14-day windows.
- Disclose: publish a security advisory and credit the reporter (with permission).
5. Coordinated disclosure timeline
We follow a 90-day coordinated disclosure window by default: we aim to release a fix and advisory within 90 days of a validated report, and we ask that you not disclose publicly before the earlier of (a) a fix being available or (b) 90 days, whichever comes first. For vulnerabilities under active exploitation, we will move faster and coordinate an accelerated timeline with you. We are happy to coordinate CVE assignment and joint disclosure.
6. Recognition
With your permission, we will acknowledge your contribution in the security advisory. AGLedger does not currently operate a paid bug-bounty program; this is a coordinated-disclosure (not a bounty) policy.
7. Changes
We may update this policy by posting a revised version with an updated effective date at agledger.ai/security. Material changes will be noted in the change log below.
| Date | Version | Change |
|---|---|---|
| 2026-06-04 | 1.0 | Initial coordinated vulnerability disclosure policy for the software product. Supports EU Cyber Resilience Act Annex I Part II (CVD) and Article 14 reporting; referenced by License Agreement § 6.6. |
| 2026-06-09 | 1.1 | Softened the §2 fixed "2 business days / 5 business days" researcher response clocks → "promptly / as soon as practicable" (fixed response times to anonymous external researchers are not guaranteed; a missed clock would be a published broken promise). Safe harbor, scope, and the legally-required CRA Art. 14 authority-reporting windows (24h/72h/14d) unchanged. |
| 2026-09-10 | 1.2 | Removed the pointer to a PGP key at agledger.ai/security: no key is published anywhere, and security.txt carries no Encryption: field (agledger-legal#25). Reporters now flag sensitive detail in their first email and an encrypted channel is agreed before it is sent, matching SECURITY.md in the code repository. Added the @agledger/verify and @agledger/verify-core packages to §1 scope. |
| 2026-09-15 | 1.6 | Facts whose home is elsewhere removed: the package list (the packages are named where they are published), the remediation numbers and the N and N-1 window (Support Terms), a threat-model explanation with an internal field name, a GitHub button label, and a restatement of License Agreement §§ 6.2 and 6.4 beside their citation. |
| 2026-09-15 | 1.5 | Section 6 no longer promises a security acknowledgments page; none exists, and credit is given in the advisory. |
| 2026-09-15 | 1.4 | Section 4 step 3 no longer states that a fix is available to every user at no charge. Nothing requires that statement to be published, and in a public policy it reads as a representation to everyone, including users outside the EU and outside any support period, where the underlying duty binds only as a manufacturer obligation. The operational fact remains: releases are public, unauthenticated and not entitlement-gated. |
| 2026-09-15 | 1.3 | §4 step 3 corrected: Security Fixes are released publicly as signed artifacts at no charge to anyone, and the contractual commitment is to Enterprise Edition Licensees under License Agreement § 6.2 (the step previously said all perpetual licensees, which § 6.2 does not say). The introductory note no longer says the AUP covers public APIs or that the two documents share safe-harbor terms: the AUP governs the online resources and this policy's safe harbor applies to the software product. §2 adds GitHub private vulnerability reporting on the public repositories as a reporting channel. §4 step 2 calls the Support Terms remediation times targets. Em dashes rewritten. |
Related
AGLedger is a product of AGLedger LLC. This document describes the security architecture of AGLedger software. It is not a guarantee of security and should be evaluated alongside your organization’s specific risk assessment. Contact: security@agledger.ai