Open Questions
Questions the working group needs to resolve before OARS can be ratified.
These are not defects in the founding document. They are the ambiguities that surface when prose is turned into a reference implementation and every value has to be pinned down — which is exactly what this exercise is for. Each one is recorded here with the evidence needed to decide it.
Each has an issue for discussion, linked below. Resolutions land as pull
requests against standard/ and data/model/.
OQ-1 — Which aggregation method is normative? (blocking)
Section titled “OQ-1 — Which aggregation method is normative? (blocking)”Discuss in issue #1.
The problem. The specification describes two different ways to reach a composite score, and they disagree.
§4.1 describes normalize → weight → aggregate: within each grouping, divide the sum of raw scores by the grouping’s maximum, multiply by the grouping’s weight, and sum.
The worked examples in §6 instead sum the per-factor point values directly. Example 2 reaches 52 by adding 15 + 10 + 10 + 17.
For the same permission — Mail.Send, delegated — the two methods give:
| Method | Score | Tier |
|---|---|---|
| §4.1 normalize-weight-aggregate | 28.0 | Low |
| §6 direct sum of factor points | 52 | Medium |
That is a whole tier apart, on the example the document itself chose to illustrate the model.
Two further inconsistencies point the same way. §4.1’s own example uses dimensions named Governance (30%), Privilege (50%), and Scope (20%) — a set that matches neither the application dimensions in §1.3 (25/50/25) nor the permission domains (40/30/25/5). And §6’s Example 1 scores Token Persistence as 0 for a short-lived token, where §3.5 gives short-lived a value of 10.
What the reference implementation does. It implements §4.1, because that is
the method the specification states in prose and it produces a scale that is
bounded to 0–100 by construction. Every score in dist/ today comes from that
method.
Why this needs deciding rather than defaulting. Normalizing against the sum of every factor maximum in a domain means a permission has to trigger nearly all of them to score highly. Real permissions trigger a handful. The result is that scores compress toward the low end:
| Permission | Score | Tier |
|---|---|---|
Mail.Send (delegated) |
28.0 | Low |
Files.ReadWrite.All (application) |
36.8 | Medium |
Directory.Read.All (application) |
37.3 | Medium |
Sites.FullControl.All (application) |
43.3 | Medium |
RoleManagement.ReadWrite.Directory (application) |
64.6 | High |
Application.ReadWrite.All (application) |
81.2 | Critical |
Tenant-wide read and write access to every file in the organisation, granted to a daemon with no user oversight, scores 36.8 and lands in the same tier as reading the directory. Most practitioners would not accept that ranking.
The theoretical maximum of 100 is only reachable by a permission that is simultaneously global-admin, role-assigning, directory-wide impersonating, tenant-wide, policy-modifying, PII-bearing, offline-token-issuing, and on an unsupported legacy API. Nothing real is all of those at once, so the top of the scale is unreachable in practice and the usable range is roughly 0–65.
Options.
- Keep §4.1 and recalibrate the tier thresholds to the range the method actually produces. Cheapest change; keeps the arithmetic simple. Requires admitting the published 0–29/30–59/60–79/80–100 bounds are wrong.
- Keep §4.1 but normalize against an observed maximum rather than the theoretical one — divide by the highest score any real permission reaches in that domain. Restores spread, but the denominator changes whenever a new permission is rated, so scores are not stable across dataset versions.
- Adopt the direct-sum method from §6 and cap at 100. Matches the worked examples and practitioner intuition; loses the guarantee that domain weights mean what they say, since a domain’s influence becomes a function of how many factors happen to fire.
- Keep §4.1 for the composite and add dominant-trait overrides — a floor
tier for specific factor values, so
privilegeElevation: role-assignmentforces at least High regardless of composite. §4.2 already gestures at this (“dominant traits can independently elevate a borderline case”) without specifying it.
Option 4 is the most faithful to what the document is reaching for, and is the maintainers’ current preference, but it needs the override list defined.
Decision needed from: spec editor, with maintainer consensus. This blocks Public Review, because every rating in the dataset depends on it.
OQ-2 — Scoring ranges need discrete values
Section titled “OQ-2 — Scoring ranges need discrete values”Discuss in issue #2.
Several factors are specified as ranges: Redirect URI Method is “Custom/Wildcard URI: 2–3”, Impersonation Capability is “App-wide / dir-wide: 30–40”, Access Policy Modification is “CA/Policy changes: 40–50”.
A range is not implementable — two people scoring the same app would legitimately
disagree, which defeats the purpose. The reference implementation split each
range into discrete named values (for example custom-uri: 2 and
wildcard-uri: 3, app-wide: 30 and directory-wide: 40).
These splits are the implementer’s reading and need the spec editor to confirm
that each one lands where intended, and that no case was lost in the split. See
data/model/application.yaml and data/model/permission.yaml.
OQ-3 — Which enforcement matrix is normative?
Section titled “OQ-3 — Which enforcement matrix is normative?”Discuss in issue #3.
§5 states the highest-risk-wins principle and says organisations should map tier combinations to outcomes reflecting their own risk appetite, but gives no matrix.
A reference matrix has been added in §5.2 and data/model/tiers.yaml, explicitly
marked non-normative (enforcement.normative: false). The working group should
confirm that enforcement stays advisory — the maintainers’ view, since risk
appetite is exactly the thing a standard should not dictate — or decide that a
baseline matrix is normative with documented deviation.
OQ-4 — Application-level factors and the shared dataset
Section titled “OQ-4 — Application-level factors and the shared dataset”Discuss in issue #4.
Application-level factors are tenant-specific: ownership, maturity, credential hygiene, and activity can only be evaluated against a live tenant. They cannot be shipped as a community-curated dataset the way permission ratings can.
The current split assumes implementations compute the application layer at
runtime from Microsoft Graph and consume the permission dataset as published
data. data/model/application.yaml carries a signal field naming the Graph
property each factor reads from, as an implementation aid.
The working group should confirm this division, and decide whether those
signal values become normative — which would make the standard directly
testable by tools like Maester, at the cost of coupling it to Graph API shapes
that change.
OQ-5 — Rating coverage and prioritisation
Section titled “OQ-5 — Rating coverage and prioritisation”Discuss in issue #5.
Microsoft Graph exposes well over a thousand permissions. Rating all of them by hand is not realistic, and a dataset that is 5% complete is not obviously useful.
Proposal: prioritise by real-world consent frequency rather than alphabetically, and publish coverage honestly so implementers know what is missing. An unrated permission must be reported as unrated — never as low-risk. Absence of evidence cannot be allowed to read as evidence of safety.
The working group should agree the initial target set and the “unrated” contract for implementations.
OARS — Open App Risk Standard is derived from the Graph Consent Risk Framework by Khurram Chaudhary.
Specification and dataset licensedCC BY 4.0; tooling and site licensed MIT. © 2026 Khurram Chaudhary and the Citadel Project contributors.
A Citadel Project standard ·GitHub ·Cite this standard