Skip to main content

agent-access-review

Tests CodeQL OpenSSF Scorecard M8ven Score

User access reviews for AI agents. It finds every agent and MCP server an organization runs, works out what each one can read, write, execute and send, tests that access against 12 controls, and produces the packet an auditor expects: a reviewer sign-off sheet, hashed evidence, and OSCAL assessment results mapped to NIST 800-53, SOC 2, NIST AI RMF and the OWASP Top 10 for LLM Applications.

In one sentence: the quarterly "who has access to what?" review that companies already run for employees, applied to AI agents.

Real-world case study: what you get by copying the MCP configs from official READMEs: 8 of 9 unpinned, 7 of 9 with unreviewed write/send/execute access, and an exfiltration path once they're combined.

Quick start (2 minutes)

You need Python 3.11+. No cloud account, API keys or network access.

pip install "git+https://github.com/Mihirajmera/agent-access-review@v0.2.0"
agent-access-review demo

demo reviews five example agents and writes the packet to review-demo/. Open review-demo/access-review.md, or just read the sample report here without installing anything.

Then review your own setup:

Tool Where its MCP config lives Command
Claude Desktop (macOS) ~/Library/Application Support/Claude/claude_desktop_config.json agent-access-review scan ~/Library/Application\ Support/Claude/claude_desktop_config.json
Claude Desktop (Windows) %APPDATA%\Claude\claude_desktop_config.json PowerShell: agent-access-review scan "$env:APPDATA\Claude\claude_desktop_config.json"
Cursor ~/.cursor/mcp.json (global) or .cursor/mcp.json (project) agent-access-review scan ~/.cursor/mcp.json
VS Code .vscode/mcp.json in a project agent-access-review scan .vscode/mcp.json
Your own agents an agents.yaml you maintain agent-access-review scan agents.yaml

Secrets in your configs are masked before anything is written, so the output is safe to share.

New to this? Key terms in plain English
Term Meaning
AI agent An AI model that can take actions through tools: read files, query databases, send email, run commands.
MCP (Model Context Protocol) The standard way apps like Claude Desktop, Cursor and VS Code plug tools into an AI. Each "MCP server" in a config is one tool the agent can use.
User access review (UAR) The periodic check where each person's access is listed, an owner confirms it's still needed, and the rest is revoked. Auditors test it under SOX and SOC 2.
ITGC IT General Controls: the baseline controls (access, change management, operations) auditors test for financial reporting.
Non-human identity An account used by software rather than a person: service accounts, API keys, and now AI agents.
Exfiltration path A route for data to leave the organization. Here: an agent that can read sensitive data, reads content an attacker can write, and can send data out.
Prompt injection Hiding instructions in content an AI reads (an email, web page or ticket) so it does something its user never asked for.
OSCAL NIST's machine-readable format for security controls and assessment results, so GRC tools can import findings automatically.

Problem

Every SOX and SOC 2 program runs quarterly user access reviews: list who has access to what, have an owner confirm it's still needed, revoke the rest, keep the evidence. AI agents now hold the same kind of access (API tokens, database connections, shell access, mailboxes), and almost nobody reviews them:

  • No owner, no approval. A developer adds an MCP server to their Claude Desktop or Cursor config and the agent instantly has their GitHub token and home directory. No ticket, no approver, and it never appears in an access review.
  • Over-broad by default. Setup guides tell people to grant the whole home directory, the full-control repo scope, or tenant-wide *.All Microsoft Graph permissions.
  • Secrets in plain text. MCP configs routinely hold raw tokens and database passwords.
  • A new attack path. An agent that can read sensitive data, read content an attacker wrote (a GitHub issue, an email, a web page), and send data out can be prompt-injected into leaking that data. No traditional access control looks at that combination.

Agents are non-human identities. They need the same joiner/mover/leaver and recertification controls as people, plus a few that are specific to AI.

What it checks

