← Back to Portfolio XAVIER RICHERT GRC Portfolio · Item 03 · 2026
GRC Portfolio — Write-up #03

Quarterly Access Rights Review
& Privilege Creep Analysis

Simulated access certification exercise for a fictional 120-user SaaS organisation. Python-driven analysis of user-role assignments identifying orphaned accounts, excessive privileges, and unreviewed role accumulation. Findings mapped to ISO 27001:2022 and NIST CSF 2.0.

Author
Xavier Richert
Date
March 2026
Environment
Simulated dataset — fictional
Frameworks
ISO 27001:2022 · NIST CSF 2.0
Tools
Python · Pandas · NumPy
Executive Summary

A quarterly access rights review of Arkos Software (fictional, 120 users) identified 23 accounts requiring immediate action: 6 orphaned accounts belonging to departed employees with active system access, 11 cases of privilege creep where users had accumulated roles beyond their current job function, and 6 accounts with administrative privileges that had never been reviewed since onboarding. Risk is rated Critical for orphaned accounts and High for unreviewed admin privileges. Five recommendations are provided with implementation detail and framework references.

01

Scenario & Scope

Organisation: Arkos Software (fictional) — a 120-person B2B software company using a centralised identity platform (Azure Active Directory), a cloud ERP (NetSuite), a code repository (GitHub Enterprise), and a customer data platform (Segment). Quarterly access reviews are required by the company's ISO 27001 compliance programme but have not been performed in 14 months.

The review scope covers all 120 active directory accounts and their assigned roles across the four platforms. The objective is to produce a certified entitlement report: a document confirming that all access rights are appropriate, with exceptions escalated for revocation or investigation.

What privilege creep is Privilege creep occurs when users accumulate access rights over time as they change roles, work on temporary projects, or receive exceptions — but those rights are never removed when the original need expires. A developer who spent three months on a finance data project may still have read access to payroll data two years later. Multiplied across an organisation, this creates significant risk surface: each unnecessary access right is a potential path for an attacker or a disgruntled insider.
02

Review Summary — 120 Accounts

6
Orphaned accounts
6
Unreviewed admins
11
Privilege creep
97
Certified clean

Of 120 accounts reviewed, 23 require action — a 19.2% exception rate, which is high for an organisation of this size and reflects 14 months without a review. Industry benchmark for a well-managed quarterly cycle is typically under 5%.

03

Python — Privilege Creep Detection Script

The following script loads the user-role dataset, cross-references against the current HR system for active employment status, and applies three detection rules: orphaned accounts, role accumulation beyond threshold, and admin accounts with no review date on record.

Python — access rights review automation (Pandas)
import pandas as pd
from datetime import datetime, timedelta

# Load user-role matrix and HR active employee list
roles_df = pd.read_csv('arkos_user_roles.csv')
hr_df    = pd.read_csv('hr_active_employees.csv')

active_ids = set(hr_df['employee_id'])
today      = datetime.now()

# ── RULE 1: Orphaned accounts (user not in HR = departed) ──
orphaned = roles_df[~roles_df['employee_id'].isin(active_ids)]
print(f"Orphaned accounts: {len(orphaned)}")          # → 6

# ── RULE 2: Privilege creep (>3 roles assigned) ──
role_count = (
    roles_df[roles_df['employee_id'].isin(active_ids)]
    .groupby('employee_id')['role']
    .count()
    .reset_index(name='role_count')
)
creep = role_count[role_count['role_count'] > 3]
print(f"Privilege creep candidates: {len(creep)}")   # → 11

# ── RULE 3: Admin roles with no last-reviewed date ──
admin_roles = roles_df[roles_df['role'].str.contains('admin|superuser|owner',
              case=False, na=False)]
unreviewed_admins = admin_roles[admin_roles['last_reviewed'].isnull()]
print(f"Unreviewed admin accounts: {len(unreviewed_admins)}") # → 6

# ── Build consolidated exception report ──
exceptions = pd.concat([
    orphaned.assign(finding='ORPHANED_ACCOUNT',    severity='CRITICAL'),
    unreviewed_admins.assign(finding='UNREVIEWED_ADMIN', severity='HIGH'),
])

creep_users = roles_df[roles_df['employee_id'].isin(creep['employee_id'])]
creep_users = creep_users.assign(finding='PRIVILEGE_CREEP', severity='MEDIUM')
exceptions  = pd.concat([exceptions, creep_users])

exceptions.to_csv('arkos_access_exceptions_Q1_2026.csv', index=False)
print(f"Exception report written: {len(exceptions)} rows")

## CRITICAL: 6 orphaned accounts include 2 with admin-level privileges
## in GitHub Enterprise and NetSuite. Immediate revocation required.
## Former employees retain theoretical ability to authenticate.
04

Sample Account Findings — 10 of 23

The following table shows a representative sample from the exception report. Accounts are anonymised. The "action" column reflects the reviewer's certification decision for each account.

