Skip to the document
Aksu Indexv 1.0

Specification

The Aksu Index

Version 1.0 · approved 31 July 2026 · this page published 20 August 2026

Definition

The Aksu Index of an (agent, running user) pair is the number of distinct fields the code behind the agent has been proven able to reach beyond what that user is allowed to see — always reported together with what could not be resolved.

The Index is stated as four disjoint numbers. Section 04 of this document is the rule that forbids quoting fewer than four of them.

Canonical form

Aksu Index: P proven (C GDPR) · B unproven boundaries · U unresolved

The shape of the line, with placeholders. It is not a measurement; two measured lines appear in section 05.

Freeze notice

Version: 1.0 — approved by the maintainer on 31 July 2026 (the four load-bearing choices: pair-scoped, fields-only, four-bucket reporting, GDPR callout). Freezes permanently at first public reference, and is never silently redefined after that (§8).

A gap without a number is an opinion.

The gap this measures was not discovered here. Identity and SaaS-security vendors named it first and describe it precisely, and a standards body classifies it as a risk category. Their words follow, with dates and links, because a contribution is only legible once its antecedents are.

Only sources verified against the live page are listed here. Pages were fetched and the quoted sentences matched byte for byte on 20 August 2026. Where a source was checked and did not say what it is often reported to say, that is recorded in the reading note rather than smoothed over.

The nearest published metric, disclosed

One numbered over-privilege metric is already published, and it is not this one:

OPUR — Over-Privilege Use Rate When Lower Privileges Suffice: Investigating Over-Privileged Tool Selection in LLM Agents, arXiv 2606.20023, 18 June 2026.

OPUR scores model behaviour — how often a language model selects a higher-privilege tool when a lower-privilege one would do — across a synthetic benchmark. It measures a different object: not a specific agent in a specific org against a specific running user's effective permissions. The two are not competing definitions.

What this document adds

The gap has a name. This gives it a number.

Stated narrowly, so it can be checked: the gap is named by identity and SaaS-security vendors and classified by OWASP. What has not existed is a published specification for a number that can be quoted, and then checked, by someone who did not produce it.

Specification §1, §2, §3

The Aksu Index of an (agent, running user) pair is the number of distinct fields the code behind the agent has been proven able to reach beyond what that user is allowed to see — always reported together with what could not be resolved.

The three quantities

Let, for the (agent, running user) pair:

outer
the set of qualified fields (Object.Field; relationship paths kept verbatim) reachable by the agent's resolved code chain. “Resolved” means execution semantics are computed per operation under the precedence law: explicit mode clause ▸ apiVersion default (≥ v67 → user mode) ▸ sharing declaration (record axis, system mode only).
inner
the subset of outer the running user could read anyway under their effective permissions.
gap
outer \ inner, restricted to operations proven to execute not bounded by the running user (the FLS axis resolved False).

Invariant, enforced by the tool: outer = inner + gap (the concentric circles).

The four buckets

The Index then reports four disjoint quantities. They are disjoint by construction: the most severe verdict wins across an agent's actions, so a field cannot land in two buckets.

bucketmeaningevidence level
P — provenfields in gap whose escalation is proven (ERROR findings, PS502/PS506)proven
C — classifiedsubset of P carrying the org's own compliance labels (GDPR/PII — PS506)proven
B — unproven boundariessame rules at WARN: a real boundary the analysis could not prove crossed (e.g., a sanitizer present but the path unprovable)bounded, unproven
U — unresolvedreach that could not be determined at all: dynamic SOQL, SOSL without RETURNING, undetermined sharing context (PS504)honest unknown
P is the headline number. C is why it matters. B and U are why the headline can be trusted — they are printed, never absorbed into P and never dropped.
C is inside P
C is a subset of P, never an addend. Every field counted in C is already counted in P. Any rendering that places them side by side as peers is wrong, and the rendering used on this page places C inside P's own box for that reason.
On the word “regulated”
Which fields count as regulated is the org's decision, not this specification's. The measurement reads the data-classification labels the org's own administrators already applied — whether they tag for GDPR, CCPA, HIPAA, or an internal policy. The mechanism is regime-agnostic; calling it a GDPR measurement would describe one customer's use of it as though it were the feature.

