Skip to main content

AxonFlow v9.4.0 Release Notes

v9.4.0 is a minor release focused on detection accuracy and governance integrity. The headline is capability-scoped policy evaluation: detectors that model executable input (SQL injection, dangerous commands, dynamic code execution, config-file writes, and the other execution-class families) no longer evaluate the tools AxonFlow knows can only write documents, which removes a whole class of false-positive blocks on documentation work without weakening enforcement anywhere a payload could actually execute. Alongside it, the operation detectors are hardened to require operation syntax rather than matching plain English or Markdown, an override justification is no longer scanned as governed content, response-plane redaction now fails closed when policies cannot be loaded, decision-chain records persist again, and the customer portal gets a correctness sweep. Three idempotent database migrations apply automatically on startup, so it is a drop-in upgrade from v9.3.x.

Added

Capability-scoped policy evaluation

Execution-class detector families model one specific threat: "this input is about to be executed by the governed tool." That model is right for a shell tool or a database connector, and wrong for a tool whose only capability is writing prose into a SaaS document, such as a Jira issue or a Confluence page. Before v9.4.0, those detectors evaluated every governed request regardless, so ordinary documentation text (a Markdown table divider, the English word "revoke", a config filename mentioned in a runbook) could trip a SQL-injection or dangerous-operation policy, sometimes at a critical, non-overridable severity.

v9.4.0 scopes execution-class detectors to the tools whose capability is actually present. When a governed tool is positively classified as a text-document tool, the execution-class families skip it: SQL injection, dangerous shell commands (including reverse shells), credential-file access, internal-network and cloud-metadata fetches, path traversal, package installation, dynamic code execution, and configuration-file writes. Every other tool, including anything unclassified, keeps full evaluation. The design is fail-closed throughout:

  • Content detection stays universal. PII in every jurisdiction, secrets and sensitive data, prompt-injection guards, and the compliance families evaluate every tool, including text-document tools. A national ID written into a Jira ticket is still a leak, and an injection string written into a document is still stored prompt injection.
  • Unknown means full evaluation. A tool that is not positively classified gets every enabled detector, and a policy is skipped only when it is positively classified as execution-class. New or team-authored policies evaluate everywhere until they are classified.
  • Classification is never caller-asserted. It happens server-side against a built-in registry of known text-document tools; there is no request field through which a client can claim "I am text-only." Tools that AxonFlow itself executes against managed connectors are never scoped at all.

The same payload that passes through a document tool is still evaluated, and blocked where the policy says block, when it is sent to any tool that could execute it. Scoping is on by default in both editions. Setting AXONFLOW_CAPABILITY_SCOPING_DISABLED=true restores the previous behavior (it can only ever widen evaluation, never narrow it), and Enterprise deployments can extend the registry of text-document tools with AXONFLOW_TEXT_DOCUMENT_TOOLS. The new How Detection Works page explains the detector tiers, the capability classes, and how to read a scoped decision.

Who is affected: teams governing the Jira and Confluence document tools, which the built-in classification registry covers out of the box, and who previously saw execution-class policies block legitimate prose. Other document tools are treated as unknown (full evaluation) until an Enterprise deployment adds them to the registry. Deployments where every governed tool executes commands, queries, or file writes see no behavior change.

Synthetic client identities are labeled in the audit portal (Enterprise)

When a governed request arrives without a per-developer identity (for example from a client older than Claude Code plugin v1.8.0), the platform attributes it to a client-scoped synthetic identity rather than leaving the field blank. The portal's audit views previously rendered those synthetics the same way as a real developer email, which made them easy to read as a bug. The Log Explorer now renders synthetic identities distinctly, with a badge and an explanation, keeps genuine emails unchanged, and shows a note stating the minimum client versions and configuration (AXONFLOW_USER_EMAIL) needed for per-developer attribution, with the honest caveat that some enforcement planes do not record the supplied email yet. See Audit Logging for how identity lands on the record.

Fixed

Operation detectors no longer match ordinary documentation text

Independently of capability scoping, the detectors that model risky operations now require the syntax of the operation instead of matching prose. The pattern-based changes ship as migration core/135, which only updates unmodified seeded patterns, so deployments that customized these pattern rows keep their customizations; the IP change is in the detector code itself and applies everywhere:

  • The SQL authentication-bypass detector no longer matches a Markdown table divider next to ordinary prose; classic bypass payloads such as ' OR 1=1 -- still match.
  • The SQL REVOKE detector no longer matches the English word "revoke" in a sentence, and the sibling loose-verb SQL detectors (GRANT, DROP TABLE, DROP DATABASE, TRUNCATE, ALTER TABLE, CREATE USER, and DELETE without a WHERE clause) get the same treatment: prose such as "grant viewer or editor access" no longer matches, while the corresponding SQL statements still do.
  • The dynamic code execution detector no longer matches eval as a substring of an identifier (an organization id or a word like retrieval); a code-evaluation call such as eval(...) still matches.
  • The agent config-file detector no longer matches a config filename such as .env merely being mentioned in text; commands and calls that write or read such a file still match.
  • The IP address detector no longer treats never-routable and special-purpose ranges (0.0.0.0/0, loopback, link-local, carrier-grade NAT, multicast, the reserved test blocks) as personal data; private-network and routable public addresses stay detected.

Every change was verified in both directions: the documentation text that used to false-positive now passes, and a true-attack corpus for each detector still matches, with a small number of deliberate narrowings where a bare fragment of an operation is genuinely indistinguishable from ordinary prose. Both directions are now locked in as a regression gate: a labeled per-category corpus of attack and benign cases scores recall on attacks and the false-positive rate on benign input in continuous integration, and a change that weakens either fails the build. Who is affected: everyone, in both editions; these detectors become more precise.

