Provity is a Streamlit-based interface for locally assessing Windows executables without relying on external network calls. It orchestrates three on-box checks—signature verification (osslsigncode), malware scanning (ClamAV), and a lightweight static strings pass for common IoCs—and then summarizes the results into an overall risk level.
- Offline-first workflow: all analysis stays on the local host.
- Signature verification via osslsigncode with CA bundle validation.
- Malware scan using the ClamAV CLI (clamscan) and concise result messaging.
- Static strings extraction (strings) with simple heuristics for IPs, URLs, shell usage, and registry keys.
- Risk Summary: overall risk level (Low/Medium/High), score (0–100), and evidence list.
- Temporary files are cleaned after each scan.
- Optional scan history dashboard backed by PostgreSQL (anonymous logging).
- Python 3.9+ with Streamlit installed (
pip install streamlit). - System binaries available on PATH:
osslsigncodeclamscan(ClamAV)strings(from binutils or equivalent)
- Optional (for .deb signature checks):
dpkg-debanddpkg-sig. - CA certificates bundle readable at
/etc/ssl/certs/ca-certificates.crtfor signature validation (adjust the path inverify_signatureif your system differs).
Provity can store scan results (risk score/level and basic metadata) in PostgreSQL and show them in a dashboard inside the Streamlit UI.
- Storage is anonymous by default: all scan events are stored with
user_id='anonymous'. - Database files are kept locally under
./pgdatawhen using Docker (and ignored by git).
If you prefer not to use a virtual environment, install the Python dependencies into your system Python.
On Debian/Ubuntu this typically means:
python3 -m pip install --user -r requirements.txtThen you can run Streamlit via:
python3 -m streamlit run app.pyIf you do want isolation:
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install -r requirements.txtEnsure osslsigncode, ClamAV, and strings are installed and callable from the shell.
From the project root:
docker compose up -d
docker compose psThen set the connection string (example):
export DATABASE_URL='postgresql://provity:provity@localhost:5432/provity'
#### Recommended: Read-only dashboard access
Provity's **Dashboard** can run in a safer read-only mode. In this mode:
- The UI shows history by running **SELECT** queries only.
- DB initialization and scan logging are disabled.
- The app prefers `DATABASE_URL_READONLY` for dashboard queries.
Set (example):
```bash
export DATABASE_URL_READONLY='postgresql://provity_ro:provity_ro@localhost:5432/provity'Create the read-only user inside the Docker Postgres (one-time):
sudo docker exec -i provity-postgres psql -U provity -d provity <<'SQL'
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='provity_ro') THEN
CREATE ROLE provity_ro LOGIN PASSWORD 'provity_ro';
END IF;
END $$;
GRANT CONNECT ON DATABASE provity TO provity_ro;
GRANT USAGE ON SCHEMA public TO provity_ro;
GRANT SELECT ON TABLE scan_events TO provity_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO provity_ro;
SQLSecurity note: it is recommended to avoid exposing Postgres (5432) to the public internet.
## Run
From the project root, launch Streamlit (system Python):
```bash
python3 -m streamlit run app.py
The app starts a local web UI.
- Upload a file (
.exe,.dll,.sys,.msi,.deb) to initiate analysis. - If you enable Enable scan history (PostgreSQL) in the sidebar (and have
DATABASE_URLset), the app will log scan events and show the Dashboard tab.
- The uploaded file is written to a temporary location.
- Signature check:
osslsigncode verify -CAfile /etc/ssl/certs/ca-certificates.crt -in <file>; reports validity and signer CN if present. - Malware scan:
clamscan --no-summary <file>; returns clean, infected with name, or engine error. - Static analysis:
strings -n 6 <file>; scans extracted text for IPs, URLs, common shell commands, and registry references, keeping up to five hits per category. - Risk summary: computes a score and level (Low/Medium/High) with evidence based on the three checks.
- Temporary file is deleted after processing.
When enabled, Provity stores each scan as a row in the scan_events table:
original_filenamefile_sha256(SHA-256 hash of the uploaded file)score,risk_levelscanned_at- small
metadataJSON (scanner backend, whether .deb, etc.)
The Dashboard tab shows:
- A per-file summary (last seen time, scan count, last risk level)
- A recent scans table (most recent first)
- Streamlit entrypoint:
app.py - Scanners and utilities:
provity/provity/scanners.py: signature verification, ClamAV scan, and IoC extractionprovity/risk.py: risk scoring and evidence generation
- Database helper:
provity/db.py - SQL schema:
sql/schema.sql - Docker Postgres (optional):
docker-compose.yml(data inpgdata/)
- The current CA path and CLI binaries assume a Unix-like environment; adjust paths for Windows if needed.
- ClamAV and strings outputs are directly surfaced; large binaries may take time to process.
- Detection heuristics are intentionally simple and should be complemented with deeper analysis for production use.
- No network calls are made by the app itself, but system tools may rely on existing signature trust stores.
- Streamlit app: app.py
- Scanners: provity/scanners.py
- Risk scoring: provity/risk.py