Scope

One Index describes exactly one agent × one running user, at one moment, under one tool version. It is not an org score.

A hypothetical holder of a single permission set may be substituted, but the report must label it as a hypothesis, not a person.

Specification §1 · ADR-013

This is the discipline the specification exists to impose. It is the one clause most likely to be broken by someone quoting the number in a hurry.

Specification §1

Quoting the proven number alone while unresolved > 0 is a violation of this specification. An unknown never reads as clean.

ADR-013, accepted 19 August 2026

The headline is P — the count of fields proven reachable beyond the running user — rendered large, first, and always with C, B and U beside it. No ratio is computed, stored or displayed.

Two layout consequences

  1. 01

    The band renders four numbers as one visual object. C is rendered inside P, never as a peer tile that could read as P + C.

  2. 02

    When P = 0 and U > 0, the not-clean statement renders inside the band, adjacent to the zero, and may not be styled as a pass. This is the design's primary test case, not an edge case.

Why no ratio

A single-decimal ratio was proposed and rejected. It is worth recording why, because the ratio is the obvious thing to reach for and it fails in exactly the case that matters:

The disqualifying case — an agent measuring 0 proven with unresolved reach (section 05)
Its ratio is 1.0: a perfect reading for an agent the analyzer explicitly refuses to call clean. The ratio has no term for U, so it cannot express the one thing [the honesty discipline] exists to protect. This alone is disqualifying.

No ratio, percentage, grade, threshold or letter rating is computed, stored or displayed anywhere in this specification.

Enforced by construction
The rule is not left to reviewers. In the reference implementation no function returns fewer than all four numbers, and on this page the badge component accepts the four as a single object — there is no call site that could render P alone.

Measured 31 July 2026 · Salesforce Summer '26

Both agents below run in the author's own demonstration orgs. There are no customers, and no third-party org is described. Both runs were taken on 31 July 2026 against Salesforce Summer '26.

TechnoStore Revenue Assistant

Two actions, both at an API version below 67, so both default to system mode. Six fields are proven reachable beyond the running user, one of which carries the org's own compliance label. One operation could not be resolved at all, which is why the fourth number is not zero.

TechnoStore Revenue Assistant
Running user: hypothetical grant model — permission set TechnoStore_Revenue_Assistant2098228049_Permissions. A hypothesis, not a person.

