Skip to main content

ScopeGuard

English | Turkish version

Changelog | Turkish release notes

Status: beta. ScopeGuard is a local-first security checking tool. It checks API authorization behavior and selected risks in source code, configuration, Dockerfiles, Kubernetes manifests, and Terraform files. It includes an offline request planner and coverage matrix, a read-only API scenario runner, offline source and Terraform checks, optional OSV dependency lookups, reasoned expiring suppressions, bilingual findings, and local JSON, Markdown, SARIF, and HTML reports with comparison support.

Current milestone

  • Local demo API binds to 127.0.0.1; the runner defaults to loopback targets.
  • All records and bearer tokens are synthetic.
  • GET /records/{id} enforces record ownership.
  • GET /vulnerable/records/{id} intentionally demonstrates a broken object-level authorization check.
  • scopeguard validate checks the OpenAPI and YAML scenario structure without network access.
  • scopeguard run executes only the configured, read-only GET, HEAD, and OPTIONS checks and writes a redacted JSON report.
  • scopeguard inspect scans selected local source, configuration, Dockerfile, Kubernetes, and Terraform patterns without executing code, building containers, or using the network.
  • API, local, and dependency findings can be saved as JSON, Markdown, SARIF 2.1.0, and self-contained HTML files at user-selected local paths. Reports stay local by default.
  • Dependency checks query OSV only when --allow-network is explicitly provided; only package names, ecosystems, and pinned versions are sent.
  • Suppressions require a rule, relative path pattern, reason, and expiry date; suppressed items remain visible in reports.
  • scopeguard compare reports added, resolved, and unchanged findings between saved JSON reports.
  • An optional GitHub Actions workflow scans source and uploads SARIF only after a manually dispatched run with the upload option enabled.
  • Remote targets require an exact HTTPS host/port allowlist in the config and an explicit --allow-remote flag at run time.

First scan (Windows)

Requires Python 3.11 or newer. Install ScopeGuard once using the pipx instructions, then:

  1. Open PowerShell in the project folder you want to inspect.
  2. Run scopeguard, choose 2. Project Security, then 1. Guided quick scan.
  3. Select the folder and a scan profile. ScopeGuard saves JSON, Markdown, SARIF, and HTML reports in the project folder.

To run the standard offline scan without opening the menu:

scopeguard quick-scan

Quick scans inspect supported files without executing project code or sending files over the network. To try API checks, start the synthetic demo in another terminal with scopeguard-demo; test real services only with explicit authorization.

Security checks and commands

Command What it checks or does Network use
init Creates scenarios for anonymous access, BOLA/IDOR, BFLA, or custom GET/HEAD/OPTIONS status checks. None
configure Saves a reusable local scan profile; stores no API credentials or targets. None
quick-scan Runs a saved profile or built-in local scan preset and writes local reports. None
inspect Scans local secrets, Python, configuration, Dockerfile, Kubernetes, and selected Terraform risks; writes local reports. None; source code is not run
validate Validates the OpenAPI document and scenario configuration. None
plan Shows the exact requests and identities in a scenario. None; tokens are not read
coverage Shows configured identity/endpoint pairs; --strict enforces required coverage. None; tokens are not read
run Sends configured read-only GET, HEAD, and OPTIONS checks to the scoped target and writes local reports. Yes, to the configured target only
dependencies Checks pinned versions in supported lockfiles against OSV; requires --allow-network. Yes; package names, ecosystems, and versions only
compare Compares two reports of the same type: API, local inspection, or dependencies. None
doctor Checks the installation and packaged demo inputs offline. None

The inspect checks are static heuristics, not a complete scanner. They do not test a live web service. API scenarios test only explicitly configured safe GET, HEAD, and OPTIONS operations and expected outcomes; they do not fuzz endpoints or infer the application's authorization policy.

Install and run

Requires Python 3.11 or newer. The recommended installation uses pipx to keep ScopeGuard isolated from other Python tools.

Windows PowerShell

If pipx is not installed:

py -m pip install --user pipx
py -m pipx ensurepath

Restart PowerShell after ensurepath, then install ScopeGuard:

pipx install scopeguard

Linux or macOS

Install pipx using the official pipx guide, then run:

pipx install scopeguard

Open the menu with scopeguard. From a project folder, scopeguard quick-scan starts the default offline scan. To update later, run pipx upgrade scopeguard.

If you do not want pipx, install into your Python user account and launch as a module:

py -m pip install --user scopeguard
py -m scopeguard

On Linux or macOS, use python3 -m pip install --user scopeguard and python3 -m scopeguard.

Contributors who need the source code can clone the repository and use py -m pip install . (or python3 -m pip install .). For an editable development install, use py -m pip install -e ..

Startup menu

Run `scopeguard` with no arguments (or double-click `ScopeGuard.bat` on Windows) to open the bilingual menu. It is organized into three sections:

  1. API Security — create a starter scenario, validate the OpenAPI and scenario files, preview requests, review identity/endpoint coverage, or run configured checks. API checks use the safe methods configured in the scenario.
  2. Project Security — the first option is Guided quick scan. Choose a project folder and scan preset to create local reports. This section also includes category-based local checks, secret detection, the opt-in online dependency check, reusable profiles, temporary suppressions, and report comparison.
  3. Advanced Tools — open the command console, read help, or view the installed version.

Choose `0` to go back or exit as shown. For your first scan, choose 2, then 1. You can also run `scopeguard quick-scan` directly from the project folder. Start the included demo with `scopeguard-demo` in a second terminal before using the API section.

When a default report filename already exists, the menu picks the next available numbered name. If you enter an existing report name yourself, ScopeGuard asks before overwriting it. Default reports and .scopeguard-profile.yaml are ignored by Git to keep local findings and machine-specific paths out of commits. Add custom report filenames to your .gitignore if needed.

The local inspection checks are heuristic and need human review. Use quoted paths containing spaces. The --version and --help options are also available from the normal command line.

Run without a virtual environment

On Windows, you can install ScopeGuard into your Python user account and start it as a module:

py -3 -m pip install --user .
py -3 -m scopeguard

This avoids a project .venv and a manual activation step. It installs dependencies into that Python account, so the automatic launcher above is preferred when you want ScopeGuard's dependencies isolated from other Python tools. Python 3.11 or newer is required.

Offline local source inspection

ScopeGuard can inspect local source, configuration, Dockerfile, and Kubernetes manifest files independently of API checks. It reads supported text files without executing them or making network requests. The starter checks look for credential-like hard-coded values, selected risky Python calls (such as eval, unsafe deserialization, shell-enabled subprocess calls, and disabled TLS verification), and configuration patterns such as debug mode or wildcard CORS, plus Dockerfile checks for root execution, mutable base image references, and credential-like ARG/ENV assignments, Kubernetes checks for selected Pod/Workload security fields including privileged containers, privilege escalation, root execution, host namespaces, hostPath mounts, and added ALL capabilities. Terraform checks use textual heuristics for selected AWS security-group, S3, database, and storage settings; they do not evaluate modules, expressions, provider plans, or cloud state. Kubernetes inspection is a static text-based heuristic; it does not contact a cluster or validate complete Kubernetes semantics. These heuristic findings need human review; this is not a complete vulnerability scanner.

Run all local inspection checks and save JSON, Markdown, SARIF, and HTML reports on your computer:

scopeguard inspect --path . --checks secrets python config docker kubernetes terraform --output inspect.json --markdown-output inspect.md --sarif-output inspect.sarif --html-output inspect.html --language en

Use --checks with one or more of secrets, python, config, docker, kubernetes, and terraform to choose categories. The docker check examines Dockerfiles offline for selected container hardening issues; it does not build images or contact registries. The kubernetes check applies static heuristics to YAML manifests for selected pod and container security settings; it does not connect to a cluster. ScopeGuard skips common virtual environment, dependency, and build folders, and ignores files larger than 1 MB. The reports contain file names and line numbers but omit source snippets and matched secret values. The optional SARIF 2.1.0 file maps finding severities to SARIF levels and includes descriptions and remediation. HTML output is self-contained and can be opened locally. All report formats stay on the selected local paths unless you opt into the workflow upload. The command returns exit status 1 when it finds findings; inspect the report and verify each result.