ID Control Severity Frameworks
AAR-01 Every agent has an accountable human owner high NIST 800-53 AC-2 · SOC 2 CC6.2 · AI RMF GOVERN 2.1
AAR-02 Access is approved and recertified within 90 days high / medium AC-2 · CC6.2, CC6.3
AAR-03 Privileged actions (write, delete, send) need human approval high / medium AC-6 · CC6.3 · AI RMF MAP 3.5 · OWASP LLM06
AAR-04 Least privilege: no home directories, wildcards, admin or tenant-wide scopes high AC-6 · CC6.3 · LLM06
AAR-05 Code and shell execution is sandboxed high CM-7, AC-6 · LLM05, LLM06
AAR-06 No hardcoded credentials high IA-5 · CC6.1
AAR-07 Credentials rotated within 90 days medium / low IA-5 · CC6.1
AAR-08 Dormant access removed after 90 days medium / low AC-2(3) · CC6.2
AAR-09 No exfiltration path (sensitive data + untrusted input + egress, with no human gate) high AC-4 · AI RMF MEASURE 2.7 · LLM01, LLM02
AAR-10 Tool packages pinned to a version or image digest medium SR-3 · LLM03
AAR-11 Remote MCP servers use HTTPS high SC-8 · CC6.7
AAR-12 Every tool's capabilities are inventoried medium CM-8 · AI RMF GOVERN 1.6

Each control is defined once in controls.yaml and cross-walked to every framework, so one test produces evidence for all of them. The mappings are my own judgment and should be checked against official crosswalks before being relied on in a real audit.

The AI-specific risk: exfiltration paths (AAR-09)

Traditional access reviews look at one permission at a time. For AI agents, the danger is a combination: an agent that can read sensitive data, reads content an outsider wrote, and can send data out. Each leg is harmless alone. Together, one prompt injection hidden in an email, ticket, issue or web page can instruct the agent to leak the data. A human approval step on any leg breaks the chain.

flowchart TB
    subgraph BAD["❌ finance-ops-agent: flagged AAR-09"]
        direction LR
        U1["📨 Untrusted input<br/>anyone can email the AP inbox"] -->|"hidden instruction:<br/>forward vendor bank details"| A1(("🤖 agent"))
        D1[("🔒 Restricted data<br/>NetSuite vendor bills")] -->|reads| A1
        A1 -->|"sends email<br/>no human approval"| X1["🌐 Egress<br/>any recipient"]
    end
    subgraph GOOD["✅ support-copilot: passes"]
        direction LR
        U2["📨 Untrusted input<br/>customer tickets"] --> A2(("🤖 agent"))
        D2[("🔒 Confidential data<br/>ticket history")] --> A2
        A2 -->|"drafts reply"| H{{"👤 Human approves"}}
        H -->|sends| X2["Customer"]
    end
    BAD ~~~ GOOD

    classDef risk fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
    classDef safe fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef gate fill:#fef3c7,stroke:#d97706,color:#78350f
    class U1,D1,X1 risk
    class U2,D2,X2 safe
    class H gate

This maps to OWASP LLM01 (prompt injection) and LLM02 (sensitive information disclosure), NIST 800-53 AC-4 (information flow enforcement) and NIST AI RMF MEASURE 2.7 (AI security and resilience).

How it works

