Trace taint across your entire codebase. Before attackers do.
PySpector is a graph-based SAST framework for modern Python. A Rust analysis core builds the call graph and control flow graph of your project, then propagates taint from sources to sinks across function boundaries, at an average of 25,000 lines/second.
Traditional scanners grep for patterns. PySpector understands the structure of your application: its control flow, its call graph, and the path untrusted data takes through both.
Flow-sensitive analysisA Control Flow Graph tracks variable states sequentially, distinguishing safe code paths from vulnerable ones, instead of flagging everything that merely looks risky.
Inter-procedural taint trackingUntrusted data is propagated across function boundaries with global fixed-point iteration and context-aware function summaries that map parameters to return values.
Rust-native performanceThe core engine is compiled Rust with rayon parallelization across every available core, built for CI/CD pipelines and 500k+ LoC monorepos.
Multi-engine hybrid scanningThree engines in one pass: a regex engine for secrets and config errors, an AST engine for structural anti-patterns, and a graph engine for full data-flow chains.
AI-agent security rulesA specialized --ai ruleset finds prompt injection, insecure tool use, and data leakage in LLM-integrated Python applications and agent frameworks.
Supply-chain auditingThe --supply-chain mode checks project dependencies against known CVEs, so the code you import is held to the same standard as the code you write.
Extensible plugin systemPost-process findings, generate artifacts, or trigger automation, inside a trust model with checksums, AST inspection, and explicit opt-in execution.
SARIF & CI/CD nativeFirst-class SARIF 2.1.0 export plugs directly into GitHub Code Scanning, security dashboards, and DevSecOps aggregation pipelines.
Interactive triage & baseliningA built-in TUI lets you review findings, suppress accepted risk, and save a baseline so reviewed issues never resurface in future scans.
Core Engine
From source file to finding, in four stages.
A hybrid architecture: a flexible Python CLI orchestrates the workflow, while a memory-safe Rust core (bridged via pyo3) does the heavy lifting in parallel.
PYTHON
STAGE 01
AST Parsing
Source is parsed with the native ast module into a structured JSON AST, ready for semantic analysis.
RUST
STAGE 02
Call Graph Construction
A project-wide map of function definitions and call sites enables true cross-file, inter-procedural analysis.
RUST
STAGE 03
CFG Generation
Every function is decomposed into a Control Flow Graph, capturing order of operations and conditional logic.
RUST
STAGE 04
Fixed-Point Taint Propagation
A worklist algorithm propagates taint from sources to sinks, respecting sanitizers that clean data along the way.
Benchmarks
Measured against the tools you already run.
Head-to-head against Bandit and Semgrep with identical configurations, across five major Python codebases (Django, Flask, Pandas, Scikit-learn, Requests) from 13k to 530k lines of code.
Throughput: lines analyzed per second
PySpector25,607 l/s
Bandit14,927 l/s
Semgrep1,538 l/s
Debian-based Linux VM (2 cores, 4 GB RAM). Values are averages over multiple runs with CPU settling periods between executions. Raw benchmark data is available in the repository for reproducibility.
Comparative profile
Metric
PySpector
Bandit
Semgrep
Relative speed
71% faster
baseline
16.6× slower
Memory usage
1.4 GB avg
111 MB avg
277 MB avg
CPU utilization
120% multi-core
100% single
40%
Analysis depth
Graph + Taint + AST + RegEx
AST patterns
Patterns
PySpector trades a larger memory footprint for full graph construction and multi-core saturation. Recommended: 4+ cores and 4+ GB RAM for large codebases; 2 cores / 2 GB minimum.
Documentation
Everything you need, from first scan to custom plugins.
The complete PySpector reference: installation, CLI, scan modes, taint concepts, output formats, triage, automation, custom rules, and the plugin SDK.
Start here · 01
Installation
PySpector ships on PyPI as a hybrid Python/Rust package. The Python CLI orchestrates scans; the Rust core performs the analysis.
Prerequisites
Requirement
Version
Notes
Python
3.9 to 3.14
A dedicated Python 3.14 virtual environment is highly recommended.
Rust toolchain
stable
Required for the analysis core. Install via rustup, then verify with cargo --version.
Hardware
2+ cores, 2 GB RAM
4+ cores and 4+ GB RAM recommended for large codebases. SSD recommended for big repos.
# Download Python 3.14 from the Microsoft Store, then:PS> python3.14 -m venv venv
PS> .\venv\Scripts\Activate.ps1
# or, depending on the installation source:PS> .\venv\bin\Activate.ps1
Install from PyPI
bash
$ pip install pyspector
Verify the install by running pyspector --help. If the Rust core fails to build, confirm cargo --version works inside the same shell session.
Start here · 02
Your first scan
The primary command is scan. It accepts a local file, a directory, or a remote Git repository.
bash
$ pyspector scan [PATH or --url REPO_URL] [OPTIONS]
Common invocations
bash
# Scan a local file or directory$ pyspector scan /path/to/your/project
# Scan and save the report as HTML$ pyspector scan /path/to/your/project -o report.html -f html
# Scan a public GitHub repository directly$ pyspector scan--urlhttps://github.com/username/repo.git
Wizard mode
New to SAST, or running PySpector in a classroom? The --wizard flag launches a guided, interactive scan setup, ideal for first-time users and students.
bash
$ pyspector scan--wizard
Reading the results
Findings are reported with a severity, a rule ID, the file and line, and (for graph-engine findings) the full taint path from source to sink. Severities map to the following scale:
CRITICALHIGHMEDIUMLOWINFO
Use a severity threshold to keep noise out of CI, and the triage workflow to baseline accepted findings.
Start here · 03
Taint analysis concepts
PySpector's graph engine models your application as data flowing between three kinds of program points. Understanding them makes findings (and false-positive triage) much easier to reason about.
Sources
Where untrusted data enters: HTTP parameters like request.args, environment input, file reads, CLI arguments, LLM outputs.
Functions that neutralize taint along the way: escaping, parameterization, allow-listing. Paths through a sanitizer are not reported.
How a finding is produced
Parse: each Python file is converted to a JSON AST by the CLI and handed to the Rust core via pyo3.
Map: the engine builds a project-wide call graph, so a value returned by a helper in utils.py is connected to its caller in views.py.
Model: every function becomes a Control Flow Graph: the analysis knows that an if branch which sanitizes input makes that branch safe, while the else branch may not be.
Propagate: a worklist algorithm iterates to a global fixed point, pushing taint through assignments, calls, and returns using context-aware function summaries.
Report: any taint that reaches a sink without passing a sanitizer becomes a finding, with the complete source → sink path attached.
Why flow-sensitivity matters: pattern-based tools flag every call to subprocess.run with a variable argument. PySpector only reports it when an actual untrusted value can reach it on at least one execution path.
Reference · 01
CLI reference
PySpector exposes four top-level commands: scan, watch, triage, and plugin.
pyspector scan
Option
Description
PATH
Local file or directory to analyze.
-u, --url REPO_URL
Clone and scan a public GitHub or GitLab repository instead of a local path (other hosts are rejected).
-f, --format
Report format: json, html, or sarif. Defaults to terminal output.
-o, --output
Write the report to a file instead of stdout.
--wizard
Interactive guided scan mode for first-time users.
--ai
Enable the AI/LLM security ruleset (prompt injection, insecure tool use, data leakage).
--supply-chain
Check project dependencies for known CVEs.
--plugin NAME
Run a trusted plugin after the scan. Repeatable.
--plugin-config FILE
JSON file with per-plugin configuration blocks.
-s, --severity LEVEL
Minimum severity to report: LOW (default), MEDIUM, HIGH, or CRITICAL.
-c, --config FILE
Path to a pyspector.toml configuration file (overrides defaults).
--syntax-warnings
Treat Python SyntaxWarnings as errors and exclude the affected files.
--stats
Print a performance and findings statistics table after the scan (LoC/sec, memory, per-engine breakdown, top rules and files).
--list-plugins
List all available plugins and exit.
--debug
Show all informational and progress messages; without it only findings, warnings, and errors are printed.
pyspector watch
Continuous watch mode: PySpector runs a full initial scan, then re-scans whenever a .py file is created, modified, or deleted, printing only the NEW and RESOLVED findings after each pass.
Option
Description
PATH
File or directory to watch.
--debounce SECONDS
Wait this long after the last change before re-scanning (default: 1.0).
-s, --severity / --ai / -c, --config
Same semantics as scan.
bash
$ pyspector watch ./src --severity MEDIUM --debounce 2
pyspector triage
Usage
Description
pyspector triage report.json
Open the interactive triage TUI on a previously generated JSON report.
pyspector plugin
Subcommand
Description
plugin list
Show discovered plugins with trust status, version, and author.
plugin trust NAME
Validate, checksum, and mark a plugin as trusted.
plugin info NAME
Display stored metadata and checksum verification status.
plugin install PATH [--trust]
Install a plugin file, optionally trusting it in the same step.
plugin remove NAME
Remove a plugin from the local catalogue.
Configuration file (pyspector.toml)
Project-level settings live under [tool.pyspector] and are loaded with -c pyspector.toml. Anything you set merges on top of the defaults:
Sensible exclusions ship by default (.venv, .git, __pycache__, build, dist, node_modules, vendor, and common test-fixture patterns). PySpector also writes a .pyspector_cache directory next to the scan target: an incremental AST cache (plain JSON, never pickle) that makes repeat scans dramatically faster. It is safe to delete at any time and should stay out of version control.
Reference · 02
Scan modes
AI / LLM security mode
Use --ai when scanning projects that integrate with Large Language Models or agent frameworks. The specialized ruleset targets the failure modes unique to AI applications: prompt injection paths, insecure tool invocation, and unintended data leakage into prompts or logs.
bash
$ pyspector scan /path/to/your/project --ai
Supply-chain mode
Use --supply-chain to check the dependencies declared by your project against known CVEs: a fast first pass on the code you import rather than the code you wrote.
Point PySpector at any public GitHub or GitLab repository and it will clone and analyze it in one step, useful for auditing third-party packages before adoption, or for security research at scale. The URL host is validated, so only github.com and gitlab.com repositories are accepted.
Scan responsibly. Only scan repositories you own or are authorized to assess. Findings in third-party code should go through that project's own disclosure process.
Reference · 03
Reports & SARIF
Select the output format with -f and a destination with -o. Three formats are supported, each suited to a different consumer:
SARIF (Static Analysis Results Interchange Format) is the lingua franca of security tooling. PySpector results integrate directly with GitHub Code Scanning, GitHub Advanced Security, and any SAST aggregation platform.
# Generate SARIF, then upload to GitHub Code Scanning$ pyspector scan ./project -f sarif -o report.sarif
Reference · 04
Triage & baselining
Real codebases accumulate accepted risk. The triage workflow lets you review findings once, mark them as ignored, and never see them again in subsequent scans.
bash
# 1. Generate a JSON report$ pyspector scan /path/to/your/project -o report.json -f json
# 2. Open the interactive triage TUI$ pyspector triage report.json
Inside the TUI
Key
Action
↑ / ↓
Navigate between findings.
i
Toggle the "ignored" status of the selected finding.
s
Save changes to .pyspector_baseline.json.
The baseline file is loaded automatically on subsequent scans, so already-reviewed findings stay suppressed across your whole team and CI pipeline. Commit it alongside your code.
Extend · 01
Plugin system
Plugins post-process findings, generate custom artifacts, or orchestrate follow-up actions after every scan. They run in-process once the Rust core returns the final issue list, so they see exactly the same normalized data that drives the built-in reports.
Lifecycle
Discovery: plugin files live in the repository's PySpector/plugins directory and are discovered automatically.
Registration: trusted plugins are recorded in plugin_registry.json with their checksum and metadata.
Validation: before execution, PySpector validates plugin configuration, statically inspects the source for dangerous APIs, and verifies the on-disk checksum.
Execution: the plugin is initialized, receives the full findings list, and may emit additional files or data. cleanup() is always called at the end.
Managing plugins from the CLI
bash
$ pyspector plugin list # discovered plugins, trust status, version, author$ pyspector plugin trust plugin_name # validate, checksum, mark as trusted$ pyspector plugin info plugin_name # metadata + checksum verification$ pyspector plugin install path/to/plugin.py --trust$ pyspector plugin remove legacy_plugin
Only trusted plugins are executed automatically. When you trust a plugin, PySpector calculates its SHA256 checksum and stores the version, author, and description it declares via PluginMetadata. If the file is modified later, you are warned before it runs again.
AST-based static inspection blocks dangerous constructs (eval, exec, subprocess.*) and warns on sensitive-but-acceptable calls like open.
Trust workflow: a plugin must be explicitly trusted before it can run; validation warnings are surfaced in the CLI.
Checksum verification: each trusted plugin has a stored SHA256 hash; any change is flagged before execution.
Argument isolation:sys.argv is reset so Click-based plugins can't accidentally consume the parent CLI arguments.
Structured error handling: exceptions are caught, traced, and reported without aborting the main scan; cleanup() still runs.
Review before you trust. Plugins run with your privileges. Always read third-party plugin code before running pyspector plugin trust or installing with --trust.
Extend · 02
Authoring plugins
Create a Python file in ~/.pyspector/plugins/<name>.py and subclass PySpectorPlugin:
python · my_plugin.py
from pathlib import Path
from typing import Any, Dict, List
from pyspector.plugin_system import PySpectorPlugin, PluginMetadata
classMyPlugin(PySpectorPlugin):
@propertydefmetadata(self) -> PluginMetadata:
returnPluginMetadata(
name="my_plugin",
version="0.1.0",
author="Your Name",
description="Summarises HIGH severity findings",
category="reporting",
)
defvalidate_config(self, config: Dict[str, Any]) -> tuple[bool, str]:
if"output_file"not in config:
returnFalse, "output_file is required"returnTrue, ""definitialize(self, config: Dict[str, Any]) -> bool:
self.output = Path(config["output_file"]).resolve()
returnTruedefprocess_findings(self, findings, scan_path, **kwargs) -> Dict[str, Any]:
highs = [f for f in findings if f.get("severity") == "HIGH"]
self.output.write_text(f"{len(highs)} HIGH findings\n", encoding="utf-8")
return {
"success": True,
"message": f"Summarised {len(highs)} HIGH findings",
"output_files": [str(self.output)],
}
Required interface
Member
Required
Purpose
metadata
Yes
Return a PluginMetadata instance describing the plugin.
validate_config(config)
Recommended
Abort gracefully when required settings are missing by returning (False, "reason").
initialize(config)
Yes
Prepare state or dependencies; return False to skip execution.
process_findings(...)
Yes
Receive every finding as a dict; return success, message, optional data, and output_files.
cleanup()
Optional
Release resources; called even if an exception occurs.
Best practices
Store API keys and long-lived secrets in environment variables and read them during initialize; give helpful errors when credentials are missing.
Keep side-effects inside the scan directory. When scanning a single file, scan_path is that file, so switch to scan_path.parent before writing outputs.
Validate configuration early with validate_config; PySpector surfaces the message in the CLI without executing the plugin.
Return meaningful message values and populate output_files so automation can pick up generated artifacts.
Support a dry_run switch (see the bundled aipocgen plugin) for air-gapped testing.
Tip: plugins are plain Python modules, so you can run python my_plugin.py while developing for quick checks before trusting them through the CLI.
Extend · 03
Writing custom rules
Rules define what the engine looks for. They live as TOML files in src/pyspector/rules/, are loaded at runtime, and are applied uniformly across every scanned file. There are three kinds:
regex patternFast line-level matching for secrets, misconfigurations, and simple anti-patterns. Define a pattern regular expression.
ast_matchStructural matching against Python AST nodes, e.g. Call(func.id=eval), for precise detection that text search cannot express.
taint source / sink / sanitizerTeach the flow engine new [[taint_source]], [[taint_sink]], and [[taint_sanitizer]] entries so untrusted data is tracked across functions.
A minimal AST rule looks like this:
toml · built-in-rules.toml
[[rule]]id = "PY200"description = "Use of eval() detected."severity = "High"remediation = "Avoid eval(). Use ast.literal_eval or explicit parsing."ast_match = "Call(func.id=eval)"
Useful fields when authoring rules:
Field
Applies to
Purpose
id
all
Unique identifier surfaced in every report.
description / severity
all
Human-readable summary and one of Low, Medium, High, Critical.
remediation / cwe
all
Fix guidance and an optional CWE identifier (used for SARIF tags and cross-rule dedup).
exclude_pattern / file_pattern
rules
Suppress on lines matching a regex, or restrict the rule to matching file globs.
function_call / vulnerable_parameter_index
sinks
The call to watch and which positional argument must be tainted to fire.
is_method / triggers_on
sinks
Whether the sink is a method call, and which taint origins should trigger it.
New rules are welcome through the contribution flow below. Include a clear description, a severity, and helpful remediation advice with every rule you add.
Extend · 04
CI/CD & automation
PySpector is built for pipelines: fast enough to run on every commit, SARIF-native for platform integration, and shipped with helper scripts for local guardrails.
GitHub Code Scanning
Generate SARIF in your workflow and upload it so findings appear directly in pull requests and the repository security dashboard:
Block commits that introduce new HIGH or CRITICAL issues. The setup script creates an executable .git/hooks/pre-commit that scans staged Python files:
bash
# From the root of your Git repository:$ ./scripts/setup_hooks.sh
# Bypass for a specific commit if you must:$ git commit--no-verify
pre-commit framework
If your team uses the pre-commit framework, add PySpector as a local hook so it runs on staged Python files alongside your other checks:
yaml · .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: pyspector
name: PySpector SAST
entry: pyspector
args: ["scan", "."]
language: system
types: [python]
The bundled ./scripts/setup_hooks.sh takes the stricter route: it installs a raw Git hook that scans only the staged files with --severity HIGH and blocks the commit on any HIGH or CRITICAL finding (bypass with git commit --no-verify).
Scheduled scans with cron
For continuous monitoring outside CI, an interactive script generates the right crontab entry for your project:
bash
$ ./scripts/setup_cron.sh
REST API & Docker
PySpector also ships a small Rust HTTP service (pyspector-api, built on actix-web) that exposes scanning over the network. It accepts POST /scan on port 10000 with a JSON body and is rate-limited (12 requests/second, burst of 5):
The body takes either url (a public repo to clone) or path (a server-side directory), plus the ai and json_output booleans. A Dockerfile is included to build and run the service in a container:
Every contribution helps make Python code safer: bug reports, feature ideas, new detection rules, documentation, and improvements to the Python or Rust core are all welcome. The full guide lives in CONTRIBUTING.md, and the project follows a Contributor Covenant code of conduct.
Development setup
You need Python 3.9+ (3.14 recommended) and the Rust toolchain via rustup. Installing in editable mode compiles the Rust engine and lets you iterate without reinstalling:
bash
# Fork PySpector, then clone your fork:$ git clone https://github.com/YOURUSERNAME/PySpector.git
$cd PySpector
$ python3.14 -m venv venv &&source venv/bin/activate
$ pip install-e . # compiles the Rust core$ pyspector --help
Before opening a PR
Run the test suite and the quality gates; the same checks run in CI and as pre-commit hooks:
bash
$ python -m unittest discover tests/unit -v# unit tests$ ruff check src/ && ruff format src/ # lint + format$ mypy src/ # type checks
Then create a feature branch, commit with a clear message (the repo uses conventional commits, e.g. feat: add rule for insecure cookie settings), push to your fork, and open a pull request describing what you changed. Adding new detection rules (see Writing custom rules) is one of the highest-impact ways to contribute.
Project · 02
Frequently asked questions
Why is my scan slow?
If your scan is slow, it's probably because you aren't using PySpector, but rather something else (xD). Jokes apart: scan time grows with the codebase (a 500k LoC project takes longer than a 10k one), but benchmarks consistently show PySpector outpacing other Python SASTs on the same workloads.
Do I need Rust installed to use PySpector?
Yes. PySpector includes a Rust analysis core, so local installation from source requires the Rust toolchain. Install it with rustup, then verify with cargo --version before installing or building PySpector.
What can I scan?
A local Python file, a local project directory, or a public Git repository URL: pyspector scan ./my-python-project or pyspector scan --url https://github.com/username/repo.git.
How do I choose the report format?
Use -f to select json, html, or sarif, and -o to write the report to a file, for example pyspector scan ./project -f sarif -o report.sarif.
How should I handle false positives?
Generate a JSON report, open the triage TUI with pyspector triage report.json, mark findings as ignored with i, and save the baseline with s. Future scans load the baseline automatically so reviewed findings don't reappear.
Are plugins safe to run?
Only trusted plugins are executed automatically. PySpector validates plugin source, records a checksum when you trust a plugin, and warns you if the file changes later. Always review third-party plugin code before trusting it.
When should I use the AI and supply-chain modes?
Use --ai for projects that integrate with LLMs or AI agents; use --supply-chain to check dependencies for known CVEs. They can be combined in a single scan.
How do I integrate PySpector into CI?
Generate SARIF with -f sarif and upload it to a compatible platform such as GitHub Code Scanning. For local guardrails, run ./scripts/setup_hooks.sh to install the pre-commit hook.
Does my code ever leave my machine?
No. All analysis (AST parsing, call graph, taint propagation) runs locally in the Rust core. Two optional features touch the network: --supply-chain sends only dependency names and versions to the OSV.dev API, and --url clones the target repository locally before scanning it. Third-party plugins like aipocgen call external APIs only if you configure them, and support dry_run for fully offline use.
Can PySpector re-scan automatically while I code?
Yes: pyspector watch ./src runs a full initial scan, then re-scans whenever a .py file changes, printing only the NEW and RESOLVED findings. Tune the delay with --debounce SECONDS.
How do I exclude files or directories from a scan?
Add an exclude list under [tool.pyspector] in a pyspector.toml and pass it with -c. Common noise (.venv, node_modules, build artifacts, test fixtures) is already excluded by default, and reviewed findings can be silenced permanently with a triage baseline.
Can I write my own detection rules?
Yes. Rules are plain TOML: regex rules for textual patterns, ast_match rules for structural patterns, and taint sources/sinks/sanitizers for data-flow rules. See Writing custom rules for the format and a complete example.
What is the .pyspector_cache directory?
An incremental AST cache that makes repeat scans much faster by re-encoding only the functions that changed. It is generated automatically, stored as JSON (never pickle, so nothing executable), safe to delete at any time, and should stay out of version control.
How can I contribute?
Report bugs, suggest enhancements, add detection rules, or improve the Python/Rust core. The Contributing section covers the dev setup and PR checklist, and the full guide lives in CONTRIBUTING.md.
We hold our own code to the standard we scan others against. Valid security research deserves meaningful recognition, including a CVE requested on your behalf through GitHub's CNA partnership.
How to report
All security issues must be reported privately through GitHub Security Advisories. This keeps disclosure private until a fix ships, enables direct collaboration with maintainers, and lets us formally request a CVE for you. If you can't use GitHub Advisories, email pyspector@protonmail.com (responses may be slower).
A strong report includes: a concise descriptive title, a summary of the flaw and its impact, a non-simulated PoC (Python, Bash, or Rust preferred), a CVSS v3.1 vector string, the most applicable CWE identifier(s), and the affected version range (ecosystem pip, package pyspector). We aim to acknowledge within 48 hours and provide a status update within 7 days.
Recognition & incentives
CVE assignment: formally requested on your behalf through GitHub's CNA partnership: a permanent, citable record of your finding.
Public credit: named in the GitHub Security Advisory and release notes (unless you request anonymity).
Hall of Fame: reporters of MEDIUM, HIGH, or CRITICAL severity findings are listed in the Security Hall of Fame.
Anonymous submissions are processed equally and respected. Duplicate or low-impact findings may receive private acknowledgement only and are not eligible for CVE requests.
Scope
In scope
Command injection (CWE-77/78): e.g. unsanitized input reaching subprocess via --url git clone
Arbitrary code execution via malicious .toml rulesets, plugins, or scan targets (CWE-94)
Plugin sandbox escape: bypassing trust, checksums, or AST inspection (CWE-693)
Path traversal & arbitrary file write (CWE-22/73)
SSRF via the REST API /scan endpoint's url parameter (CWE-918)
Auth/authorization bypass on the REST API (CWE-306/862)
Rust core memory corruption, UAF, buffer or integer overflow (CWE-119/416/190)
DoS requiring unrealistic resources or physical access
Issues requiring root/admin privileges or prior access to developer secrets
Attacks on project infrastructure (GitHub Actions, PyPI account, domain)
Disclosure timeline
Private triage: report received via GitHub Advisory, validated, and acknowledged.
Coordination: fix developed in a private branch; you may be invited to verify the patch.
Release: a patched version is published on PyPI and GitHub.
CVE request: formally requested through GitHub's CNA on your behalf.
Advisory publication: technical details published with full credits.
Safe harbor: we support good-faith research. You will not face legal action if you act ethically, report promptly, avoid accessing or exfiltrating user data, don't exploit or disclose before a fix, and keep testing within PySpector's open-source codebase. Data exfiltration, destructive testing, or premature public disclosure voids this protection.
Community
Security Hall of Fame
PySpector is built by and for the security community. These researchers reported valid findings of MEDIUM severity and above through our disclosure program. Thank you.