guides Intermediate

Security Best Practices

The verified security posture of pyvorin-native 1.0.9: what the product guarantees, what it does not, and the practices that keep it sound.

Published May 4, 2026

pyvorin-native 1.0.9 keeps your source code on your machine, protects its licence state with signatures and file permissions, and sends the outside world a narrow, sampled telemetry stream. This page collects the verified controls, names the exact boundary of each one, and lists the operational practices — environment hygiene, cache permissions, sibling-package scoping — that the product cannot enforce for you.

Everything here was read from the installed build or captured at runtime. Where 1.0.9 is weaker than its marketing implies, this page says so.

Verified outbound surface

The strongest security property of the native package is how little it says. A full string sweep of the installed binaries finds exactly four network destinations, and only under specific conditions:

EndpointWhen calledPayload
POST https://api.pyvorin.com/api/v1/licenses/checkpyvorin activate, and periodic revalidation from the hard gatelicense_key, device_fingerprint — no source code, no filenames
POST https://api.pyvorin.com/v1/usage/events/bulktelemetry flush: 50 events, 300 seconds, or process exitevent metadata envelope — see below
POST …/api/auth/token / …/revokeonly the product CLI's login / logoutaccount credentials / token

Compilation itself makes no network calls at all: the compiler path contains zero HTTP client code and links LLVM output against runtime libraries on disk. There is no update-check call, no error-reporting beacon, no component downloader. If you are scoping egress rules for a hardened host, the table above is the whole list for the native package.

One scope warning belongs here in bold terms. A sibling package, pyvorin-thin, is a different product with a different posture: it submits source code to a server-side compile endpoint. The guarantees on this page are for pyvorin-native. If a shared environment has both packages installed, audit which one your entrypoints import.

Source code never leaves the machine

On the native path this is verifiable, not asserted. The compile pipeline lowers Python to LLVM IR through llvmlite and links locally; a search of the compiler modules for any HTTP client finds nothing, and the runtime capture of every network call made during activation confirms the licence payload carries only the key and a device fingerprint. Your functions never appear in any payload, at any tier.

Licence state on disk

Activation stores ~/.pyvorin/license.json with file mode 0600 — readable only by the owning account. The file is protected in depth:

  • Integrity field. An HMAC-SHA256 over the payload with a build-time secret is stored in the file; edits invalidate it.
  • Device binding. The stored fingerprint is SHA-256 of hostname:username:/etc/machine-id, truncated to 32 characters. Copying the file to another host fails validation.
  • Signed lease. The server response includes an Ed25519-signed lease, verified against an embedded public key. Entitlement claims in the signed lease override anything edited locally, so a tampered tier field does not widen access.
  • Anti-rollback. A monotonic last_seen watermark with five minutes of tolerance blocks replaying an older, unexpired lease over a newer one.
  • Validity cap. Leases are rejected beyond 800 days of validity, and the entitlement cache enforces offline grace windows after expiry (24 hours for trial tiers, 72 hours for basic and professional, 90 days for enterprise).

Practical consequences. Keep ~/.pyvorin/ inside a private home directory — the mode-0600 file is only as strong as the directory above it. On shared CI runners, isolate the home directory per job so one job's licence state is not another's. And if the gate fails after a host rebuild, the usual cause is a changed machine-id or hostname; re-activation against the same key is the documented recovery.

Integrity checking of the product itself

At import, the package SHA-256-hashes every compiled module against a baked-in table and raises a RuntimeError naming tampering on mismatch. This is the control that turns a compromised site-packages tree into a loud failure instead of silent arbitrary code execution.

The same mechanism has an escape hatch, and it is a security-relevant one: setting PYVORIN_DEV_MODE=1 skips the hash check entirely. That variable exists for development builds. Never set it in production, and treat its presence in a production environment as a finding — it converts a hard integrity boundary into nothing. The same variable disables other protective behaviour; there is no legitimate production use.