flowchart LR
    subgraph IN["📥 Inputs"]
        A["Claude Desktop / Cursor<br/>MCP configs"]
        B["VS Code<br/>.vscode/mcp.json"]
        C["agents.yaml<br/>LangChain · CrewAI · custom"]
    end
    subgraph CORE["⚙️ agent_access_review"]
        P["Parsers<br/>secrets redacted here"]
        K[("Capability catalog<br/>catalog.yaml")]
        I["Normalized inventory<br/>agent → grants + credentials"]
        X["12 checks<br/>AAR-01 … AAR-12"]
        M[("Control catalog<br/>controls.yaml")]
    end
    subgraph OUT["📤 Audit outputs"]
        R["access-review.md<br/>reviewer packet + sign-off"]
        S["access-review.csv<br/>Keep / Modify / Revoke"]
        E["evidence/*.json<br/>SHA-256 hashed"]
        O["OSCAL 1.1.2<br/>assessment results"]
    end
    A & B & C --> P --> I --> X
    K -. "what each server can do" .-> I
    M -. "NIST · SOC 2 · AI RMF · OWASP" .-> X
    X --> R & S & E & O

    classDef input fill:#e0f2fe,stroke:#0284c7,color:#0c4a6e
    classDef core fill:#ede9fe,stroke:#7c3aed,color:#3b0764
    classDef data fill:#fef3c7,stroke:#d97706,color:#78350f
    classDef output fill:#dcfce7,stroke:#16a34a,color:#14532d
    class A,B,C input
    class P,I,X core
    class K,M data
    class R,S,E,O output
  1. Discover. Point it at files or folders. It reads two formats:
    • MCP configs (Claude Desktop, Cursor, VS Code .vscode/mcp.json): local npx / uvx / docker servers and remote HTTP servers. These carry no owner or approval, which is exactly why they're the shadow-AI problem.
    • Agent manifests (agents.yaml): a governed record for LangChain, CrewAI or custom agents, with owner, approval, tools, scopes, credentials and last-used dates.
  2. Classify. An MCP config only says which server runs, not what it can do. The capability catalog turns a server name into a grant: actions, data classification, whether it ingests untrusted content and whether it can send data out. Unknown servers are flagged (AAR-12), never assumed safe.
  3. Redact, then hash. Secrets are masked during parsing, before anything is stored, so evidence can be shared with auditors. Each agent's inventory and redacted source record are hashed with SHA-256 over canonical JSON, so any later edit to the evidence is detectable.
  4. Review. Every tool grant gets a recommended decision (Keep / Modify / Revoke / Investigate) and an empty column for the reviewer, the same shape as a user access review spreadsheet.
  5. Export. OSCAL 1.1.2 assessment results: one observation per agent pointing at its evidence file and hash, and one finding per NIST 800-53 control objective.

The review cycle

It's the same quarterly user access review that SOX and SOC 2 auditors already test for people, run on agents:

flowchart LR
    D["1 · Discover<br/>configs + manifests"] --> C["2 · Classify<br/>capability catalog"]
    C --> T["3 · Test<br/>12 controls"]
    T --> R{"4 · Owner review<br/>per tool grant"}
    R -->|Keep| E["5 · Evidence<br/>hashed JSON + OSCAL"]
    R -->|"Modify / Revoke"| F["Remediate<br/>ticket + fix"]
    F -->|re-scan| T
    E --> Q["6 · Recertify<br/>every 90 days"]
    Q -.-> D

    classDef step fill:#e0f2fe,stroke:#0284c7,color:#0c4a6e
    classDef decision fill:#fef3c7,stroke:#d97706,color:#78350f
    classDef fix fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
    classDef done fill:#dcfce7,stroke:#16a34a,color:#14532d
    class D,C,T,Q step
    class R decision
    class F fix
    class E done
User access review (people) Agent access review (this tool)
HR feed lists every employee Configs and manifests list every agent and MCP server
Manager confirms each entitlement Agent owner marks each tool grant Keep / Modify / Revoke
Terminated users removed Unowned agents flagged (AAR-01), unused tools revoked (AAR-08)
Privileged access gets extra scrutiny Write, send, delete and shell access need a human gate (AAR-03, AAR-05)
Screenshots and spreadsheets as evidence Hashed JSON evidence and OSCAL output

Sample run

The bundled examples are a developer's Claude Desktop config, a VS Code MCP config and three governed agents. The full output is committed in sample-output/: the reviewer packet, the decision sheet, hashed evidence and OSCAL.

$ agent-access-review demo
AGENT                        TOOLS  HIGH   MED   LOW
support-copilot                  2     0     0     0
finance-ops-agent                4     4     3     0
devops-agent                     2     6     1     1
claude-desktop-config            6    11     5     1
vscode-mcp                       2     5     1     3

5 agents · 16 tool grants · 41 findings

%%{init: {"themeVariables": {"pie1": "#dc2626", "pie2": "#f59e0b", "pie3": "#16a34a", "pieSectionTextColor": "#ffffff", "pieStrokeColor": "#ffffff"}}}%%
pie showData title Findings by severity
    "High" : 26
    "Medium" : 10
    "Low" : 5
Control Agents failing
AAR-02 · Approved and recertified within 90 days 4 / 5
AAR-03 · Human approval for privileged actions 4 / 5
AAR-08 · Dormant access removed 4 / 5
AAR-01 · Accountable owner 3 / 5
AAR-04 · Least privilege 3 / 5
AAR-09 · No exfiltration path 3 / 5
AAR-05, 06, 07, 10, 12 2 / 5 each
AAR-11 · Encrypted transport 1 / 5
Excerpt from the reviewer packet: finance-ops-agent
Tool Actions Data Recommended Reviewer decision
netsuite read, write restricted Modify ☐ Keep ☐ Modify ☐ Revoke
outlook read, send confidential Modify ☐ Keep ☐ Modify ☐ Revoke
sharepoint read confidential Modify ☐ Keep ☐ Modify ☐ Revoke
expense-ocr read confidential Revoke ☐ Keep ☐ Modify ☐ Revoke
Check Severity Finding
AAR-09 high Exfiltration path: reads sensitive data, ingests untrusted content (outlook) and can send data out (outlook) with no human approval.
AAR-03 high netsuite can write restricted data without a human approving each action.
AAR-03 high outlook can send confidential data without a human approving each action.
AAR-04 high Over-broad access on sharepoint: Sites.Read.All.
AAR-02 medium Access was last approved 216 days ago by cfo-office (limit 90).
AAR-07 medium netsuite.NETSUITE_TOKEN was last rotated 315 days ago (limit 90).
AAR-08 medium expense-ocr has not been used for 164 days.

Some of what it finds:

  • finance-ops-agent reads vendor bills in NetSuite (restricted data), reads an inbox vendors can email (untrusted input) and can send email (egress), with no human approval. That's an AAR-09 exfiltration path: one crafted invoice email could get the agent to mail out vendor banking details. Its approval is also 216 days old, and its OCR tool hasn't been used in 164 days, so it's marked Revoke.
  • claude-desktop-config gives an agent the whole /Users/dev home directory, an unsandboxed terminal, a GitHub token and a database password in plain text, and runs four unpinned packages.
  • support-copilot passes every check: it writes to tickets, but a human approves before anything is sent.

CI regenerates sample-output/ on every push and fails if it differs from what's committed, so the sample always matches the current code.

How to read the results

Recommended decision (one per tool grant, in the packet and the CSV):

Decision Meaning What the owner does
Keep No findings on this tool Confirm it's still needed and sign off
Modify The access is needed but unsafe as configured Narrow scopes, add human approval, move secrets to a vault, pin the version
Revoke Unused for 90+ days Remove it; re-request if it's needed again
Investigate The tool isn't in the capability catalog, so its access can't be judged Find out what it can do, then add it to catalog.yaml

Severity: high means fix before the agent's next use (an unowned agent, plaintext secrets, an exfiltration path). Medium means fix within the review cycle (stale approval, unpinned package). Low means a gap in evidence rather than a risk (no usage logs, no rotation date).

The reviewer fills in the empty Reviewer decision column and the sign-off table. The completed packet plus the hashed evidence files are the audit evidence for the review.

Run it

Install from a release (shown in the Quick start), or work from source (dependencies are pinned exactly in requirements.txt):

git clone https://github.com/Mihirajmera/agent-access-review.git
cd agent-access-review
python -m venv .venv && source .venv/bin/activate     # Windows: .venv\Scripts\activate
pip install -r requirements.txt