Try the safe, synthetic fixtures in examples/local-scan. They demonstrate expected findings across all six categories and list the rule IDs and severities. The fixture README explains the report evidence fields and remediation guidance. Findings are expected, so this sample command exits with status 1:

scopeguard inspect --path examples/local-scan/insecure-patterns --checks secrets python config docker kubernetes terraform --output local-scan.json --markdown-output local-scan.md --sarif-output local-scan.sarif --language en

For the safe comparison set, scan examples/local-scan/secure-patterns with the same options and different output filenames. It is expected to produce zero findings and exit with status 0.

Suppressions

Use a suppression file only for a reviewed finding that needs a temporary exception. Each entry needs an exact or globbed rule ID, a relative file path pattern, a non-empty reason, and an ISO date expiry. Expired entries make the suppression file invalid. Suppressed findings remain listed in JSON, Markdown, HTML, and SARIF reports, including the reason and expiry.

version: 1
suppressions:
  - rule_id: "terraform.public-ingress"
    path: "infra/network.tf"
    reason: "Temporary approved exception; access is restricted by the staging firewall."
    expires: "2026-12-31"

Pass it to either local or dependency scanning with --suppressions scopeguard-ignore.yaml. Suppressions affect only the matching rule and relative path.

Dependency vulnerability checks

Dependency scanning is a separate, online opt-in command. It reads exact versions from requirements*.txt, poetry.lock, Pipfile.lock, package-lock.json, npm-shrinkwrap.json, Cargo.lock, and go.sum, then queries OSV. It does not upload lockfiles or source code. The query sends package ecosystem, name, and version. Review your organization's data-sharing policy before using it on private projects. A pyproject.toml or package.json without a supported lockfile is not enough; generate or commit the lockfile with your package manager first.

scopeguard dependencies --path . --allow-network --output dependencies.json --markdown-output dependencies.md --sarif-output dependencies.sarif --html-output dependencies.html --language en

Without --allow-network, ScopeGuard does not make OSV requests. The command has size and package-count limits and reports advisory IDs, detected versions, severity when available, and fixed versions when listed. Unknown advisory severity stays marked unknown rather than being guessed.

HTML reports and comparison

The run, inspect, and dependencies commands can write a self-contained HTML report with --html-output report.html. It can be opened locally and does not load remote scripts or styles. Compare earlier and current JSON reports (API findings are matched by check and identity; local and dependency findings by rule and location/package):

scopeguard compare --previous previous.json --current current.json --output diff.json --markdown-output diff.md --html-output diff.html --open-report

The comparison lists added, resolved, and unchanged findings. Both input reports must be the same type (API, local inspection, or dependencies); ScopeGuard rejects mixed report types to avoid misleading results. It exits with status 1 when active findings were added; reports that remove findings return 0. It performs no network access.

GitHub Actions and optional SARIF upload

The .github/workflows/scopeguard-sarif.yml workflow scans the repository on pushes and pull requests. To publish SARIF to GitHub Code Scanning, start the workflow manually in the Actions tab and set upload_sarif to true. Upload is off by default; local CLI scans never upload. GitHub repository settings and plan must support Code Scanning.

Create a starter scenario interactively from an OpenAPI document:

scopeguard init --spec examples/api/openapi.yaml --output examples/scenarios/my-scenario.yaml

The wizard lets you select anonymous-access checks, BOLA/IDOR horizontal access checks, BFLA role checks, or custom safe-method status checks. The custom profile lists GET, HEAD, and OPTIONS operations from the OpenAPI document. It asks for sample path values and expected status codes and performs no API requests. Review the generated scenario before running it; the wizard cannot infer your authorization policy or prove that your expected responses are correct. Existing files are preserved unless you pass --force.

To start the included synthetic demo API, open a second terminal and run scopeguard-demo after installing from PyPI. From a source checkout, run py -m scopeguard_demo. If you started the repository launcher, use & .\.venv\Scripts\python.exe -m scopeguard_demo on Windows or ./.venv/bin/python -m scopeguard_demo on Linux/macOS:

