agentsec · Tools · scopefit

Offline · stdlib-only · MIT

scopefit: detect over-privileged GitHub tokens used by agents in AI agents


Offline least-privilege checker for GitHub tokens used by AI agents.

What it detects

Offline least-privilege checker for GitHub tokens used by AI agents.

You give scopefit two things:

  1. What the token was granted. You type or paste this yourself. Two formats work: a fine-grained PAT / GitHub App permission map, or a classic OAuth scope list.
  2. What the agent actually called. Either an agent transcript (JSON/JSONL) or a plain list of endpoints.

scopefit works out which permissions the observed GitHub REST calls need, using a bundled endpoint→permission mapping. It then reports:

It is a single file of stdlib-only Python with no dependencies, and it makes no network calls.

Rules

OptionMeaning
-g/--grants FILEGranted permissions (see formats below)
-c/--calls FILETranscript (JSON/JSONL) or endpoints text; repeatable
`--grant-type auto\fine\
`--calls-format auto\transcript\
--public-reposUse the classic scopes for public repos
--mapping FILEUse an alternate mapping JSON
--jsonMachine-readable output
`--fail-on over\missing\

Usage

# classic token vs. an agent transcript
python3 scopefit.py --grants examples/classic_overprivileged_scopes.json --calls examples/agent_transcript.jsonl

# fine-grained grant vs. an endpoint list, JSON output, fail only on missing permissions
python3 scopefit.py -g examples/fine_grained_tight.json -c examples/endpoints.txt --json --fail-on missing

After pip install of the kit, the same options work as agentsec scopefit …. Every tool also accepts --help and almost every tool accepts --json.

Example output

The over-privileged classic token in examples/ checked against a fake triage-agent transcript (exit code 1):

The same transcript checked against examples/fine_grained_tight.json: 0 over-granted, 0 missing, exit 0.

scopefit 0.1.0 - grant type: classic OAuth scopes
Observed calls: 8 (mapped 6, unmapped 1, graphql 1)

ENDPOINTS USED (deduplicated):
  METHOD  ENDPOINT                                              FINE-GRAINED                       CLASSIC  N
  ------  ----------------------------------------------------  ---------------------------------  -------  -
  GET     /repos/{owner}/{repo}/issues                          issues:read, metadata:read         repo     1
  POST    /repos/{owner}/{repo}/issues/{issue_number}/labels    issues:write, metadata:read        repo     1
  GET     /repos/{owner}/{repo}/pulls/{pull_number}             metadata:read, pull_requests:read  repo     1
  GET     /repos/{owner}/{repo}/commits/{ref}/status            metadata:read, statuses:read       repo     1
  POST    /repos/{owner}/{repo}/issues/{issue_number}/comments  issues:write, metadata:read        repo     1
  GET     /repos/{owner}/{repo}/contents/{path+}                contents:read, metadata:read       repo     1

OVER-GRANTED:
  SCOPE            WHY
  ---------------  ------------------------------
  admin:org        never needed by observed calls
  admin:repo_hook  never needed by observed calls
  delete_repo      never needed by observed calls
  gist             never needed by observed calls
  user             never needed by observed calls
  workflow         never needed by observed calls

MISSING (needed but not granted):
  (none)

HIGH-RISK GRANTS:
  GRANT            USED  RISK
  ---------------  ----  ----------------------------------------------------------------------
  admin:org        NO    full control of organizations, teams and memberships
  admin:repo_hook  NO    can create/delete repo webhooks (exfiltration channel)
  delete_repo      NO    can permanently delete repositories
  repo             yes   full read/write to ALL private repositories the user can access
  user             NO    can modify the user profile
  workflow         NO    can modify GitHub Actions workflows (CI code execution, secret access)

UNMAPPED ENDPOINTS (unknown to scopefit; permissions NOT guessed - check GitHub docs):
  METHOD  ENDPOINT                             N
  ------  -----------------------------------  -
  GET     /repos/{owner}/{repo}/traffic/views  1
  note: 1 GraphQL call(s) seen; GraphQL is NOT analyzed.

SUGGESTED MINIMAL GRANT (observed usage only):
  ["repo"]
  (fine-grained alternative, preferred: {"contents": "read", "issues": "write", "metadata": "read", "pull_requests": "read", "statuses": "read"})
  WARNING: unmapped/GraphQL calls may need more than this suggestion.

Summary: 6 over-granted, 0 missing, 6 high-risk, 1 unmapped.
Mapping is a best-effort SUBSET from GitHub docs and may be out of date; future runs may need more.
Policy --fail-on any: FAIL

SARIF and CI

agentsec scopefit path/to/input --json > scopefit.json
# scopefit does not yet emit SARIF; use --json and keep --fail-on for CI.

# GitHub Actions (composite action ships with the repo)
- uses: dunkleschitz/agentsec@v0
  with:
    tools: scopefit
    paths: path/to/input
    fail-on: high

--sarif is not available on this tool yet (resultguard and toolpoison are reserved as good first issues). Use --json and a --fail-on exit gate instead.

OWASP mapping

Heuristic mapping of what this tool helps a reviewer look for. Not an official OWASP endorsement, and not complete coverage of any item. Sources: OWASP Top 10 for LLM Applications 2025 and OWASP Top 10 for Agentic Applications 2026.

Known limits

Full source, tests, and fixtures: tools/scopefit/ in the repository. Install the kit with pip install git+https://github.com/dunkleschitz/agentsec.git.