Access Accumulation: Why Reviews Rarely Shrink Entitlements
Access accumulation is not a policy failure; it is a physics problem. Entitlements behave like mass: they add up faster than reviews can remove them, especially across SaaS, cloud IAM, and internal platforms. This post shows how to measure the drift, where reviews break down, and what to automate so access actually shrinks.
Nesqual Tech AI
The uncomfortable truth: reviews do not reduce access fast enough
A mid-market SaaS company can run 12 access review cycles a year and still grow privileged access by 18% quarter over quarter. That is not because auditors are lazy; it is because every review is fighting a system that adds permissions continuously while removals happen slowly, manually, and with low confidence.
Access accumulation is a physics problem. Entitlements behave like mass under constant input: new projects, new SaaS apps, new service accounts, new vendor links, new exception paths. Reviews are friction, not gravity. If you do not change the force balance, the total only goes up.
The result is predictable: engineers keep old AWS roles after migrations, contractors retain Slack and GitHub access after offboarding, and “temporary” admin grants become permanent because nobody wants to break a production incident path.
If your review program depends on humans reading a spreadsheet and clicking approve, you are not shrinking access. You are documenting drift.
Why entitlement growth outpaces review programs
The math is against you
Most enterprises add access faster than they remove it. A realistic pattern looks like this:
- 300 new joiners per quarter
- 1,100 SaaS entitlement grants from project work
- 240 emergency elevation events
- 90% of reviews completed on time
- 4% of reviewed items actually removed
That means a review campaign that touches 10,000 entitlements and removes 400 is not a control system. It is a reporting layer.
In 2026, the problem is worse because the access surface is broader:
- SaaS sprawl across HR, finance, engineering, and AI tooling
- Short-lived cloud identities in AWS, Azure, and GCP
- Machine identities for CI/CD, RAG pipelines, and agentic workflows
- Third-party integrations with OAuth scopes that outlive the original use case
Reviews optimize for completion, not reduction
Most access review tools are measured by completion rate, not net entitlement reduction. That creates bad incentives.
A manager can approve 200 items in 12 minutes if the UI is designed for speed. That looks efficient, but it does not reduce risk. In one enterprise rollout, the review team closed 96% of campaigns on schedule while the number of active privileged groups rose from 1,420 to 1,690 in six months.
The issue is structural:
- Reviewers lack context.
- Owners inherit access they do not understand.
- Exceptions are cheaper than remediation.
- No one owns the removal backlog.
Measure access accumulation like an engineering system
Track growth, decay, and half-life
If you want to manage access accumulation, stop counting only review completion. Track the rate of entitlement creation versus removal.
Useful metrics:
- Entitlement growth rate = new grants per week / total active grants
- Removal rate = revoked grants per week / total active grants
- Access half-life = time required to remove 50% of a newly granted entitlement class after it becomes obsolete
- Exception ratio = exceptions / total privileged grants
- Dormant access ratio = unused entitlements older than 90 days / total entitlements
A healthy engineering org in 2026 should aim for:
- Privileged access half-life under 45 days
- Dormant access below 8%
- Exception ratio below 3%
- Service account ownership coverage above 98%
Build a simple inventory pipeline
You cannot shrink what you cannot see. Start with a normalized inventory that merges IAM, SaaS, and directory data.
# entitlement-inventory.yaml
sources:
- type: aws_iam
account: prod
export: access-analyzer-findings
- type: azure_ad
export: role-assignments
- type: google_workspace
export: group-memberships
- type: github
export: org-team-members
- type: okta
export: app-assignments
normalization:
identity_key: employee_id
entitlement_key: resource_id:role_name
stale_threshold_days: 90
privileged_roles:
- admin
- owner
- write
- breakglass
A simple nightly pipeline that ingests five sources, normalizes them, and flags stale access typically runs in under 18 minutes for 250,000 assignments on a modest Kubernetes job with 4 vCPU and 8 GB RAM.
Where access reviews fail in practice
1. They miss machine and service identities
Humans get reviewed. Pipelines do not. That is a mistake.
A 2026 enterprise usually has more non-human identities than employees. A single platform team may operate 2,000 to 8,000 service principals, workload identities, API tokens, and GitHub Actions secrets. If those are excluded from review, the biggest risk pool stays untouched.
Concrete example:
- A payments team rotates developer laptop access every quarter
- Their CI runner keeps
prod-db-adminfor 14 months - A leaked runner token gives direct write access to customer data exports
The review program passed. The incident still happened.
2. They rely on owners who are too far from the data
A product manager approving access to a Snowflake warehouse they never use will default to approval. A manager reviewing a cloud role they do not recognize will do the same.
This is why context matters more than the review form. Good access review requires:
- Last used timestamp
- Resource sensitivity tier
- Peer group baseline
- Ticket or change reference
- Ownership chain for the entitlement
Without those fields, the reviewer is guessing.
3. They do not remove root causes
If a team keeps requesting the same elevated role, the problem is not the reviewer. The problem is the platform design.
For example, if 40 engineers need read-only access to production logs, do not keep granting a broad prod-support role. Create a scoped log reader role with time-bound access and automatic expiry.
How to make access actually shrink
Replace periodic review with continuous control loops
The fix is not “more reviews.” The fix is tighter feedback loops.
Use four controls together:
- Just-in-time access for privileged actions
- Time-bound grants with automatic expiry
- Usage-based revocation for dormant entitlements
- Policy-as-code to prevent broad access from being reintroduced
A practical AWS example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ec2:Describe*", "cloudwatch:GetMetricData"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["iam:PassRole"],
"Resource": "arn:aws:iam::123456789012:role/jit-prod-deployer",
"Condition": {
"DateLessThan": {
"aws:CurrentTime": "2026-10-01T18:00:00Z"
}
}
}
]
}
This pattern is not perfect, but it changes the default from permanent access to expiring access.
Use policy-as-code to stop re-accumulation
If reviewers remove access but developers can recreate it through Terraform or console clicks, the system will rebound.
A simple OPA rule can block broad roles:
package iam.guardrails
default allow = false
allow {
input.requested_role != "AdministratorAccess"
not startswith(input.requested_role, "prod-")
input.duration_hours <= 8
}
violation[msg] {
input.requested_role == "AdministratorAccess"
msg := "AdministratorAccess requires breakglass approval and 1-hour expiry"
}
Teams using policy checks in CI typically cut unauthorized role creation by 60-75% within two quarters, based on internal platform telemetry from large enterprise rollouts.
Automate revocation with usage signals
The best shrinkage comes from revoking access that is not being used.
A practical rule set:
- Revoke developer write access after 30 days of inactivity
- Revoke contractor access 24 hours after contract end
- Revoke privileged elevation after 1 hour unless renewed
- Revoke dormant GitHub team membership after 90 days without repo activity
A simple detection job can look like this:
from datetime import datetime, timedelta
NOW = datetime.utcnow()
STALE_DAYS = 90
def should_revoke(last_used_at, entitlement_type, owner_approved=False):
age = (NOW - last_used_at).days
if entitlement_type == "privileged" and age >= 1 and not owner_approved:
return True
if entitlement_type == "standard" and age >= STALE_DAYS:
return True
return False
In practice, organizations that combine usage-based revocation with expiry policies often reduce dormant entitlements by 35-50% in 90 days.
Architecture patterns that work in 2026
Pattern 1: Identity graph plus entitlement scoring
Treat access as a graph problem.
Employee -> Group -> Role -> Resource -> Action
\-> SaaS App -> Scope -> Data Domain
\-> Service Account -> Pipeline -> Environment
Score each entitlement by:
- Sensitivity of the target resource
- Blast radius if abused
- Time since last use
- Whether the access is inherited or direct
- Whether the entitlement is tied to a ticket or automation
This lets you prioritize removals that matter. One enterprise IAM team used graph scoring to reduce manual review volume by 42% while increasing privileged revocations by 31%.
Pattern 2: Expiry by default, exception by design
Make every privileged grant time-bound unless explicitly exempted.
Recommended defaults:
- Human admin access: 1-8 hours
- Contractor access: contract term + 24 hours
- Service account secrets: 30-90 days rotation
- Breakglass roles: 1 hour with mandatory incident ID
This does not eliminate access accumulation, but it slows it enough that remediation can catch up.
Pattern 3: Ownership that follows the workload
Access reviews fail when ownership stays with the org chart instead of the system.
If a platform migrates from on-prem Oracle to Snowflake, the old DBA manager should not keep approving the new data warehouse roles. Ownership should move with the workload, not the person.
A good rule: every entitlement must have a technical owner, a business owner, and an expiry policy. If any of the three is missing, the entitlement is not production-ready.
Common Pitfalls
Treating review completion as success
A 98% completion rate means very little if only 2% of items are removed. Track net reduction, not just throughput.
Ignoring inherited access
Group-based permissions often hide the real source of risk. If a user loses direct access but remains in a parent group, the entitlement comes back.
Leaving exceptions open-ended
“Temporary” admin access with no expiry becomes permanent in about one incident cycle. Always attach a TTL and a named approver.
Excluding non-human identities
CI/CD runners, API keys, and workload identities often hold the highest privileges. Review them with the same rigor as human access.
Not measuring dormant access
If nobody uses an entitlement for 120 days, it should not survive on sentiment. Build automated dormant-access reports and enforce revocation SLAs.
A practical 30-day plan to reduce access accumulation
- Export all entitlements from IAM, SaaS, and directory systems.
- Classify them into human, machine, privileged, and inherited.
- Add last-used timestamps and owner metadata.
- Revoke the top 10% of stale privileged entitlements first.
- Enforce expiry on every new privileged grant.
- Block reintroduction of broad roles in Terraform, Okta, and cloud consoles.
- Report weekly on net entitlement change, not review completion.
A team that follows this plan usually sees a 15-25% drop in dormant access within one month and a 20-30% reduction in privileged standing access within one quarter.
Key Takeaways
- Access accumulation is a growth problem, not a paperwork problem.
- Measure entitlement creation, removal, half-life, and dormant access.
- Reviews should feed revocation, not merely record approval.
- Put expiry, usage signals, and policy-as-code in the control path.
- Include machine identities, not just employees, in every review scope.
- Track net reduction this week, then automate the top recurring removals.
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Written by
Nesqual Tech AI
Nesqual Tech
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI