kestrix-scan
A security scanner for developers and anyone coding with an AI assistant: it runs locally with no dependencies, checks each file Claude Code writes as Claude writes it, and is measured on real CVE fixes (accuracy table).
pip install kestrix-scan # or: uv tool install kestrix-scan / pipx install kestrix-scan
kestrix-scan src # text report; exit 1 on high or critical findings
kestrix-scan install-claude-plugin # the Claude Code plugin; enable it as in "Claude Code plugin" below
It covers code in 13 languages (Python, JavaScript, TypeScript, PHP, Go, Java, Kotlin, C#, Ruby, C, C++, Rust and Swift), web files (HTML, Vue, Svelte, CSS), SQL files, GitHub Actions, Dockerfiles, shell, Terraform and Kubernetes, hard-coded secrets and dependencies in 9 lockfile ecosystems. It finds shell and SQL injection, XSS sinks, unsafe deserialization, disabled TLS checks, weak hashes and randomness, leaked API keys, and lockfile dependencies with known vulnerabilities or reported as malware, with a CWE and a concrete fix for every finding. It runs in your terminal, in CI with SARIF for GitHub code scanning, in pre-commit and pytest, and inside Claude Code, where it has Claude fix what it finds while it writes code.
- No dependencies on Python 3.11 and newer (only
tomlion 3.10). Python 3.10 to 3.13. - Nothing leaves your machine. Files are read as data: never imported, executed or uploaded. Scans open no
network connections. The only command that uses the network is
kestrix-scan db update, which you run to download the public OSV vulnerability data; dependency checks read that local copy. - Fast to start:
kestrix-scan --versiontakes about 40 to 55 ms, a few milliseconds more than Python itself.
Part of Kestrix by Ruthvik Bandari. Apache-2.0.
Quick start
Before the first PyPI release, install it from GitHub:
pip install "git+https://github.com/Ruthvik-Bandari/kestrix#subdirectory=packages/kestrix-scan".
$ kestrix-scan app.py
app.py
4:5 HIGH py.subprocess.shell_true CWE-78
subprocess.run runs a built command through the shell (shell=True).
fix: Pass the command as a list of arguments without shell=True, for example subprocess.run(['git', 'log', ref], check=True). Use shlex.quote only when a shell is unavoidable.
1 finding(s): 0 critical, 1 high, 0 medium, 0 low in 1 file(s); 0 suppressed, 0 in baseline, 0 skipped; fail-on high.
Rule-based pattern analysis on this machine. Rules miss things and can be wrong; no detection rate is claimed. No findings means no rule fired, not that the code is secure.
| Option | Meaning |
|---|---|
PATH ... |
Files or directories to scan (default .). Directories skip .gitignored, vendored and build paths. |
--format text|json|sarif |
Output format. JSON has a schema_version; SARIF 2.1.0 is for GitHub code scanning. |
--output FILE |
Write the report to a file instead of stdout. |
--fail-on low|medium|high|critical|none |
Lowest severity that makes the command exit 1 (default high, or [tool.kestrix] fail-on). |
--diff REF |
Only report findings on lines changed since a git ref (untracked files count as new). |
--baseline FILE / --write-baseline FILE |
Leave out known findings / record the current ones, to adopt the scanner gradually. |
--config FILE / --no-config |
Use one settings file / ignore settings files. |
--hook |
Claude Code hook mode: read the hook JSON on stdin; always exit 0. |
Exit codes: 0 nothing at or above --fail-on, 1 findings at or above it, 2 usage or input error.
kestrix-scan rules lists every rule; kestrix-scan --help lists the commands. python -m kestrix_scan works too.
Silence a confirmed false positive on its line, or the line above, with a reason (required):
subprocess.run(
deploy.command, shell=True
) # kestrix: ignore[py.subprocess.shell_true] command from the reviewed deploy config
Dependency scanning
kestrix-scan db update # downloads the OSV data for the ecosystems your lockfiles use (the only network step)
kestrix-scan . # lockfiles are now checked too, offline
kestrix-scan db status # where the index is, how old, how many advisories
db update downloads the OSV export of each ecosystem
(https://storage.googleapis.com/osv-vulnerabilities/<ECOSYSTEM>/all.zip) over HTTPS, with a 2 GiB cap,
keeps it in your cache directory ($KESTRIX_SCAN_DB, or ~/Library/Caches/kestrix-scan,
$XDG_CACHE_HOME/kestrix-scan, %LOCALAPPDATA%\kestrix-scan) and builds a SQLite index from it, recording
each download's SHA-256 and time. The exports include the OpenSSF malicious-packages feed. On 2026-10-20
PyPI was 36.5 MB and npm 218.6 MB, and the index 86 MB; on 2026-10-23 Packagist was 11.0 MB, Go 12.6 MB, Maven 10.4 MB,
RubyGems 5.2 MB, crates.io 3.6 MB, NuGet 2.7 MB and Pub 0.03 MB. Without --ecosystem, db update downloads only the
ecosystems of the dependency files it finds (plus those already indexed and db-ecosystems from [tool.kestrix];
PyPI and npm when there are none); --ecosystem Go Packagist names them and --all takes all nine. A repeat
update sends If-None-Match and If-Modified-Since: an unchanged export is a 304 and the index is not rebuilt.
Scans then read requirements*.txt (exact == pins; other lines are noted as not checked), uv.lock,
poetry.lock, pdm.lock, Pipfile.lock, package-lock.json (v2 and v3), yarn.lock (v1 and Berry),
pnpm-lock.yaml, bun.lock, composer.lock (PHP), go.mod/go.sum, Cargo.lock, pom.xml/gradle.lockfile,
Gemfile.lock, packages.lock.json (NuGet) and pubspec.lock, and match each version against the advisories with
the ecosystem's own ordering (PEP 440, SemVer, Composer, RubyGems, NuGet, Maven). A version that cannot be compared is
reported as "possibly affected" at low confidence, never skipped:
package-lock.json
12:1 CRITICAL dep.vulnerable CWE-1321
minimist@1.2.0 (npm) has 2 known vulnerability(ies): GHSA-vh95-rmgr-6w4m (CVE-2020-7598), GHSA-xvch-5gv4-984h (CVE-2021-44906). Prototype Pollution in minimist; fixed in 1.2.3, 1.2.6.
fix: Upgrade minimist to 1.2.6 or later and update the lockfile.
15:1 CRITICAL dep.malicious CWE-506
react-0b1@1.0.0 (npm) is reported as a malicious package: GHSA-8ghv-p6hq-5px9 (MAL-2023-722). Malicious code in react-0b1 (npm)
fix: Remove react-0b1 from the project and its lockfile, then rotate every credential, token and key on machines where it was installed.
dep.vulnerable: the advisories' highest CVSS severity, their CWE, ids and summary, and "Upgrade X to V or later" with the lowest version that fixes all of them.dep.malicious: critical; remove it and rotate credentials.- A
dep.db_stalenote (never a failure) in text, JSON and SARIF output when the index is missing or older thandb-max-age-days(default 7;KESTRIX_SCAN_MAX_AGE_DAYSoverrides). The Claude hook,/kestrix:statusand the install guard say so too.dep.ecosystem_missingnotes an ecosystem the index has no data for. - Suppress with
# kestrix: ignore[GHSA-...] reasonon a requirements line, or for any file withignore-advisories = {"GHSA-..." = "reason"}in[tool.kestrix]. Baselines,--diffandfail-onapply. - Reachability is not analyzed. A language runtime (for example the PHP interpreter) is not a lockfile dependency and is not checked; the website check's exposure finding covers server and runtime versions. Details: docs/modules/code.md.
Configuration
[tool.kestrix] in pyproject.toml, or the same keys at the top level of .kestrix.toml:
[tool.kestrix]
fail-on = "medium" # low, medium, high, critical or none
exclude = ["tests/fixtures/", "*.min.js"] # globs, as in .gitignore
baseline = ".kestrix-baseline.json" # relative to this file
rules.enable = ["py.", "secret."] # rule ids or prefixes; default: every rule
rules.disable = ["py.crypto.weak_hash"]
ignore-advisories = {"GHSA-xxxx-xxxx-xxxx" = "not reachable: we never parse untrusted XML"}
claude.install-guard = false # turn off the Claude Code install guard here
db-max-age-days = 7 # warn when the OSV index is older than this
db-ecosystems = ["PyPI", "npm", "Go"] # extra ecosystems for `db update`
- The nearest file wins, searching upwards from the scan root and stopping at the git root. In each directory
.kestrix.tomlis read beforepyproject.toml; apyproject.tomlwithout[tool.kestrix]is skipped. - Command-line flags override the file.
- An unknown key is a warning. An unknown rule id or prefix is an error (exit 2) with a suggestion, so a typo never silently disables nothing.
- Excludes apply to files named on the command line too, which is how pre-commit passes them.
Set up a project: kestrix-scan init
kestrix-scan init # append a minimal [tool.kestrix] to pyproject.toml
kestrix-scan init --pre-commit # add the pre-commit hook
kestrix-scan init --ci github # write .github/workflows/kestrix.yml
kestrix-scan init --claude-plugin # install the Claude Code plugin
init appends to pyproject.toml as text and never rewrites it; it leaves an existing [tool.kestrix]
alone unless you pass --force. Without a pyproject.toml it writes .kestrix.toml. It writes
.pre-commit-config.yaml only when it is missing or empty, and otherwise prints the entry to add. Running
it again is safe: each step reports what is already in place.
pre-commit
repos:
- repo: https://github.com/Ruthvik-Bandari/kestrix
rev: v0.1.0
hooks:
- id: kestrix-scan
The hook scans the staged Python and text files, lockfiles included, and honours [tool.kestrix]. Dependency results
use the local index and pre-commit never refreshes it, so run kestrix-scan db update daily (cron, a scheduled job or
the CI workflow below); a stale index is reported as a note.
GitHub code scanning
kestrix-scan init --ci github writes a workflow that runs on every push and pull request and daily at 05:17 UTC, so a
vulnerability published tomorrow in a locked dependency appears without a commit. It caches the OSV download directory
(actions/cache), so the daily refresh is a conditional request per ecosystem. Its actions are pinned to commit SHAs and
its job has only contents: read and security-events: write. The steps that matter:
- run: pip install kestrix-scan==0.1.0
- run: kestrix-scan db update # downloads the OSV data of your lockfiles' ecosystems; needs network access
- run: kestrix-scan --format sarif --output kestrix.sarif || true
- uses: github/codeql-action/upload-sarif@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
with:
sarif_file: kestrix.sarif
Findings then appear under Security → Code scanning. To fail the build instead, drop || true.
pytest
pytest --kestrix # adds one "kestrix-scan" item that scans the rootdir
pytest --kestrix --kestrix-fail-on=medium
The item fails when findings meet the threshold (default: [tool.kestrix] fail-on, else high), and its
failure report is the scanner's text report. Without --kestrix the plugin only registers its options; the
scanner is not even imported.
Claude Code plugin
kestrix-scan install-claude-plugin # copies the plugin to ~/.claude/kestrix-plugin
claude plugin marketplace add ~/.claude/kestrix-plugin
claude plugin install kestrix@kestrix-local
Or from the repository's marketplace: /plugin marketplace add Ruthvik-Bandari/kestrix, then
/plugin install kestrix@kestrix. Nothing in your Claude Code settings changes until you run those commands.
- After every Write or Edit the plugin runs
kestrix-scan --hookon the changed file and hands Claude the findings the edit introduced, with the rule, CWE and fix, so Claude fixes them in the same turn. - Skills and commands:
secure-code-review, a per-rulefixing-security-findingsplaybook,/kestrix:scan,/kestrix:fixand/kestrix:review(a review of the current git diff). - Install guard: before a
pip,uv,npm,pnpm,yarn,bun,composer require,go get,cargo add,gem installordotnet add packageinstall runs, the plugin checks the packages against the local OSV index. A known malicious package is denied; a known-vulnerable pinned version gets a warning naming the fixed version. No index means no check; an old index adds a line saying the result may be stale. Turn it off withKESTRIX_INSTALL_GUARD=0orclaude.install-guard = false. - Opt-in Stop gate: with
KESTRIX_BLOCK_ON_STOP=1, Claude cannot finish while new high or critical findings remain in files it changed (at most three times per session). - Fails open: a missing scanner, a timeout or an error never blocks an edit. Findings never contain secret values, only their kind and first four characters.
kestrix-scan install-claude-skill installs only the kestrix-security skill;
package-claude-plugin and package-claude-skill write zips. Full details:
docs/claude-plugin.md.
Python API
import kestrix_scan
config = kestrix_scan.load_config("src") # [tool.kestrix] or .kestrix.toml, if any
report = kestrix_scan.scan(["src"], config=config, fail_on="high")
for finding in report.findings: # kestrix_scan.Finding: frozen dataclass
print(finding.path, finding.line, finding.rule_id, finding.cwe, finding.fix)
print(report.to_json()) # the same JSON as --format json
raise SystemExit(kestrix_scan.exit_code(report))
for rule in kestrix_scan.rules(): # the registry, in its stable order
print(rule.id, rule.severity, rule.cwe, rule.title)
scan raises kestrix_scan.Rejected for a missing path, a bad baseline, an unknown git ref or bad
settings. The package is typed (py.typed).
Privacy
kestrix-scan reads files as bytes, decodes them as text, parses Python with the standard-library ast and
splits every other language with its own bounded, standard-library tokenizer.
It never imports or runs the code it scans, never follows symbolic links out of the scan root, and caps
file size and count. Scans, the plugin hooks and the install guard make no network requests; the test suite
proves they work with every socket call refused. The one exception is kestrix-scan db update, which you run
explicitly: it downloads the public OSV exports over HTTPS and sends nothing about your project. --diff and directory walks run the local git binary.
Languages and measured accuracy
What the numbers mean. Each language was measured on real security fixes from CVEfixes and the GitHub Advisory Database: does a rule fire on the vulnerable version of a file a fix changed? Rules were tuned on one half of the projects, then run once on the other half, which they had never seen, next to an established open-source tool on the same files. Caught is the share of in-scope vulnerable files flagged, with a 95% confidence interval; false alarms are alerts per 1,000 lines of the fixed (safe) code. Every tool catches a small share on this benchmark: many CVEs are logic or authorization flaws no pattern rule sees, and a fix commit often changes files that never held the bug. Method, per-rule numbers and limits: CVE-fix benchmark.
| Language or files | Rules | Caught (held-out) | Compared on the same files | False alarms per 1,000 lines |
|---|---|---|---|---|
| Python | 30 py.* |
7.7% [4.2, 12.0] | Bandit 1.9.4: 10.2% at 0.99 false alarms | 0.23 |
| JavaScript, TypeScript (JSX, TSX) | 16 js.* |
10.3% [7.2, 13.9] | eslint-plugin-security: 12.4% at 16.9 false alarms | 0.43 |
| PHP and Blade | 9 php.* |
5.4% [2.8, 10.2] | Psalm 6.20 taint: 3.3% at 0.66 | 0.80 |
| Java and Kotlin | 7 java.* |
10.9% [5.9, 18.4] | Opengrep: 5.8% at 0.34 | 0.20 |
| Ruby and ERB | 6 rb.* |
4.7% [1.0, 10.0] (ERB views: 13 of 16) | Opengrep: 11.2% at 1.91 | 1.55 |
| Go | 4 go.* |
1.1% [0.0, 6.7] | gosec 2.30: 6.7% at 0.78 | 0.13 |
| C# | 4 cs.* |
2.4% [0.0, 16.7] (41 files) | Opengrep: 0.0% at 0.05 | 0.15 |
| C and C++ | 7 c.* |
3.4% [0.7, 6.7] | flawfinder 2.0.19: 19.4% at 6.13; Opengrep: 4.6% at 0.62 | 0.34 |
| Rust | 3 rust.* |
not measurable: 14 fixes, no tool caught any | Opengrep: 0.0% at 2.33 | 0.05 |
| Swift | 3 swift.* |
not measurable: 1 fix | 0 to 0.11 on 3 clean projects | |
HTML, Vue, Svelte, CSS, next.config |
12 html.* vue.* svelte.* web.* css.* next.* |
tuning data only: 27.4% [7.4, 50.9] of 73 files; held-out run waits for new advisories | no licensed tool | 0.47 on clean web files |
| SQL files | 3 sql.* |
no .sql files in the fix data |
||
| GitHub Actions, Dockerfile, shell, Terraform (AWS), Kubernetes | 24 gha.* docker.* sh.* tf.* k8s.* |
no CVE-fix data for these formats; agrees with zizmor, hadolint and checkov on 94% to 100% of the files where the checks mean the same | on 16,157 real files: 4.5 for unpinned actions, 0.03 for workflow script injection | |
| Claude Code and MCP settings | 5 config.* |
not benchmarked | ||
| Secrets in any text file | 11 secret.* |
not on this benchmark; shapes are high-precision on purpose | ||
| Dependencies (9 lockfile ecosystems) | 2 dep.* |
exact version match against OSV advisories, not a heuristic |
Bold marks where Kestrix is ahead of the compared tool. Python and JavaScript/TypeScript are from the second held-out run (test2); the Python rules added later were measured on tuning data only. Some rules ship with little or no evidence; the Limits list names them.
Rules
There are 146 rules. They cover Python (30 py.* rules: eval/exec, shell=True and os.system, pickle and
unsafe YAML, tar extraction without a filter, SQL built from strings, disabled TLS checks, MD5/SHA-1, random for secrets, tempfile.mktemp,
Flask debug, unverified JWTs, stdlib XML parsers, Jinja2 environments without autoescape, assert for access checks, and, through intraprocedural taint
analysis from Flask (including route parameters), Django, FastAPI, Starlette, aiohttp, Tornado and LLM-client sources, path traversal, SSRF, open redirects, XSS/SSTI and
LLM output reaching code, a shell, SQL or a path; plus unsafe model loading), JavaScript and TypeScript (16 js.*
rules for .js, .mjs, .cjs, .jsx, .ts, .tsx, .mts and .cts: eval and new Function,
child_process shells, DOM and React HTML sinks, SQL built from strings, rejectUnauthorized: false, MD5/SHA-1,
Math.random() for secrets, JWT none and ignoreExpiration, Express, Koa and hapi request data (including the request URL) reaching files, URLs and
redirects, prototype pollution, wildcard CORS with credentials, Angular bypassSecurityTrust*, and LLM output reaching eval, a shell or HTML; request
sources also include Next.js route handlers, params and server-action FormData, Fastify, Koa and NestJS decorators),
web files (12 rules in vue.*, svelte.*, web.*, html.*, css.* and next.* for .vue, .svelte, .html, .htm,
.css, .scss and next.config.*: v-html and {@html} with a non-literal value, javascript: links, inline event
handlers, target="_blank" without noopener, forms and subresources over http:, Angular [innerHTML], remote CSS over
http: and expression(), and a ** image host in next.config; mostly low severity, with <script> blocks run through the
js.* rules), PHP and Blade (9 php.* rules for .php, .phtml and .blade.php: request values from $_GET, $_POST, $_REQUEST,
$_COOKIE, php://input and Laravel/Symfony request objects reaching commands, include, SQL, echo, URLs and file paths inside one
function, extract($_REQUEST), md5/sha1 of passwords and Blade {!! !!}), SQL files
(3 sql.* rules for .sql: GRANT ALL, plaintext account passwords and PostgreSQL SECURITY DEFINER functions without a fixed search_path), Go (4 go.* rules for .go:
request data from net/http, gin, echo, fiber or chi reaching exec.Command, SQL or template.HTML, and InsecureSkipVerify: true), Java and Kotlin
(7 java.* rules for .java, .kt and .kts: servlet, Spring, JAX-RS, Stapler and Ktor request data reaching JDBC and JPA SQL, Runtime.exec and
ProcessBuilder, file paths, outbound URLs and the response writer, plus ObjectInputStream, XStream, Jackson default typing and SnakeYAML
deserialization and XML parser factories without DOCTYPE protection), C# (4 cs.* rules for .cs: ASP.NET request data reaching SqlCommand, Entity
Framework and Dapper SQL, Process.Start and file paths, and BinaryFormatter and Json.NET TypeNameHandling), Ruby on Rails (6 rb.* rules for .rb
and .erb: params reaching where/find_by_sql/order, html_safe/raw/<%== %>, constantize, send, system and backticks, and file
paths), C and C++ (7 c.* rules for .c, .h, .cc, .cpp, .cxx, .hpp, .hh and .hxx: gets, strcpy/strcat/sprintf into arrays
declared with a size, system/popen with a built command, printf-family formats that are not literals, scanf %s without a width, rand()
next to security values and tmpnam/mktemp), Rust (3 rust.* rules: Command running a shell with a built script, TLS verification turned
off, unchecked memory operations in unsafe blocks on input-derived values), Swift (3 swift.* rules: trust-all URLSession challenge handlers
and Alamofire's disabled evaluator, NSAllowsArbitraryLoads in .plist files, secrets in UserDefaults); these systems-language rules flag only
lexically obvious patterns and cannot judge memory safety, CI and infrastructure files (24 rules in gha.*, docker.*, sh.*, tf.* and k8s.* for GitHub Actions
workflows, Dockerfiles, .sh and .bash scripts, Terraform and Kubernetes manifests: pull_request_target checking out the PR head,
${{ github.event.* }} in run:, unpinned third-party actions, permissions: write-all, running as root, ADD of a URL,
curl | sh, latest images, secrets in ENV/ARG, eval and rm -rf of variables, chmod 777, public S3 buckets, admin
ports open to the internet, unencrypted storage, and privileged or host-mounted pods; read with a bounded YAML subset reader,
nothing is run), Claude Code and MCP configuration
(5 config.* rules: hooks that run downloaded scripts, permission bypasses, unpinned npx -y/uvx servers and
literal credentials), secrets in any text file (11 secret.* rules: AWS, GitHub, Slack, Stripe, Google, Anthropic
and OpenAI-style keys, private keys, JWTs and high-entropy credentials), and dependencies in lockfiles (2 dep.*
rules: dep.vulnerable, dep.malicious). The full table with CWEs and severities is in
docs/modules/code.md, and
each rule's sources are in
docs/modules/code-rules-provenance.md.
JavaScript and TypeScript: precision first, no full parser. The scanner stays dependency-free, so it does not
ship a JavaScript parser. A bounded tokenizer (strings, nested templates, comments, regex versus division, JSX and
TypeScript annotations) feeds a structural matcher that knows calls, member chains, assignments, object keys, JSX
attributes, function scopes and import/require aliases, plus a light same-function taint for Express request
data, the URL and LLM output. Every rule matches a precise shape and stays quiet when the code is ambiguous, so it
misses more than a parser-based tool would, by design. Minified files (a .min. name or an average line over 500
characters) are skipped as minified. Vue, Svelte and HTML files are read with a bounded tag scanner (no HTML parser): the
template rules look at directives and attributes, <script> bodies go through the JavaScript rules with the file's line
numbers, and a missing Content-Security-Policy is deliberately not reported.
Rules are pattern analysis: they miss things and can be wrong in context, and no findings means no rule fired, not that the code is secure. The measured rates are in Languages and measured accuracy. A benchmark scorecard measures category coverage on synthetic code (OWASP BenchmarkPython v0.1 and the project's own labelled cases) against Bandit and the security-guidance regex layer, including the categories where Kestrix loses. Rule ids are stable; renaming one is a breaking change recorded in the CHANGELOG.
Metadata
Release files for kestrix-scan 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| kestrix_scan-0.1.0.tar.gz | 514.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kestrix_scan-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / kestrix_scan-0.1.0.tar.gz
| Download URL | kestrix_scan-0.1.0.tar.gz |
|---|---|
| Size | 514.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ab285a4447d6e9e8cc99fef2291a7dba3b06811d354a041622513a74314b5ee6
|
|
BLAKE2b-256 checksum How to use checksums |
57ea60a5f277b6d8962e2e744408c9a4abc26cf71d3b5157582798dfb561a80b
|
| 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 26, 2026.
Transparency logRelease files / kestrix_scan-0.1.0-py3-none-any.whl
| Download URL | kestrix_scan-0.1.0-py3-none-any.whl |
|---|---|
| Size | 538.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e0b83e840d96ff0a74e42f0f772395b6dd3cbe743a71bf412c2c793c8e0de332
|
|
BLAKE2b-256 checksum How to use checksums |
14733e33beae76f8f07608346f4d2820ccefdb0e2df5e190ee3f14dcadceedc6
|
| 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 26, 2026.
Transparency logSecurity for kestrix-scan 0.1.0
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.
Attestation for kestrix_scan-0.1.0.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 26, 2026.
Transparency logA 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.