Skip to main content

Scope Mismatch Detection

Scope mismatch detection identifies annotations where the declared axag-scope is inconsistent with the operation's actual access pattern, tenant model, or role requirements.

Why It Matters​

Scope mismatches can cause:

  • Cross-tenant data leakage — An operation scoped to global that should be scoped to tenant
  • Privilege escalation — An operation scoped to user that actually modifies tenant-wide settings
  • Broken authorization — Roles defined for one scope applied in another
  • Agent over-reach — An agent invoking operations beyond its authorized boundary

Common Scope Mismatches​

1. Missing Scope on Tenant-Sensitive Operations​

❌ No scope — agent can't determine tenant boundary
<!-- ❌ No scope declared — agent doesn't know tenant boundary -->
<button
axag-intent="user.list"
axag-entity="user"
axag-action-type="read"
axag-required-roles='["admin"]'
>List All Users</button>

Rule: AXAG-LINT-011 (warning) — an operation that names roles, approval roles or a tenant boundary SHOULD declare the scope those roles apply within.

Fix:

✅ Fix — add tenant scope
<button
axag-intent="user.list"
axag-entity="user"
axag-action-type="read"
axag-required-roles='["admin"]'
axag-scope="tenant"
>List All Users</button>

2. Global Scope on User-Specific Operations​

❌ Global scope on personal action
<!-- ❌ Global scope on a personal action -->
<button
axag-intent="profile.update"
axag-entity="profile"
axag-action-type="write"
axag-scope="global"
axag-required-parameters='["user_id","display_name"]'
>Update Profile</button>

Rule: AXAG-LINT-018 (warning) — operations on personal entities SHOULD use user scope, not global.

Fix:

✅ Fix — use user scope
<button
axag-intent="profile.update"
axag-entity="profile"
axag-action-type="write"
axag-scope="user"
axag-required-parameters='["display_name"]'
>Update Profile</button>

3. Tenant Scope Without Tenant-Aware Roles​

<!-- ❌ Tenant scope but roles don't include tenant context -->
<button
axag-intent="settings.update"
axag-entity="settings"
axag-action-type="write"
axag-scope="tenant"
axag-required-roles='["superadmin"]'
>Update Settings</button>

Rule: AXAG-LINT-019 (warning) — superadmin roles typically imply global scope. Verify that tenant is correct.

4. Cross-Entity Scope Inconsistency​

When two operations on the same page operate on the same entity but declare different scopes:

<!-- Operation 1: tenant scope -->
<button axag-intent="report.generate" axag-entity="report"
axag-action-type="read" axag-scope="tenant">Generate</button>

<!-- Operation 2: global scope (on same entity) -->
<button axag-intent="report.delete" axag-entity="report"
axag-action-type="delete" axag-scope="global">Delete</button>

Rule: AXAG-LINT-020 (warning) — operations on the same entity within one file SHOULD use a consistent scope unless the difference is deliberate.

Scope Hierarchy​

global
└── tenant
└── user
└── public
ScopeMeaningTypical Operations
globalPlatform-wide, all tenantsSystem settings, platform analytics
tenantWithin a single tenant/organizationTeam management, tenant config, business data
userPersonal to the signed-in userProfile, preferences, cart, personal data
publicNo authentication neededCatalogue browsing, help pages

These four are the only values the manifest schema accepts. A narrower boundary — a team, a department — is tenant plus axag-required-roles.

Detection Rules Summary​

RuleMismatchSeverity
AXAG-LINT-011Role or tenancy attributes without a scopeWarning
AXAG-LINT-018Global scope on personal operationsWarning
AXAG-LINT-019Scope/role hierarchy mismatchWarning
AXAG-LINT-020Inconsistent scope on the same entityWarning
AXAG-LINT-021Delete operation without scopeWarning
AXAG-LINT-022Tenant-level entity written with user scopeWarning
AXAG-LINT-036Tenant-scoped action that takes the tenant as a parameterError

Scope rules are warnings because only your domain knows the right boundary. AXAG-LINT-036 is an error: a tenant-scoped action that accepts the tenant as a parameter lets an agent name someone else's tenant, which @web-axag/server then has to refuse.

CI Integration​

- name: Check for scope mismatches
run: npx axag-lint src --format github

Next Steps​