v9.2.0
[9.2.0] - 2026-06-23 (read-only MCP posture, tamper-evident audit signing, turnkey SIEM export, compliance-category enforcement)
Additive minor. v9.2.0 hardens governance and audit assurance: a one-config read-only MCP posture, a connector-level database backstop, per-record cryptographic signing of the decision chain (now capturing live traffic) with read-only verification endpoints, a turnkey central-store / SIEM audit exporter, and automatic cross-border transfer_basis stamping on the canonical audit row. Two behavior changes to note (both in Fixed): the seeded RBI / SEBI / MAS-FEAT / EU-AI-Act compliance policies now actually fire on /decide and the gateway (they were silently excluded by a category-spelling mismatch), and a tool/connector response carrying an indirect prompt-injection pattern is now sanitized by default on the response plane (the statement carrying the injection is removed). Everything else is additive and off by default.
Added
- Read-only MCP enforcement posture: one config flag blocks every write-path MCP call. (Community) Setting
MCP_READ_ONLY=true(env, default off) blocks write-intent MCP calls across all connector-execution planes: thecheck_policyadvisory tool, thecheck-inputPEP gate,tools/execute,resources/query, and the gateway pre-check. A method-name verb classifier (classifyMCPCall) handles tool-call intent, and a SQL statement classifier (statementIsWritePath) handles the raw-statement query plane: it masks string literals and comments, rejects stacked statements and dollar-quoted bodies, and catchesSELECT ... INTOandEXPLAIN ANALYZE <dml>, failing closed on anything it cannot prove read-only. - Connector-level read-only database transaction backstop. (Community) A new per-call
base.Query.ReadOnlyfield lets a connector run a read inside a database-enforced read-only transaction. The PostgreSQL connector honors it by openingBEGIN READ ONLY, so the database itself rejects (SQLSTATE25006) any write that a statement classifier might miss; it is the durable backstop under the read-only MCP posture above. Byte-identical behavior when the flag is off (no extra round-trip, no transaction). MySQL and Snowflake can adopt the same flag in a follow-up; Cassandra has no read-only-transaction primitive and stays verb-path only. - Tamper-evident audit signing + read-only verification endpoints. (Community) Each decision-chain record is now signed with a per-record Ed25519 signature and linked by a
prev_hashhash chain with a monotonicchain_seq, appended race-free under an advisory lock (migrationcore/125). A single record can be verified standalone offline: the response republishes the digest pre-image, record digest, prev_hash, and chain hash so an auditor can recompute and re-verify trusting neither the endpoint nor its digest. Three new read-only endpoints (documented indocs/api/agent-api.yaml):GET /api/v1/audit/chains/{id}/verify(linkage + every signature, with anauthorship_provenflag for the strong non-repudiation claim),GET /api/v1/audit/records/{id}/verify(one record standalone), andGET /api/v1/audit/signing-key(publish the current public key). Signing key and retired-key rotation are configured viaAXONFLOW_AUDIT_SIGNING_KEY(+ optionalAXONFLOW_AUDIT_SIGNING_KEY_ID) andAXONFLOW_AUDIT_VERIFY_KEYS; when no key is set, records are hash-chained but reported honestly as unsigned. - Decision-chain signing now captures live traffic. (Community) The production decision-chain tracker is now a writing instance: real
/decide, OpenAI-compatible, gateway pre-check, and early-deny decisions are enqueued and signed + hash-chained off the request hot path by async workers (the same instance still backs the verify endpoints, so a record signed here verifies against the keys loaded here). Previously the tracker was instantiated verify-only, so no production decision was ever signed. A/decideredaction signs asapproved(an obligation on anallowverdict per the decide → fulfill contract); only the gateway plane records aredacted→ modified verdict. - Turnkey central-store / SIEM audit exporter. (Community) A new exporter ships each decision to an external store off the decision hot path (non-blocking queue with timeout and circuit breaker), so a denied or redacted decision can land in a customer's SIEM or object store without touching request latency. Enabled via
AXONFLOW_AUDIT_SINK=s3(default empty = disabled; decision path byte-for-byte unchanged when off), withAXONFLOW_AUDIT_S3_BUCKET/AXONFLOW_AUDIT_S3_PREFIX/AXONFLOW_AUDIT_S3_REGION/AXONFLOW_AUDIT_S3_ENDPOINT/AXONFLOW_AUDIT_S3_PATH_STYLE. Shipped, dropped, failed, and skipped records are metered onaxonflow_central_store_records_total. - Automatic cross-border
transfer_basisstamping on the canonical audit row. (Enterprise) The orchestrator now auto-stamps the UU PDP Pasal 56 cross-border transfer basis (and derived data-residency) onto the canonicalaudit_logsdecision row (columns added in migrationcore/126), resolved per-request, then per-org viaAXONFLOW_ORG_TRANSFER_BASIS, then a globalAXONFLOW_DEFAULT_TRANSFER_BASIS, so Pasal 56(b) attestation is turnkey rather than hand-stamped.
Fixed
-
Indirect prompt-injection is now governed on the response / tool-output plane. (Community, behavior change) The four indirect prompt-injection patterns (instruction-override, role-reassignment, system-prompt exfiltration, and template/bracket markers; migration 116) were seeded
phase='request', soevaluateOutputPoliciesnever evaluated them: a malicious instruction returned in a connector free-text field (for example a back-office CRM note) re-entered the model's context ungoverned, even though the response plane already covered SQL-injection, PII, and sensitive-data. Migrationcore/128flips those foursys_dangerous_injection_*policies tophase='both'and sets their previously-NULLaction_response(the request-plane action staysblock), and a newEnabledSecurityDangerousCategorieshelper folds the security-dangerous category into the response evaluation set (the phase flip alone is inert, becausefilterByCategorieswould otherwise drop the category). Only the injection patterns are promoted; the dangerous-command patterns (migration 059: reverse shell,/etc/passwd,eval(), credential-file access) stay request-only by design, since matching a command description against connector output would hard-block benign data. The default response-plane action is redact (sanitize): the sentence/line/clause containing the injection is removed (JSON-aware, preserving valid structure and sibling fields), so no injectable instruction reaches the model, while surrounding legitimate data passes through, overridable per-org to warn or block via the detection-posture override; the input plane still blocks. The outcome is recorded as a canonicalplane=mcpresponse audit row. Behavior change: a tool/connector response carrying one of these injection patterns now has the injection-bearing statement removed by default. -
Seeded compliance policies now enforce on
/decideand the gateway. (Community, behavior change) The seeded RBI, SEBI, MAS-FEAT, and EU-AI-Act compliance policies stored drifted category spellings (rbi_compliance,sebi_compliance,mas_feat_compliance,eu_ai_act_compliance) that did not match the canonical category constants (compliance-rbi,compliance-sebi,compliance-masfeat,compliance-euaiact). Because the decision filter matches category exactly, those rows were silently excluded and the policies never fired. The industry seeds are canonicalized at source for fresh deployments, and a forward-fix migration (core/127, pluscore/014for EU) realigns existing deployments. Behavior change: deployments seeded with these compliance packs will start enforcing them on/decideand the gateway. -
Matched policies surface the policy name, not an opaque UUID. (Community) The orchestrator's active-policy cache is keyed by
policy_idto avoid cross-tenant name collisions, butListActivePoliciescopied that key into the policy'sName, somatched_policiesreported a UUID. It now reads the stored policy name. -
The OJK cross-border export reads the canonical audit row. (Enterprise) The Indonesian OJK cross-border export is repointed to read the canonical
audit_logsdecision row carrying the stampedtransfer_basis, consolidating it onto the same source as the rest of the compliance exporters.
Security
golang.org/x/netandgolang.org/x/cryptobumped to clear Trivy HIGH advisories (x/net0.52 → 0.56,x/crypto0.49 → 0.53) across the flagged modules, restoring a green repo-wide vulnerability scan. Dependency-only; no code or behavior change.
Full release notes: https://docs.getaxonflow.com/docs/releases/v9-2-0
Migrations are additive and apply automatically on startup.