Access review
Who has access to what across your connected systems: dormant accounts, over-privilege, and shared credentials.
Scope
A periodic "who can do what" review across every connected system this run can read. Enumerate and compare only — never create, modify, or revoke access, and never read credential values. The output is a proposal for the access owner. The subject is the org's own systems; do not review or report on this application's own accounts or configuration.
Procedure
- Enumerate per-system accounts, for every connected system. Use only
read-only enumeration:
- GitHub / GitLab — organization or group members, their role, outside collaborators, teams and their repository permissions, deploy keys, and personal-access or project tokens where the API exposes them. Admin/owner rights and outside collaborators on private repositories are the two lists to read closely.
- Snowflake —
SHOW USERS,SHOW ROLES,SHOW GRANTS TO ROLE, andACCOUNT_USAGE.GRANTS_TO_USERS/GRANTS_TO_ROLES; users withACCOUNTADMINorSECURITYADMIN, users with no MFA or with password authentication where key-pair is the standard, andLAST_SUCCESS_LOGINolder than 90 days. - Postgres —
pg_roles(rolsuper,rolcreaterole,rolbypassrls) andinformation_schema.role_table_grants; anything granted toPUBLICis granted to everyone and is almost always a finding. - MySQL —
SELECT user, host FROM mysql.userfor the account list, thenSHOW GRANTS FOR '<user>'@'<host>'per account;WITH GRANT OPTION,ALL PRIVILEGES ON *.*, and any account with host%are the three to read closely. Anonymous accounts (emptyuser) are a finding on sight. - Cloud and SaaS providers generally — whatever member/role listing the provider's read-only tools expose. If a system is connected but exposes no way to enumerate access, record that as a coverage gap rather than skipping it silently. With nothing enumerable connected, say so plainly in the report, emit a single info finding recording that the review had no reviewable surface, and stop — do not substitute another surface to review.
- Find the dormant. Cross-reference every principal against its last activity: 90 days with no login or action is the usual dormancy line, 180 days is indefensible. A dormant account with elevated privileges is the highest-value finding this checkup produces, because it is both the likeliest to be forgotten and the likeliest to be abused. Where a system exposes no last-activity timestamp, say so rather than assuming the account is in use.
- Find the over-privileged. Compare each principal's grants against what their observable work requires: a support member with production write grants, a contractor with organization-owner rights, a service account with a role far wider than the queries it actually runs (check query or audit history where the system exposes it). Look for privilege that was granted for a one-off task and never removed — the pattern is a broad grant with a narrow, old usage history.
- Find the unattributable. Shared logins, service accounts several humans use, API tokens with no named owner, and any credential where the system's own audit trail cannot say which person acted. These break attribution for every other control, so report them even when the access itself is appropriate.
- Compare against the last review. Findings that are still open from the previous run are the real story of an access review — a dormant account reported three months running is a process failure, not an access failure, and should be said that way in the report.
Finding keys
The key identifies the principal and the problem, not this run, so a person
who is still over-privileged next month lands on the same ledger row and a revoked
grant that reappears is flagged as a regression. Use
<system>:<principal>:<issue-slug> with the principal identified the way its own
system does (login, username, email local part, token name). Do not put dates,
counts, or role names that change into the key.
github:acme-org/octocat:dormant-adminsnowflake:ETL_SVC:accountadmin-grantpostgres:public:grant-to-publicshared:deploy-bot:no-named-owner
Severity rubric
- critical — active access for someone who has left the organization; a
privileged credential shared by several people with no attribution; production
write or admin access granted to
PUBLICor to everyone by default. - high — admin or owner privileges that are dormant, unexplained, or far beyond the holder's role; an unaccepted or unused elevated invitation; a service account with account-level administrative rights.
- medium — ordinary over-privilege with a plausible history, dormant non-privileged accounts.
- low — tidiness: unused teams, stale invitations without privilege, naming that obscures ownership.
- info — the access map itself: principal counts by role and system, recorded so the next run can see what changed.
Output guidance
Open with a one-paragraph executive summary: how many principals across how many systems, how many are privileged, how many are dormant, and the single most exposed grant. Then one section per connected system reviewed, each opening with a small access table (Principal | Role or grants | Last activity | Assessment). Add a "Not reviewed" section naming systems that are connected but expose no enumeration, and systems the org uses that are not connected at all. Close with a recommendations table (Principal | System | Recommended action | Why | Owner to action it), revocations first. Flag every finding that was already open at the last run as a repeat, since repeats are a process finding rather than an access finding. Never propose a revocation as if you performed it.
Run it against your systems
This checkup is in the desktop app under Checkups. No card, read-only credentials you configure.