python -m agent_access_review demo                    # writes review-demo/
pytest -q

scan options: --out DIR (default review/), --as-of YYYY-MM-DD (date used for recertification, rotation and dormancy), --fail-on high|medium|low (exit 1 if a finding is at or above that severity). agent-access-review --help lists examples.

As a CI gate

Keep agents.yaml in the repo that deploys your agents, and block merges that introduce high-risk access:

- run: pip install "git+https://github.com/Mihirajmera/agent-access-review@v0.2.0"
- run: agent-access-review scan agents.yaml --fail-on high

Pin to a release tag (or a commit SHA), not main, so a new version can't change your gate without review. That's control AAR-10 applied to this tool itself.

Design decisions

  • Agents are identities, not apps. The review is modeled on ITGC user access reviews (owner, approval, recertification, dormancy, credential hygiene) because that's the control framework auditors already test. AI-specific risks are added on top, not instead.
  • AAR-09 looks at combinations, not single permissions. Each leg of an exfiltration path is harmless alone. The risk only appears when one agent holds all three, which is why traditional permission reviews miss it. A human approval step on the untrusted-input or egress leg breaks the chain.
  • Fail closed on unknown tools. An unclassified MCP server is a finding, not a pass. The catalog is data, so a GRC team can extend it without touching code.
  • Redact before hashing. Evidence that contains secrets can't be shared, and redacting afterwards would break the hash. Redaction happens in the parser.
  • Docker tags count as unpinned. Only an image digest is immutable. :v1.0 can be re-pushed.

Limitations

  • It reviews configuration, not runtime behavior. It sees that an agent can send email, not what it actually sent. Usage dates come from the manifest, which in production would be fed from tool-call logs.
  • The capability catalog is approximate: it describes what a server can do by default, and a token's real scopes (for example, a fine-grained GitHub PAT) can be narrower. The manifest format lets you record exact scopes.
  • JSON-with-comments configs are skipped with a warning.

What I'd do at enterprise scale

  • Discover from endpoints, not files. Collect MCP configs from managed laptops through MDM or EDR, and agent identities from the IdP (service principals, OAuth apps), so shadow agents surface automatically.
  • Feed usage from logs. Populate last_used from MCP gateway or proxy logs so AAR-08 is evidence-based rather than self-reported.
  • Run the review in the GRC platform. Push the decision sheet into ServiceNow GRC or SailPoint as a certification campaign with owners, due dates and escalation, and auto-revoke grants that aren't certified.
  • Close the loop. Turn not-satisfied OSCAL findings into POA&M items with owners and due dates.

Contributing

The easiest way to help is to add an MCP server to the capability catalog: see CONTRIBUTING.md. Changes are listed in the CHANGELOG.

License

MIT

Metadata

Release files for agent-access-review 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agent-access-review 0.2.1
File Size Uploaded Provenance
agent_access_review-0.2.1.tar.gz 39.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for agent-access-review 0.2.1
File Interpreter ABI Platform
agent_access_review-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 70.6 kB

Release files / agent_access_review-0.2.1.tar.gz

Download URL agent_access_review-0.2.1.tar.gz
Size 39.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b4480f2f3499701ef92ce5ef81d04cdc34b5e9323b2261c8957e1b0c4f0e24ff
BLAKE2b-256 checksum
How to use checksums
2aea87e0f32f7683340362d19c4793646827e04c923f0f803097de700f72393a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / agent_access_review-0.2.1-py3-none-any.whl

Download URL agent_access_review-0.2.1-py3-none-any.whl
Size 31.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dbfa0817fbf6385d5bd76a9ed3346c95650df8fd24d9d714cd2a9259d876b43b
BLAKE2b-256 checksum
How to use checksums
0247291908b8164cb0d69ac4d7516dfe32eb36f45875f3433950937149aa6466
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Security for agent-access-review 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for agent_access_review-0.2.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page