| Version | Supported |
|---|---|
| >= 0.4.11 | ✅ |
Please open a GitHub Security Advisory or contact the maintainers directly. You will receive a response within 48 hours.
This PHP library uses FFI to load a native shared library (libzvec_ffi.so).
The shared library runs with the same system privileges as the PHP process.
Only load trusted .so files from official sources.
Pre-built shared libraries are downloaded from GitHub Releases over HTTPS.
SHA-256 checksum verification is performed before extraction (see SEC-001 below).
For maximum trust, build the library from source using ./build_zvec.sh.
Embedding classes accept API keys as constructor parameters. Best practice: use environment variables:
// Recommended:
$apiKey = getenv('OPENAI_API_KEY');
$embedding = new OpenAIDenseEmbedding(apiKey: $apiKey);
// NOT recommended:
$embedding = new OpenAIDenseEmbedding(apiKey: 'sk-...hardcoded...');See the Security section in README for more details.
Status: Fixed in v0.4.12
Issue: SEC-002 (#71)
Problem: The Installer::install() method previously used tempnam() + .tar.gz suffix to create a temporary download file. An attacker with local filesystem access could predict the path and plant a symlink, causing the downloaded archive to be written to an attacker-controlled location (arbitrary file write). The orphaned tempnam() file was also never cleaned up.
Solution: The temporary file strategy was replaced with a cryptographically random directory (128 bits via random_bytes(8) + bin2hex), created with mkdir() at permission 0700:
$tmpDir = sys_get_temp_dir() . '/zvec_ffi_' . bin2hex(random_bytes(8));
mkdir($tmpDir, 0700, true);
$tmpFile = $tmpDir . '/download.tar.gz';
Key properties:
- Defense-in-depth:
mkdir()with 0700 permissions creates a directory only the current user can access. An attacker cannot create symlinks inside a directory they cannot traverse. - Atomic creation:
mkdir()either succeeds or fails — there is no gap between existence check and use. - Single random name: 128 bits of cryptographic randomness (
random_bytes(8)= 16 hex chars) makes path prediction infeasible. - No stale files: The
finallyblock doesrm -rfon the entire temp directory, eliminating orphaned files. - No external dependencies: Uses only PHP built-in functions.
Status: Fixed in v0.4.12
Issue: SEC-001 (#70)
Problem: The Installer::install() method downloaded the FFI shared library without verifying its integrity. A compromised release artifact or man-in-the-middle attack could serve a malicious .so/.dylib file.
Solution: SHA-256 checksums are published alongside each release in checksums.sha256. Before extracting, Installer::verifyChecksum() computes hash_file('sha256', ...) and compares it against the expected hash using hash_equals() (timing-safe comparison).
Status: In Progress (SEC-004 #73)
All C++ FFI functions accept opaque handle types. When these are null (e.g., after destroy or invalid state), null-pointer dereference causes segfaults. The fix adds null-pointer guards to all 50+ handle-accepting functions.
- Local filesystem security: The temp directory fix (SEC-002) assumes the attacker already has local user access. It prevents privilege escalation via symlink attacks.
- TLS is not explicitly pinned: The download stream context sets
verify_peerandverify_peer_nameto true, relying on the system's CA bundle. No certificate pinning is implemented. - API keys in memory: Embedding function API keys are stored in PHP string properties. Starting from v0.4.12+,
__debugInfo()masks the key in var_dump output and__destruct()callssodium_memzero()when the sodium extension is available (see SEC-008).