Account Role(s) Finding Severity HR status Action
u.meyer GitHub: Owner
NetSuite: Admin
Orphaned CRITICAL Left 2024-11-03 REVOKE NOW
s.fontaine Azure AD: Global Admin Orphaned CRITICAL Left 2025-01-14 REVOKE NOW
t.brauer Segment: Admin
Last reviewed: never
Unreviewed admin HIGH Active — DevOps Justify or downgrade
l.petit Finance read
HR read · ERP export
Privilege creep MEDIUM Active — Engineering Remove finance + HR
a.kovacs 5 roles across 3 systems Privilege creep MEDIUM Active — Sales Review all roles
p.chen NetSuite: Payroll view Privilege creep MEDIUM Active — Product Remove payroll access
m.schneider GitHub: Read · Segment: Viewer None CLEAN Active — Marketing Certified
j.dupont Azure AD: User · NetSuite: AP None CLEAN Active — Finance Certified
r.hoffmann GitHub: Write None CLEAN Active — Engineering Certified
c.martin Segment: Viewer · Azure: User None CLEAN Active — Data Certified
05

Findings Register

F-01 — Six orphaned accounts with active system access CRITICAL
Six accounts belonging to employees who departed between November 2024 and January 2026 remain active in the identity platform. Two of these accounts (u.meyer, s.fontaine) hold administrative privileges in GitHub Enterprise and Azure Active Directory respectively. A former employee with admin-level access to the version control system retains the theoretical ability to exfiltrate source code, introduce malicious commits, or access customer data. This is not a hypothetical risk — it is an open door.
ISO 27001:2022 Control 5.18 · NIST CSF 2.0 PR.AA-02 · CIS Control 5.3
F-02 — Six admin accounts with no documented review HIGH
Six accounts carrying administrative-level roles across Azure AD, Segment, and NetSuite have no last-reviewed date in the access management system. This means these privileges were granted (likely at onboarding or during a project) and have never been formally justified or reconfirmed. The principle of least privilege requires that admin access be actively justified — the absence of any review record means it cannot be. Two of these accounts belong to staff who have since changed departments.
ISO 27001:2022 Control 8.2 (Privileged access rights) · NIST CSF 2.0 PR.AA-05
F-03 — Eleven accounts with role accumulation beyond function MEDIUM
Eleven active employees hold more than three system roles, with several holding access that is inconsistent with their current job function. Notable examples: a Product Manager with payroll view access in NetSuite (likely granted for a one-off finance project); a Sales Executive with five roles across three systems including write access to the customer data platform. In each case the excess access appears to be a residue of project work or temporary exceptions that were never revoked.
ISO 27001:2022 Control 5.15 · NIST CSF 2.0 PR.AA-03 · GDPR Art. 32 (integrity and confidentiality)
F-04 — No quarterly review performed in 14 months MEDIUM
The company's ISO 27001 compliance programme requires a quarterly access review. The last documented review was 14 months ago. The current exception rate of 19.2% is a direct consequence: each quarter without a review allows orphaned accounts and accumulated privileges to compound. A well-maintained quarterly cycle would reduce this to a single review of ~5–8 exceptions, taking under two hours. The current backlog required a full audit.
ISO 27001:2022 Control 5.18 · Internal compliance programme requirement
06

Framework Mapping

F-01Orphaned accounts
ISO 27001:2022 Control 5.18 — Access rights shall be removed or adjusted when employment or contract changes. Offboarding procedures must include a trigger to the identity management team. NIST CSF 2.0 PR.AA-02 — Identities are proofed and bound to credentials on the basis of context. Orphaned accounts fail this control completely — the identity binding is broken but the credential remains active.
F-02Unreviewed admins
ISO 27001:2022 Control 8.2 (Privileged access rights) — The allocation and use of privileged access rights shall be restricted and controlled. A formal authorisation process is required, and rights shall be reviewed at regular intervals. NIST CSF 2.0 PR.AA-05 — Access permissions and authorisations are managed to align with least privilege and separation of duties.
F-03Privilege creep
ISO 27001:2022 Control 5.15 — Access to information and other assets shall be controlled based on business and information security requirements. The principle of need-to-know and least privilege must be enforced. NIST CSF 2.0 PR.AA-03 — Identities are managed and authentication is performed as part of access management, aligned with risk. GDPR Article 32 also applies where excess access extends to personal data — access should be limited to what is necessary for the stated processing purpose.
F-04Review cadence
ISO 27001:2022 Control 5.18 — Access rights shall be reviewed at regular intervals. The review process should be formal, documented, and produce a certified entitlement record. The absence of a documented review for 14 months is itself a nonconformity against the organisation's own compliance programme, which would be raised as a finding in any external ISO 27001 audit.
07

Recommendations

08

GRC Reflection

The most striking number in this review is not 23 exceptions — it is 14 months. Every quarter that passes without a review is a quarter in which privilege creep compounds silently. The accounts were not breached. Nobody acted maliciously. The risk accumulated because a process was not maintained, not because anyone made a bad decision.

This is the routine of GRC work: most of what prevents incidents is not glamorous. It is a quarterly calendar entry, a script that runs in three minutes, a spreadsheet that gets certified and filed. The value is in the consistency, not the drama.

The Python component of this review is worth noting specifically. The exception report that would have taken a junior analyst two full days to produce manually — cross-referencing HR records, role assignments, and review dates across four systems — took eleven minutes to run. Data engineering skills do not just belong in a data team. They belong anywhere that structured information needs to be turned into reliable evidence.

Skills demonstrated in this write-up
ISO 27001:2022 Controls 5.15, 5.18, 8.2 NIST CSF 2.0 PR.AA mapping Access certification methodology Privilege creep detection Least privilege principle Python · Pandas — exception reporting Orphaned account identification Entitlement review documentation Offboarding procedure design Compliance calendar management