py -m scopeguard_demo

The API listens on http://127.0.0.1:8000. Stop it with Ctrl+C. The interactive API menu resolves its bundled OpenAPI and scenario defaults when installed from PyPI. The command examples below that use examples/... paths are for a cloned source checkout.

In a second terminal, validate the example inputs:

scopeguard validate --spec examples/api/openapi.yaml --config examples/scenarios/local-demo.yaml

Validation is offline and sends no network requests. The scenario file stores environment variable names, never token values. Before running authenticated checks, set the synthetic credentials in the same PowerShell session:

$env:SG_USER_A_TOKEN = 'demo-user-a'
$env:SG_USER_B_TOKEN = 'demo-user-b'

Preview the exact requests before running them:

scopeguard plan --spec examples/api/openapi.yaml --config examples/scenarios/local-demo.yaml

plan is offline: it does not read token environment variables or send requests. It shows the target, resolved paths, identities, expected status codes, and JSON assertion pointers/operators. For a remote scenario it also reminds you that execution requires --allow-remote.

See which identity/endpoint combinations have checks configured:

scopeguard coverage --spec examples/api/openapi.yaml --config examples/scenarios/local-demo.yaml

The coverage matrix lists configured checks and marks empty identity/endpoint pairs as not configured. An empty cell is only a coverage gap in the scenario file; it is not evidence of a vulnerability. Declare required identity/endpoint pairs under coverage.required and exact check IDs under coverage.required_checks in the scenario YAML. scopeguard coverage --strict exits with status 1 if a required pair or check ID is missing, so CI can enforce both broad endpoint coverage and specific scenarios. This command is offline and does not read tokens.

CI severity gates

inspect and dependencies accept --fail-on any|critical|high|medium|low|none. The default, any, keeps the existing behavior and exits with status 1 when any active finding remains. A threshold fails only when an active finding has that severity or higher; suppressed findings do not fail the gate. For example, scopeguard inspect --path src --checks secrets python --fail-on high gates a build on high or critical source findings. Use --fail-on none to produce reports without using findings as the command exit gate. To gate only on newly introduced findings, save the previous JSON report and use scopeguard compare --previous baseline.json --current current.json; it exits 1 when new findings are present.

With the demo API still running, execute the checks in a second terminal:

scopeguard run --spec examples/api/openapi.yaml --config examples/scenarios/local-demo.yaml --output report.json

Add a shareable, redacted Markdown summary with --markdown-output report.md:

scopeguard run --spec examples/api/openapi.yaml --config examples/scenarios/local-demo.yaml --output report.json --markdown-output report.md

Choose the finding and report language with --language tr or --language en (default: en). The localized report includes a finding title, severity, evidence, potential impact, and remediation guidance. For example:

scopeguard run --spec examples/api/openapi.yaml --config examples/scenarios/local-demo.yaml --output report.json --markdown-output report.md --language tr

Optionally save findings in SARIF 2.1.0 format on your computer:

scopeguard run --spec examples/api/openapi.yaml --config examples/scenarios/local-demo.yaml --output report.json --sarif-output report.sarif --language tr

SARIF is written only to the path you specify. ScopeGuard does not upload reports or findings to GitHub or any other service.

In the interactive sg> console, use the same options after run. Commands work both as run ... and scopeguard run ....

The protected route checks cover anonymous denial (401), both users reading their own records (200), and each user being denied the other user's record (404). Those six checks should pass. The deliberately vulnerable route is expected to fail because it returns 200 where the scenario expects 404 and its JSON /owner assertion indicates cross-user access. The local demo therefore reports six passes and one intentional failure; scopeguard run exits with status 1 to make the detected issue visible. Reports include a localized explanation, severity, evidence, potential impact, and remediation advice. They omit response bodies, assertion values, and token values.

An assertion can be attached to a check like this:

assert_json:
  - pointer: /owner
    not_equals: user-a