Honesty note: the Ed25519 manifest signature described in some build documentation is not enforced in the shipped 1.0.9 — the manifest carries an empty signature and the verification key is empty, so that path returns early. The SHA-256 hash table and the lease signature are the active controls. Know which guarantees are live.

Telemetry: what leaves, and when

Telemetry is fire-and-forget: a ring buffer flushed at 50 events, 300 seconds, or process exit, over a five-second timeout, with failures silently ignored. No background thread, no blocking of your code.

Contents, verified from the captured envelope. The batch carries a version, a per-process session id, the privacy level, a locally computed abuse score, and event records of metadata only — type, parameters such as compile time in milliseconds, and a schema tag. Compile and execute events are sampled at 1%. Security events are always recorded: activation, validation_failed, tamper_detected and revoked. What telemetry never contains: source code, function names from your codebase, file paths, or argument values.

Privacy levels are standard (default), minimal (security events only) and disabled. The catch that matters operationally: there is no environment variable or config file for opting out. Privacy is changed through an in-process API call (pyvorin._telemetry.set_privacy) or dev mode. If policy requires telemetry off, that is a code change at application startup, and it belongs in code review like any other security-relevant line.

Environment variables as trust redirection

Two environment variables override where the product sends its outbound traffic: PYVORIN_LICENSE_URL (licence checks) and PYVORIN_TELEMETRY_URL (telemetry). They exist for proxies and staging. They are also, in effect, trust-redirection switches: any process that can set them can point your licence key and your telemetry at an attacker-controlled host and receive what your production environment sends.

Treat both variables as secrets-adjacent. Pin them explicitly in production deployment configuration rather than inheriting ambient environment. Scrub them from CI runner images, where a poisoned base image could otherwise harvest keys from every build. If your threat model includes malicious local code, note that such code can do far worse than redirect telemetry — but these variables lower the bar to a single export, which is why they belong in your environment audit checklist. Separately, never set PYVORIN_SKIP_LICENSE=1 to bypass the gate: the shipped build only honours it alongside a developer marker file that production wheels exclude, and relying on the bypass builds an operational habit that will break — or worse, not break — at the worst moment.

Cache and runtime file permissions

The product writes several cache locations, and their permissions deserve a line in your hardening runbook:

LocationHoldsPractice
~/.pyvorin/licence file and entitlement cacheprivate home directory; licence file already 0600
~/.pyvorin_cache/runtime caches (created at import, before any activation)private home directory on shared hosts
<site-packages>/.pyvorin_cache/disk_compilecompiled artefacts with a checksum-validated index, LRU-capped at 500 entrieskeep site-packages owned by root/service account, writable only by the deploy user
~/.cache/pyvorinXDG cache statestandard per-user permissions are sufficient

The compile cache is validated per entry, so a corrupted or replaced artefact is reported on load rather than executed — checksums turn cache tampering into a detectable event. Defence in depth still applies: the cache lives inside the install tree precisely so that its write access rides on your deployment permissions, and those permissions should be narrow.

The judgement call: shared runners

The one place these controls genuinely strain is the shared CI runner, and the resolution is a prioritisation call, not a product fix. Our recommended ordering: isolate the runner home directory per job (protects licence state and caches), pin PYVORIN_LICENSE_URL and PYVORIN_TELEMETRY_URL to the real endpoints and strip inherited values (blocks redirection), never carry PYVORIN_DEV_MODE or PYVORIN_SKIP_LICENSE in runner images (keeps integrity and the gate live), and run activation inside the job with a scoped key rather than baking a licence file into a shared image (contains revocation blast radius). On a fully private runner you can relax the first and last items. On a hosted multi-tenant runner, do not relax any of them — and prefer benchmarking with python -m pyvorin bench, which needs no licence for measurement, over activating long-lived keys there at all.

Where to go next

Last reviewed 4 May 2026 against pyvorin-native 1.0.9 installed at /root/pvfinal. Endpoint payloads were captured at runtime with network interception on 13 September 2026; file modes, integrity behaviour and cache locations were read from the installed artefacts and sources. pyvorin-thin is out of scope except as a named warning, because its source-upload posture differs from everything verified here.