privacy-claim-audit
Version 0.1.0. A stdlib-only Python CLI that checks a project's own privacy and offline claims against static Python network evidence. Works offline, never executes project code, and makes no network requests.
Usage
Requires Python 3.9 or later. Install a locally built wheel:
python3 -m pip install --no-index dist/privacy_claim_audit-0.1.0-py3-none-any.whl
privacy-claim-audit [path] [--json] [--fail-on HIGH|MEDIUM] [--ignore RULE,...] [--verbose] [--version]
privacy-claim-audit .
privacy-claim-audit tests/fixtures/good --json
privacy-claim-audit tests/fixtures/bad --ignore offline-claim-false
privacy-claim-audit . --fail-on HIGH --verbose
python3 -m privacy_claim_audit --version
The default path is .. Exit codes: 0 PASS, 2 FAIL, 1 usage/input
error. The default threshold is MEDIUM; HIGH leaves MEDIUM findings visible
without failing. --ignore drops named rules entirely, for example when a
project documents an intentional exception; unknown rule names are usage errors.
--verbose prints verified claims in human output. --version prints 0.1.0.
Human findings use SEVERITY rule file:line message, followed by PASS or FAIL.
Locations point to the claim; the message names the first evidence file:line.
Only locations, matched claim phrases and rule names are reported, never source
line contents. Syntax errors and unreadable source/docs are input errors.
JSON always includes status, findings, and verified_claims. Findings have
severity, rule, file, line, and message, sorted by (rule, file, line)
with message as a deterministic tie-breaker. Verified claims have claim and
file. PASS means no contradictions detected at the selected threshold; a
verified claim is a static scan result, not a proof of runtime privacy. Ignoring
a contradiction does not turn it into a verified claim.
Full rule table
| Rule | Severity | Trigger |
|---|---|---|
offline-claim-false |
HIGH | An offline-claim is present in docs AND any non-test source file has network-import or network-call evidence. Message names the claim phrase, the doc file, and the first evidence file:line. |
local-only-claim-false |
HIGH | A local-only-claim is present in docs AND any non-test source file has network-import, network-call, or hardcoded-endpoint evidence. |
no-telemetry-claim-false |
HIGH | A no-telemetry-claim is present in docs AND any non-test source file has telemetry-import evidence, OR a network-call to a known analytics host as a literal host in a URL string. A generic network call alone does NOT trigger this rule. |
test-only-network |
MEDIUM | Network evidence exists ONLY in test files while an offline/local-only claim is present in docs. Tests may legitimately use a local server fixture; this is informational at MEDIUM so a human can confirm the tests do not hit the network. |
claim-without-evidence-note |
Not a finding | When a claim is present and no evidence is found, reports PASS and lists verified claims (claim phrase + doc file) under JSON verified_claims. Human output prints them only with --verbose. |
Rule 3 always requires a no-telemetry claim, including its analytics-host branch. Each matched claim occurrence can produce a finding. Tests never trigger rules 1–3. An individual claim is verified when no relevant contradiction is found.
Detection and scope
Reads README.md and other top-level *.md files, and recursively scans Python
*.py source including root modules, src/, package directories and tests.
Skips .venv, venv, __pycache__, dist, build, .git, and directories
ending in .egg-info; symbolic links are skipped. It never reads .env or
other non-source/non-documentation file contents. Claims in code comments or
nested documentation do not count.
Claim regexes are case-insensitive, literal phrase alternatives surrounded by
word boundaries (\b(?:phrase|...)\b). Longer alternatives are tried first
so “fully offline” is one match rather than a second overlapping “offline”.
The complete phrase lists are:
- offline-claim:
offline,works offline,fully offline,no internet,no network,no network access,does not require internet,no internet required. - local-only-claim:
local only,local-only,runs locally,stays on your machine,never leaves your machine,data never leaves,your data stays. - no-telemetry-claim:
no telemetry,no tracking,no analytics,no phone home,no data collection,does not collect,does not send,does not transmit,does not upload,does not phone home.
Source evidence uses AST imports/calls and regex matching of string literals:
network-import: requests, httpx, urllib.request, urllib3, aiohttp, socket, smtplib, ftplib, websocket, websockets, telnetlib. Handles import/from forms and aliases; only urllib.request, not all of urllib, is network evidence.network-call: urlopen, requests.get/post/put, httpx.get/post, socket.socket/connect, smtplib.SMTP, and subprocess calls containing a literalcurlorwgetargument in an argument list.telemetry-import: sentry_sdk, posthog, mixpanel, amplitude, segment, analytics, telemetry, datadog, newrelic, honeycomb, plausible.- Known analytics hosts: segment.io, amplitude.com, mixpanel.com, posthog.com, sentry.io, google-analytics.com, googletagmanager.com. Subdomains count; unrelated hosts with a matching prefix do not. A URL must occur in a detected network call, not merely in an unused constant.
hardcoded-endpoint: a code string matchinghttps?://[A-Za-z0-9.-]+\.[A-Za-z]{2,}outside tests and docstrings. Module, class and function docstrings are skipped for this rule.
Differentiation
- vs bandit: bandit finds security issues in code; this checks whether the project's OWN privacy prose is true — no vuln detection, no severity scoring of code issues.
- vs pip-audit: pip-audit checks installed packages against a vulnerability database (needs the network/registry); this audits the repo's claims statically, offline, and never asks whether a package is vulnerable.
- vs consent-engine: that runs a live browser against a deployed web page and checks consent behaviour at runtime; this audits a repo's static claims before anything runs.
- vs privacyaudit (PyPI): that audits trained ML models for membership-inference risk; this audits prose claims vs source network behaviour — different input, different question.
- vs readme-claim-audit / dep-claim-audit: those audit install, flag, link, version, and dependency claims; this audits privacy / offline claims only — no overlap in rules.
Honest limitations
static scan misses dynamic network access (importlib-loaded modules, exec/eval of fetched code, plugins loaded at runtime); a network import that is never called at runtime still triggers a finding (human must confirm reachability); prose claim detection is pattern-based not semantic (a sentence like "we removed offline mode" could false-positive — scope prose search to README + top-level docs and document the regex list); telemetry SDK list is small and documented — unknown SDKs are not flagged; hardcoded-endpoint skips docstrings, so an endpoint documented only in a docstring is not counted as evidence.
Import aliases are resolved statically without control-flow analysis. Arbitrary object method calls, dynamically assembled URLs, shell command strings and transitive dependencies are outside the detector's finite call list.
Development
PYTHONPATH=src python3 -m unittest discover -s tests -v
PIP_NO_INDEX=1 python3 -m build
# If isolated build requirements are unavailable locally:
PIP_NO_INDEX=1 python3 -m build --no-isolation
Tests use only local fixtures and temporary directories. Package runtime has no third-party dependencies. MIT licensed; see LICENSE.
Metadata
Release files for privacy-claim-audit 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| privacy_claim_audit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for privacy_claim_audit-0.1.0-py3-none-any.whl |
Release files / privacy_claim_audit-0.1.0-py3-none-any.whl
| Download URL | privacy_claim_audit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b09885291f0dee2e6800969909475659a84129e8b38ccab58ef803d96d602bfc
|
|
BLAKE2b-256 checksum How to use checksums |
d1809e2f5462cf2a222b0951314b6c05d549aed02a53ebde4ca62c4b62c10fbf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for privacy-claim-audit 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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.