Aksu Index: 6 proven (1 carrying the org's own compliance labels); 0 unproven boundaries; 1 unresolved.

The tool's own output line, verbatim
Aksu Index: 6 proven (1 GDPR) · 0 unproven boundaries · 1 unresolved
Measured context — not part of the Index
actions
2
legacy
2 / 2 pre-v67
fields
8 reachable
fingerprint
09789b487c84

HW Energy Agent

Nine actions, none below API version 67. No field is proven reachable beyond the running user. Two operations use dynamic SOQL, so their reach could not be determined at all.

HW Energy Agent
Running user: hypothetical grant model — permission set HW_ServiceAgent. A hypothesis, not a person.

Aksu Index: 0 proven (0 carrying the org's own compliance labels); 0 unproven boundaries; 2 unresolved.

The tool's own output line, verbatim
Aksu Index: 0 proven (0 GDPR) · 0 unproven boundaries · 2 unresolved
Measured context — not part of the Index
actions
9
legacy
0 / 9 pre-v67
fields
4 reachable
fingerprint
464add656d38
Why this is the more important example
A zero here is not a pass. Two unresolved operations mean two pieces of reach nobody has measured, and an unknown never becomes clean. This is the case a ratio would have scored perfectly, and it is the reason the fourth number is never dropped.
Why the line says GDPR and the prose says regulated
The lines above are the tool's own output, reproduced byte for byte. The word GDPR appears because that is the ComplianceGroup value this org's own administrators applied to the field. The mechanism reads whatever labels it finds, so the prose of this specification says “regulated”.
Org-wide context, which is not the Index
TechnoStore measures 113 of 113 of its own Apex files below API version 67. HanseWatt measures 182 of 219, and its agent's nine actions are nevertheless all at v67. Neither figure is part of either Index. They are recorded because they show that the two numbers are independent: an agent's exposure is not read off its org's average.

ProvenanceAnalyzer fingerprint d3a0cb4d683c · parser 5.1.0. The per-report fingerprint identifies which tool produced each number; see section 07.

Specification §4, verbatim

Six statements the Index does not make. They are reproduced from §4 of the specification without alteration.

  1. 01

    It counts fields, never records. Record-level visibility is sharing-dependent; the honest answer is “run as the user to measure”, so the record axis is disclosed in prose (PS501) and never as a number in the Index.

  2. 02

    Org row counts are context, not the Index. A COUNT() is an upper bound — “could reach up to N rows”, never “reaches N”.

  3. 03

    Index = 0 with U > 0 is not clean. It is “0 proven, U unresolved”, and must be said that way.

  4. 04

    It measures authority, not behaviour. The Index says what the code chain can reach as built — not what the agent has done in any conversation.

  5. 05

    It is not a certificate. It is evidence for a security review / DPIA, produced statically, with zero agent invocations and zero Flex Credits.

  6. 06

    It is version-bound. A number is comparable only under the same tool version; the report's fingerprint (a sha256 over the rule/extractor source, parser version, analysis coverage, backend, and each class's own apiVersion) says exactly which tool produced it.

Specification §7

The measurement is published so that a number can be checked by people who did not produce it. The procedure is short.

Same org state + same running user + same tool version ⇒ byte-identical reports (proven live: two runs, equal sha256). To verify a Index someone quotes: run the tool twice on the same inputs, hash both outputs, compare fingerprints. The live COUNT() context lines are outside the deterministic fingerprint and say so.

Procedure

  1. 01

    Establish the three inputs the number depends on: the org state, the running user, and the tool version.

  2. 02

    Run the analysis twice on those same inputs.

  3. 03

    Hash both outputs. Byte-identical reports produce equal hashes; anything else means one of the three inputs moved.

  4. 04

    Compare the fingerprint in the report against the fingerprint quoted with the number. A number is comparable only under the tool version its fingerprint names.

  5. 05

    Read the live row-count context lines separately. They sit outside the deterministic fingerprint and say so, because a COUNT() is an upper bound and an upper bound is not a measurement.

Upper bounds are not measurements
Where a report gives a row count, the honest form is “could reach up to N rows”, never “reaches N”. Predicates and LIMIT clauses are not resolved, so the count bounds the reach rather than measuring it.

Specification §5

Condensed from §5 of the specification — enough that an implementer can follow it, and enough that a reader can tell what would have to be true for a number to be wrong.

  1. 01

    Resolve execution semantics per operation — the precedence law above, on both axes separately: enforces_fls (object CRUD + field security) and enforces_sharing (record visibility). Each is True / False / None = undetermined, and None is reported, never assumed safe.

  2. 02

    Extract reach SOQL (subqueries are reads of their own), SOSL, DML, async hand-offs (Queueable/Batch/@future, EventBus.publish as a write), trigger cascades, Flow runInMode, prompt-template merges — via two backends (AST and regex) feeding the same precedence core.

  3. 03

    Resolve the user effective permissions from a snapshot: profile + permission sets + PSG aggregates (muting measured to apply).

  4. 04

    Intersect with the org's own compliance labels (FieldDefinition.ComplianceGroup), including single-target relationship fields; polymorphic lookups are honestly skipped.

  5. 05

    Subtract and classify into P / C / B / U per §3.

Severity is a claim about proof, not about impact
ERROR means proven. WARN means a real boundary that could not be proven crossed. The two never merge, because the severity is what places a field in P rather than in B.
The governing discipline
A silent false-clean is worse than an honest unknown. Anything the analysis cannot resolve is reported as unresolved and counted in U — never dropped, and never treated as absence of reach.

Specification §9 · in-org measurements

The precedence law the method rests on is measured in a real org, not inferred from documentation. Where documentation and a live org disagreed, the org was believed.

From §9 of the specification

The in-org measurements

Sixteen experiments are recorded. Fifteen returned a result; one (E12, formula-field inputs) could not be deployed and is reported as open rather than as a finding.

idwhat it measuredresult
E1System-mode read versus user-mode read, on both axes.5 records vs 0
E2The same without sharing source at two API versions. Also: no declaration is not the same as without sharing.v58 = 5, v67 = 0
E2bThe two-axis proof at v67: the record axis enforced, and the FLS read blocked rather than silently stripped.0 rows; read BLOCKED
E3WITH USER_MODE on a without sharing class. The operation clause beats the declaration.0
E4FieldDefinition.ComplianceGroup is readable without cost, but the query must be bounded per EntityDefinition, and FieldDefinition is itself FLS-gated.
E5Flow runInMode is declarative and static, so Flow actions are analysable without parsing Apex.
E6A trigger's DML runs in the mode of the trigger's own apiVersion. The v58 half of a matched pair with E13.v58 child write lands
E7Agent Script apex:// syntax is vendor-validated.sf agent validate → success
E8Permission Set Groups: the platform-computed aggregate's ObjectPermissions equalled the union of its components.exact match
E9Muting is applied by the aggregate, and the runtime agrees: WITH USER_MODE is blocked while a pre-v67 class still reads the muted value.aggregate has no row
E10Three pre-v67 invocables differing only in the sharing declaration, same caller, same admin-owned rows on a Private object.without sharing = 5, no declaration = 0, with sharing = 0
E11Platform-event publish by a user holding no ObjectPermissions row at all.v58 publish lands, v67 publish blocked
E12Formula-field inputs. The fixture that would settle whether a formula carries a value past the running user's FLS could not be deployed. Reported as open, not as a result.BLOCKED — not measured
E13A v67 trigger's own DML is bounded by the running user. Re-measured with controls on 2026-08-04; the org named the child entity and the trigger's own line in the exception.v58 writes / v67 blocks
E14WITH SECURITY_ENFORCED does not compile at v67, with the v66 control. Same source, only the apiVersion differs.v66 deploys / v67 fails
E15The record axis inside a trigger body, read two ways: a plain read (which reads the operation's mode) and WITH SYSTEM_MODE (which exposes the ambient context).v58: PLAIN=5 SYS=5 · v67: PLAIN=0 SYS=5
E16A trigger body does not inherit its caller's sharing declaration, in the form an Apex caller can express. Three call shapes at two versions.all six readings identical
On documentation
Three separate reviews, each citing a real vendor source, argued that the precedence law was wrong. Each was answered with an experiment rather than an edit, and each time the live org contradicted the document. Documentation describes intent; the org describes behaviour, and only one of the two is what a customer runs.

A reference implementation exists — Agent Blast Radius — and it produced the two worked examples in section 05. It is scored against a separately published corpus, the Agent Authority Benchmark v1.1 of 19 August 2026: 28 Apex cases, of which 21 are adjudicated by a real org and 7 are labelled not adjudicable. The specification is published independently of it, so that a number it produces can be checked against the definition rather than against the tool.

Specification §8, verbatim

This document freezes at its first public reference. That reference is this page.

  • This specification freezes at its first public reference. After that, any change to §3 (the formula) or §4 (the non-claims) is a new major version, published side by side — an existing number is never silently redefined.
  • The tool fingerprint identifies which specification version produced a number.
  • Extensions that only add reporting (new sub-buckets, new labels) are minor versions and must not change P/C/B/U for an unchanged input.
Decision record
ADR-013, accepted 19 August 2026, fixed the headline as P and rejected a ratio. It ships under v1.0 because §3 — the formula — was not touched. A change that did touch §3 or §4 would have required a new major version published side by side.

The v1.0 source document contains figures and one formulation that this page does not reproduce. They are listed rather than silently corrected: a specification that quietly edits itself is the same failure it exists to prevent, one level up. The clauses that define the measurement — §1, §3, §4, §7 and §8 — are unaffected.

Mustafa Aksu, Aksu Software.

The Aksu Index specification is published so that any number carrying its name can be checked against a definition its author does not control at the moment of quotation.

Licence

The reference implementation's repository carries an MIT licence (Copyright © 2026 Mustafa Aksu), whose grant covers the software and its associated documentation files. Whether this specification, as published here, is offered under that licence or under a separate documentation licence is not stated in the source material. The licence position is therefore to be confirmed, and is not asserted here.