Detection also gets one addition in the same family: the classic comment-out SQL authentication bypass (a string terminator followed by a SQL line comment, as in admin' --) previously passed through undetected, because the existing comment detectors required a SQL keyword after the comment and this payload carries none. A new seeded policy (migration core/139) detects it, anchored so that documentation quoting the vulnerable clause does not match (prose carries text after the comment; the real payload ends at it). It ships with the same posture as the rest of its policy family, so your configured SQL-injection category action drives enforcement, and capability scoping applies to it like any other SQL-injection policy.

An override justification is no longer blocked by the policy it asks to override

Session overrides require a written justification, and the override request itself travels through governance like any other tool call. That created a loop: explaining why you need to document .env files meant writing .env into the justification, which the config-file policy then blocked. v9.4.0 exempts only the designated free-text justification field from content evaluation on the cooperative plugin-facing check endpoints. The override's scope fields (which policy, which tool, for how long) are still fully evaluated, the exemption applies only to requests with the genuine override shape, malformed or ambiguous requests are evaluated in full, and which policies can be overridden does not change: critical policies remain non-overridable. See Session Overrides.

Response-plane redaction fails closed when policies cannot be loaded

The policy engine previously returned the same result for "scanned and found nothing" and "could not load policies to scan," so on a transient policy-load failure a response-plane redactor could forward or store content it never actually scanned. v9.4.0 distinguishes the two cases, and every response-plane and storage-plane redactor now fails closed on "could not scan": content is withheld or the response is blocked rather than passed through unscanned. A successful scan that finds nothing behaves exactly as before. Who is affected: deployments that redact or block on the response plane; during a policy-load outage they now see content withheld instead of silently unscanned output.

Decision-chain records persist again

The decision chain, the hash-chained record behind tamper-evident audit signing (it also runs in an unsigned, hash-chain-only mode when no signing key is configured), hit a database type mismatch that made every insert fail. Because chain writes are deliberately best-effort so that recording can never take down the decision path, the failure was logged but not surfaced, and the chain table stayed empty; with AXONFLOW_AUDIT_SIGNING_KEY set, signing still reported itself enabled. v9.4.0 fixes the insert, and records from all planes (decision API, gateway, MCP, and telemetry ingest) now land in the chain, signed when a signing key is configured. A regression test against a real database guards the exact failure. Who is affected: every deployment that relies on the decision chain, signed or unsigned; after upgrading, verify that new records appear. Records from the affected window were never written and cannot be recovered, so treat the chain as starting fresh from the upgrade.

The dashboard policy count matches the Policies page (Enterprise)

The dashboard's policy tile counted only dynamic policies while the Policies page showed the unified static-plus-dynamic total, so the same deployment could show 17 on one screen and 80+ on another. The tile now uses the same unified source as the Policies page, is relabeled Total Policies with an enabled count, and, when any policy source is temporarily unreachable, says the count may be incomplete instead of presenting a partial number as authoritative.

Customer portal correctness sweep (Enterprise)

An end-to-end sweep of the portal against a real in-VPC Enterprise deployment fixed thirteen defects, the most visible of which:

  • In-VPC deployments were served the SaaS portal configuration because the canonical DEPLOYMENT_MODE=in-vpc-enterprise value was not recognized, which broke the nodes view and scoped SSO settings incorrectly. The in-vpc-enterprise mode (and its deprecated invpc alias) is now recognized as self-hosted.
  • Fresh Enterprise installs could fail to create connectors or SSO configurations because two organization-scoping migrations sort ahead of the migrations that create the tables they extend. Migration core/138, which runs in both editions and is a no-op where nothing is missing, re-applies that organization scoping and row-level security idempotently, and also restores redact as a valid override action.
  • Compliance evidence exports omitted the current day because a date-only end date was parsed as exclusive midnight; the end date is now inclusive.
  • The connectors and LLM-provider pages could show "no connectors" despite existing rows, return errors on records with empty optional fields, and send provider configurations in a shape the backend rejected; list parsing, empty-field handling, and the provider form contract are fixed.
  • Human approvals recorded as system when the session had no email; approvals now carry an organization-scoped synthetic identity that the audit views label as synthetic.
  • Smaller fixes: stale session after login, an override badge showing undefined, and the policy-simulation view now stating that it evaluates dynamic policies only.

Upgrading

v9.4.0 is a drop-in upgrade from v9.3.x. Migrations core/135, core/138, and core/139 apply automatically on startup, are idempotent, and complete quickly. The main behavior change to expect is the headline: tools classified as text-document are no longer evaluated by execution-class detectors. If you need the previous behavior, set AXONFLOW_CAPABILITY_SCOPING_DISABLED=true.

Two follow-ups for admins:

  • If you relaxed detector actions as a workaround for documentation false positives (for example setting the SQL-injection or dangerous-command category actions to warn deployment-wide), revert that after upgrading: capability scoping handles documentation tools precisely, and reverting restores full blocking on the tools that can execute.
  • If an in-VPC deployment configured SSO while it was mis-detected as SaaS, the settings were stored under a tenant-scoped key, and after upgrading the portal shows SSO as not configured. Login enforcement is unaffected throughout. Re-create the SSO configuration in the portal so it is stored under the platform-wide key; the earlier tenant-scoped record remains in the database and can be re-scoped or removed by a database admin.
# Community
docker compose pull && docker compose up -d

# Enterprise
docker compose -f docker-compose.yml -f docker-compose.enterprise.yml pull
docker compose -f docker-compose.yml -f docker-compose.enterprise.yml up -d

In-VPC Enterprise (AWS CFN)

Redeploy with the v9.4.0 images. The migrations apply automatically on startup; no manual steps are required.

Community-SaaS users

No action required.