equals requires the JSON Pointer to exist and match; not_equals also passes when the pointer is absent, as it is in the protected route's 404 response.

Run the automated tests

The unit tests validate malformed/out-of-scope configuration. Integration tests start the synthetic API on a temporary loopback port and verify access-control results and report redaction.

py -m unittest discover -s tests -v

GitHub Actions runs the test suite and example validation on Python 3.11 and 3.13 for every push and pull request.

Synthetic accounts and endpoints

User A owns record-a; User B owns record-b. These demo tokens are public fixtures and must never be reused anywhere else.

Invoke-RestMethod -Headers @{ Authorization = 'Bearer demo-user-a' } -Uri 'http://127.0.0.1:8000/records/record-a'
Invoke-RestMethod -Headers @{ Authorization = 'Bearer demo-user-b' } -Uri 'http://127.0.0.1:8000/records/record-a'
Invoke-RestMethod -Headers @{ Authorization = 'Bearer demo-user-b' } -Uri 'http://127.0.0.1:8000/vulnerable/records/record-a'

Each user receives 200 for their own record and 404 for the other user's record from the protected route. Anonymous requests to records receive 401. User B receives 200 for User A's record from the intentionally vulnerable route.

Authorized staging targets

Loopback remains the default. To validate a staging scenario, set an exact hostname and port, opt in in the config, and keep HTTPS certificate verification enabled:

target:
  base_url: https://staging.example.test
  allowed_hosts:
    - staging.example.test
  allowed_ports: [443]
  allow_remote: true
  max_requests: 10
  timeout_seconds: 5
  follow_redirects: false

staging.example.test is a reserved example name. Replace it only with a system you own or are explicitly authorized to test. A remote run also requires the explicit command-line flag:

scopeguard run --spec examples/api/openapi.yaml --config examples/scenarios/staging.yaml --output report.json --allow-remote

Remote targets must use HTTPS, the exact base hostname must be the only allowlisted hostname, and the configured port must be listed. Wildcards are rejected. validate remains offline; without --allow-remote, run refuses the remote target before sending a request.

Safety

This is a deliberately vulnerable teaching fixture. Keep it bound to loopback and use only the synthetic data included here. Do not expose it to a network or use real credentials or data. The runner uses loopback by default; a remote target needs config and command-line opt-in, an exact hostname and port allowlist, HTTPS, and an authorized test scope. It sends only explicitly configured GET, HEAD, and OPTIONS requests, does not follow redirects, limits request count and rate, and does not save response bodies.

Project plan

See the architecture and roadmap.

License

This project is licensed under the MIT License. See LICENSE.

Metadata

Release files for scopeguard 0.2.2

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

Source distribution (sdist)

Source distribution for scopeguard 0.2.2
File Size Uploaded Provenance Actions
scopeguard-0.2.2.tar.gz 87.3 kB With provenance Details for scopeguard-0.2.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for scopeguard 0.2.2
File Interpreter ABI Platform Actions
scopeguard-0.2.2-py3-none-any.whl Python 3 none any Details for scopeguard-0.2.2-py3-none-any.whl

Total release size: 172.1 kB

Release files / scopeguard-0.2.2.tar.gz

Download URL scopeguard-0.2.2.tar.gz
Size 87.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a7dba84d19c74bfd4e24eb311fa5812dfca4ddbe295ea2219f3365fe5cee8eb8
BLAKE2b-256 checksum
How to use checksums
6e90bd703996ee0920015431ccea5deb413b4e3bf38d7e354cf1541cc32906a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Nov 3, 2026.

Transparency log

Release files / scopeguard-0.2.2-py3-none-any.whl

Download URL scopeguard-0.2.2-py3-none-any.whl
Size 84.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6674412f20daca86a21a928bad965b9c99fdf10dd0634378f5751c1354744965
BLAKE2b-256 checksum
How to use checksums
72b49dad023de3f569b7d15a09e25282f2ee7257bbf2c6c63ab2ec53ea0adccf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Nov 3, 2026.

Transparency log

Security for scopeguard 0.2.2

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 scopeguard-0.2.2.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 Nov 3, 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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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