| title | Security Evaluation Guide |
|---|---|
| description | Security evaluation guide for CISOs and security teams assessing QP Tunnel for organizational adoption. Covers cryptographic inventory, key management, attack surface, input validation, audit integrity, dependencies, threat model, and FIPS considerations. |
| date_modified | 2026-04-04 |
| classification | Public |
| ai_context | CISO-targeted security evaluation of QP Tunnel. Covers two-layer crypto (WireGuard outer + PQ TLS inner), key management (file-based, umask 077, auto-generated), input validation (strict regex, no eval), audit trail with optional Capsule Protocol sealing, dependency audit (bash, jq, WireGuard, Caddy), STRIDE threat model, FIPS gap analysis, and evaluation checklist. Source: lib/ (common.sh, registry.sh, audit.sh, wireguard.sh, open.sh). |
For CISOs and Security Teams Evaluating QP Tunnel
QP Tunnel v0.1.0, April 2026 Classification: Public
QP Tunnel is a WireGuard VPN automation toolkit that provides encrypted remote access to on-premises devices. It wraps WireGuard with automated peer management, key rotation, service exposure, and cryptographic audit logging.
The security proposition in four sentences:
- WireGuard provides the outer tunnel with Curve25519 key exchange and ChaCha20-Poly1305 encryption.
- Exposed services add an inner PQ TLS 1.3 layer with ML-KEM-768 hybrid key exchange and AES-256-GCM encryption.
- Every operation is logged as structured JSON with optional Capsule Protocol sealing (SHA3-256 + Ed25519) for tamper-evident audit trails.
- Peer revocation is immediate: removal from the live WireGuard interface, not dependent on session timeouts or grace periods.
| Algorithm | Standard | Purpose | Notes |
|---|---|---|---|
| Curve25519 (X25519) | RFC 7748 | Key exchange | Fixed in WireGuard protocol |
| ChaCha20-Poly1305 | RFC 8439 | Authenticated encryption | Fixed in WireGuard protocol |
| BLAKE2s | RFC 7693 | Hashing, key derivation | Fixed in WireGuard protocol |
| HKDF | RFC 5869 | Key derivation | Fixed in WireGuard protocol |
These are hardcoded in WireGuard and cannot be changed or configured.
| Algorithm | Standard | Purpose | Notes |
|---|---|---|---|
| X25519MLKEM768 | FIPS 203 (hybrid) | Key exchange | Post-quantum hybrid (classical + PQ) |
| AES-256-GCM | FIPS 197 / SP 800-38D | Authenticated encryption | FIPS-approved |
| Ed25519 | RFC 8032 / FIPS 186-5 | Certificate signatures (internal CA) | All certs use Ed25519 |
The inner layer is implemented by Caddy built with Go 1.24+, which includes ML-KEM-768 in the standard library.
| Algorithm | Purpose | Per-Peer |
|---|---|---|
| Curve25519 keypair | Asymmetric identity | Yes, unique keypair per peer |
| 256-bit preshared key | Additional symmetric layer | Yes, unique PSK per peer |
Each peer has two independent identity credentials. The preshared key provides an additional layer of symmetric encryption within the WireGuard handshake.
| Algorithm | Standard | Purpose |
|---|---|---|
| SHA3-256 | FIPS 202 | Content integrity hashing |
| Ed25519 | FIPS 186-5 | Non-repudiation signatures |
Activated when qp-capsule is installed. See the Capsule Security Evaluation for the full cryptographic analysis of the audit layer.
| Algorithm | Status |
|---|---|
| SHA-1 | Not used |
| MD5 | Not used |
| RSA | Not used |
| DES / 3DES | Not used |
| RC4 | Not used |
| Key Type | Generated By | Source of Randomness |
|---|---|---|
| WireGuard keypairs | wg genkey / wg pubkey |
/dev/urandom via WireGuard |
| Preshared keys | wg genpsk |
/dev/urandom via WireGuard |
| CA private key | openssl genpkey -algorithm Ed25519 |
OpenSSL CSPRNG |
| Service TLS keys | openssl genpkey -algorithm Ed25519 |
OpenSSL CSPRNG |
All key generation calls set_safe_umask (umask 077) before any write operation. Private keys are captured via command substitution and written directly to files. They never appear in terminal output, environment variables, logs, or the audit trail.
| Key | Default Location | Permissions |
|---|---|---|
| Relay private key | ~/.config/qp-tunnel/relay.key |
0600 |
| Peer preshared key | ~/.config/qp-tunnel/peers/<name>/preshared.key |
0600 |
| CA private key | ~/.config/qp-tunnel/tls/ca.key |
0600 |
| Service TLS key | ~/.config/qp-tunnel/tls/<name>.key |
0600 |
| Config directory | ~/.config/qp-tunnel/ |
0700 |
Permissions are enforced with both umask (at creation time) and explicit chmod after write.
tunnel-rotate-keys.sh handles relay key rotation:
- Dry-run by default (shows planned changes, modifies nothing)
- On confirm: generates new keypair, backs up old keys to
key-backups/, updates WireGuard config, restarts interface - All active peers require new configs after relay key rotation
- Rotation event recorded in audit log with Capsule sealing
Recommended rotation schedule:
| Environment | Interval |
|---|---|
| Standard | 90 days |
| High-security | 30 days |
| Post-departure | Immediately when someone with relay access leaves |
Peer revocation is immediate and total:
- Peer removed from the live WireGuard interface (
wg set ... peer ... remove) - Config files archived to
archive/(never deleted, for compliance) - Registry entry marked
"status": "revoked"with timestamp - Audit log entry created with Capsule seal
There is no grace period, no session expiry timer, no propagation delay. The moment tunnel-remove-peer.sh executes, the peer can no longer reach the tunnel.
| Surface | Exposure | Mitigation |
|---|---|---|
| WireGuard UDP port (51820) | Public internet | WireGuard's cryptographic handshake rejects unauthenticated packets silently |
| Service TLS ports (8443-8499) | Tunnel subnet only | Bound to tunnel interface IP; firewall rules restrict to 10.8.0.0/24 |
| SSH on relay (if used) | Public internet (setup only) | Standard SSH hardening applies |
| Component | Why It Is Safe |
|---|---|
| Local services (upstream) | Caddy proxies locally; upstream ports are not externally reachable |
| State files (peers.json, etc.) | Mode 600, inside mode 700 directory, local filesystem only |
| Private keys | Mode 600, never logged, never output to terminal |
| Audit log | Append-only by design; Capsule sealing provides tamper evidence |
WireGuard responds to nothing from unauthenticated sources. It does not respond to pings, port scans, or malformed packets. From an attacker's perspective, the WireGuard port appears closed. The protocol only responds to valid handshake initiations from peers with known public keys.
All peer names pass through strict regex validation:
^[a-zA-Z0-9_-]+$This prevents:
| Attack | How It Is Prevented |
|---|---|
| Command injection | No shell metacharacters allowed (;, ` |
| Path traversal | No slashes or dots allowed (/, ..) |
| Null byte injection | No null bytes in the regex character class |
| Whitespace injection | No spaces or tabs allowed |
The word eval does not appear anywhere in the codebase. This eliminates the entire category of code injection through dynamic evaluation.
require_env checks that required variables are set and non-empty before any operation proceeds. require_cmd verifies that required commands exist on PATH.
The audit system validates that details parameters are valid JSON before writing. Invalid JSON falls back to an empty object rather than writing malformed data.
Registry initialization checks peers.json validity with jq empty. Corrupt files are backed up and reinitialized rather than silently used.
| Layer | Format | Integrity | Purpose |
|---|---|---|---|
| JSONL log | audit.log |
Append-only file | Fast local index, human-readable |
| Capsule database | capsules.db |
SHA3-256 + Ed25519 signed, hash-chained | Tamper-evident cryptographic proof |
| WireGuard logs | systemd journal | OS-level | Transport-layer events |
- Structured. Every entry is valid JSON with timestamp, action, status, message, user, and details.
- Token-masked. API tokens are replaced with asterisks before writing (last 4 characters visible).
- Error-trapped. Every script uses
set -euo pipefailwith an ERR trap that writes a failure entry on any unhandled error, including script name and line number. - Atomic appends. Each entry is written as a single
printfto prevent partial writes.
When qp-capsule is installed, every audit entry is additionally sealed as a Capsule:
- Content hashed with SHA3-256 (FIPS 202)
- Hash signed with Ed25519 (FIPS 186-5)
- Linked to previous Capsule via hash chain
Tampering with any record invalidates its signature and breaks the chain for all subsequent records. Verification: qp-capsule verify --db capsules.db.
If qp-capsule is not available, audit logging continues normally. Capsule sealing never blocks normal operations and never causes script failures (errors are swallowed with || true).
| Package | License | Purpose | Attack Surface |
|---|---|---|---|
bash 4.0+ |
GPL-3.0 | Shell runtime | Standard system utility |
jq |
MIT | JSON processing for state files | Processes only local, validated JSON |
wg, wg-quick |
GPL-2.0 | WireGuard tools | Kernel-level crypto, minimal userspace |
Total: 3 required dependencies. All are standard Linux distribution packages.
| Package | License | Purpose | When Needed |
|---|---|---|---|
caddy |
Apache 2.0 | PQ TLS reverse proxy | tunnel-open only |
openssl |
Apache 2.0 | Certificate generation | tunnel-open only |
qrencode |
GPL-2.0+ | QR codes for mobile setup | tunnel-add-peer (optional) |
qp-capsule |
Apache 2.0 | Tamper-evident audit sealing | Audit hardening (optional) |
doctl |
Apache 2.0 | DigitalOcean CLI | DO provider only (curl fallback exists) |
ssh |
BSD | Remote relay setup | SSH provider only |
None after initial setup. Once the relay is provisioned and peers are configured, QP Tunnel operates with zero internet dependencies. The WireGuard tunnel functions over any IP network, including air-gapped networks with manual peer configuration.
The only network-dependent operations are relay provisioning (SSH or API calls to DigitalOcean) and optional qp-capsule auto-installation via pip. Both are one-time setup operations.
| Threat | Mitigation |
|---|---|
| Attacker impersonates relay | Every peer validates the relay's Curve25519 public key during handshake. Wrong key = connection refused. |
| Attacker impersonates peer | Unique keypair + unique preshared key per peer. Spoofing requires both the private key and PSK. |
| Attacker forges TLS certificate | Per-service certs signed by internal Ed25519 CA. Clients trust only this CA. |
| Threat | Mitigation |
|---|---|
| Modify traffic in transit | WireGuard's ChaCha20-Poly1305 provides authenticated encryption. Inner TLS adds AES-256-GCM. |
| Modify audit records | Capsule Protocol sealing with SHA3-256 hash + Ed25519 signature + hash chain. |
| Modify state files | File permissions (600/700). Corrupt files are detected via jq validation and backed up. |
| Threat | Mitigation |
|---|---|
| Deny performing an operation | Every operation writes to audit.log with timestamp, username, and details. |
| Deny audit record existed | Capsule Protocol hash chain links every record. Deletion breaks the chain. |
| Threat | Mitigation |
|---|---|
| Key material leaked in logs | Private keys are never logged. Token masking on API credentials. |
| Traffic interception | Double encryption (WireGuard + PQ TLS). |
| State file exposure | Mode 600 files in mode 700 directory. |
| Relay operator reads traffic | Relay cannot decrypt (lacks peer private keys). It forwards encrypted packets only. |
| Threat | Mitigation |
|---|---|
| Flood WireGuard port | WireGuard silently drops invalid packets with minimal CPU cost (no handshake response to unknown peers). |
| Exhaust IP pool | Pool supports 244 peers. Sequential allocation. Exhaustion requires 244 active peers. |
| Kill Caddy process | PID file tracks process. Restart with tunnel-open (idempotent). |
| Threat | Mitigation |
|---|---|
| Peer accesses unauthorized services | Split-tunnel routes only tunnel subnet. Services bound to tunnel interface IP only. Firewall rules restrict per-service. |
| Shell injection via peer name | Strict [a-zA-Z0-9_-] validation. No eval anywhere. |
| Compromised relay gains access to target | Relay has no credentials for the target device. It forwards packets. Target's WireGuard rejects unauthorized peers. |
WireGuard uses ChaCha20-Poly1305 for symmetric encryption. ChaCha20-Poly1305 is a respected, widely-deployed cipher, but it is not FIPS 140-2 or FIPS 140-3 validated. No WireGuard implementation has undergone FIPS validation.
This is a protocol-level constraint, not a QP Tunnel limitation. No WireGuard-based solution can claim FIPS compliance for the transport layer.
| Mitigation | FIPS Status |
|---|---|
| Inner PQ TLS uses AES-256-GCM | FIPS 197 / SP 800-38D (FIPS-approved algorithm) |
| Inner PQ TLS uses ML-KEM-768 | FIPS 203 (NIST-standardized) |
| Certificate signatures use Ed25519 | FIPS 186-5 (FIPS-approved) |
| Audit hashing uses SHA3-256 | FIPS 202 (FIPS-approved) |
| Audit signatures use Ed25519 | FIPS 186-5 (FIPS-approved) |
| Environment | Recommendation |
|---|---|
| Commercial, healthcare, most government | QP Tunnel is appropriate. WireGuard's crypto is sound; FIPS validation is a paperwork gap, not a security gap. |
| FedRAMP High, CMMC with FIPS mandate | Substitute IPsec with FIPS-validated modules for the transport layer. The inner PQ TLS and audit layers are FIPS-approved. |
| Classified (SECRET and above) | No software VPN qualifies. NSA-approved hardware encryption devices (Type 1) are required. This is a universal requirement. |
The relay is the only component with a public IP. Harden it:
- Disable password-based SSH authentication (key-only)
- Enable automatic security updates (
unattended-upgradesor equivalent) - Restrict SSH access to known IPs if possible
- Monitor WireGuard and SSH logs via your SIEM
Back up ~/.config/qp-tunnel/ to encrypted storage. The directory contains all state, keys, and audit history. Loss of this directory means loss of the ability to manage the tunnel.
The internal CA has a 10-year validity. Per-service certificates have a 1-year validity. Monitor certificate expiration via tunnel-list and regenerate before expiry by closing and re-opening the service.
The state directory is single-user by default (mode 700). For multi-operator scenarios, use a shared service account or deploy the state directory to a shared volume with appropriate group permissions.
| Criterion | Status | Detail |
|---|---|---|
| Uses well-reviewed transport encryption | Yes | WireGuard (kernel-level, formally verified protocol) |
| Post-quantum protection available | Yes | ML-KEM-768 via inner PQ TLS 1.3 (tunnel-open) |
| Unique identity per peer | Yes | Unique Curve25519 keypair + unique preshared key |
| Immediate revocation | Yes | Hot-remove from live WireGuard interface |
| Key rotation support | Yes | Built-in with dry-run safety and automatic backup |
| Private keys protected at rest | Yes | File permissions 0600, umask 077 at creation |
| Input validation | Yes | Strict [a-zA-Z0-9_-] regex on all user input |
| No dynamic code evaluation | Yes | Zero uses of eval in entire codebase |
| Structured audit logging | Yes | JSONL with timestamp, user, action, status, details |
| Tamper-evident audit trail | Optional | Capsule Protocol sealing (SHA3-256 + Ed25519 + hash chain) |
| Split-tunnel routing | Yes | Only VPN subnet routed through tunnel |
| Service isolation | Yes | Ports bound to tunnel interface + per-service firewall rules |
| Minimal dependency footprint | Yes | 3 required dependencies (bash, jq, wireguard-tools) |
| Air-gapped operation | Yes | No network dependencies after initial setup |
| Token/credential masking | Yes | API tokens masked in all log output |
| Error handling | Yes | set -euo pipefail + ERR trap with audit logging |
| Archival of revoked credentials | Yes | Revoked configs archived, never deleted |
| FIPS 140-2/3 validated module | No | WireGuard uses ChaCha20-Poly1305 (not FIPS-validated); inner TLS uses FIPS-approved algorithms |
| No telemetry or phone-home | Yes | Zero external network calls at runtime |
| Open source | Yes | Apache 2.0 license |
| Test coverage | Yes | 420+ tests across unit, integration, and smoke tiers (bats-core) |
- Architecture -- Double-encryption model, component design, state management
- Cryptographic Notice -- WireGuard primitives and PQ tradeoff analysis
- Why QP Tunnel -- Business case and competitive positioning
- SECURITY.md -- Vulnerability reporting
QP Tunnel v0.1.0, Quantum Pipes Technologies, LLC