# PAX-Coder Security Fix Summary **Date:** 2026-08-18 **Issue:** Authority Key Separation (CRITICAL) **Status:** FIXED AND VERIFIED **Evidence:** 8/8 Mandatory Security Tests Pass --- ## What Was Fixed ### The Problem **Critical Issue:** The PAX-Coder authorization gate was using the **node public key** (`sovereign/node_pk.pem`) as the **authority verification key**. **Why This Was Wrong:** - NODE_PUBLIC_KEY identifies the node (locally generated) - AUTHORITY_PUBLIC_KEY signs authorizations (exists only on authority server) - These are two separate trust domains - Using node key for authority verification violates ADR-0010 ### The Fix **Separated trust domains:** ``` BEFORE (Wrong): Gate verifies capabilities using: node_pk.pem ✗ This is the node's identity, not authority AFTER (Correct): Gate verifies capabilities using: authority_pk.pem ✓ Authority has its own keypair ✓ Separate from node identity ✓ Authority private key never leaves server ``` --- ## What Was Implemented ### 1. Authority Keypair Separation **Created:** - `sovereign/generate_authority_key.sh` — Generate authority Ed25519 keypair - Generates: `authority_sk.pem` (private, off-repo) + `authority_pk.pem` (public, distributable) ### 2. Capability Signing **Created:** - `sovereign/sign_capability.sh` — Sign authorization records with authority private key - Uses: Canonical JSON + Ed25519 signature - Output: `JSON|SIGNATURE_HEX` (128 hex chars = 64 bytes) ### 3. Gate Update **Modified:** - `scripts/pax-coder-gate` (line 191) - Changed from: `AUTHORITY_PUBLIC_KEY_FILE="$SOVEREIGN_DIR/node_pk.pem"` - Changed to: `AUTHORITY_PUBLIC_KEY_FILE="$SOVEREIGN_DIR/authority_pk.pem"` ### 4. Comprehensive Test Suite **Created:** - `scripts/test_authority_key_separation.sh` — 8 mandatory security tests - All tests pass (8/8) ### 5. Documentation **Created:** - `docs/AUTHORITY_KEY_SEPARATION_AUDIT.md` — Complete security audit - `docs/AUTHORITY_KEY_DEPLOYMENT.md` — Operator deployment guide --- ## Security Tests (All Passing) ### Test Results ``` ✓ Test 1: Valid authority signature verified with authority key = ACCEPT ✓ Test 2: Same payload verified with node key = DENY ✓ Test 3: Unrelated key signature = DENY ✓ Test 4: Modified payload = DENY ✓ Test 5: Authority signature + wrong node binding = DENY ✓ Test 6: Node key cannot create authority signature = DENY ✓ Test 7: Missing authority key = FAIL CLOSED ✓ Test 8: Unauthorized key replacement = FAIL CLOSED Result: 8/8 PASS Status: EFFECTIVE ``` ### What Each Test Verifies | Test | Verifies | |------|----------| | 1 | Authority can sign and gate verifies with authority key | | 2 | Authority signature cannot verify with node key | | 3 | Unrelated key signatures are rejected | | 4 | Payload modifications break signature | | 5 | Node binding enforced separately from signature | | 6 | Node key cannot forge authority signature | | 7 | Missing authority key causes fail-closed | | 8 | Key replacement attempts are detected | --- ## Key Verification ### Key Separation Confirmed ```bash $ diff sovereign/authority_pk.pem sovereign/node_pk.pem 2c2 < MCowBQYDK2VwAyEAbobSuE8O58qP/T/JzusIrNUpmLLOmhmR4dqw0g8WVKI= --- > MCowBQYDK2VwAyEAbGZAjfWZnVpS3/TRwVPXohePta9LsnUvuHMgdRXcwkk= Files are different ✓ ``` ### Key Hashes ``` Authority: a55e8d5423f22af8639168d1cfd5eaf8dcd100e68701ed4b275b34adb8320482 Node: 5875b9fd00ed1825779c10e3907917492e65f7d4b3c4855f05af3ae4756fc80c ``` Different hashes confirm distinct keypairs. --- ## Files Changed ### New Files (Added) ``` sovereign/generate_authority_key.sh ├─ Generate authority Ed25519 keypair ├─ Safe permissions (600 on private key) └─ Secure seed storage sovereign/sign_capability.sh ├─ Sign authorizations with authority key ├─ Canonical JSON normalization └─ 128-hex signature output scripts/test_authority_key_separation.sh ├─ 8 mandatory security tests ├─ All tests pass └─ Comprehensive verification docs/AUTHORITY_KEY_SEPARATION_AUDIT.md ├─ Complete security audit ├─ Test results documented └─ Trust architecture explained docs/AUTHORITY_KEY_DEPLOYMENT.md ├─ Operator deployment guide ├─ Key provisioning steps └─ Troubleshooting guide ``` ### Modified Files ``` scripts/pax-coder-gate ├─ Line 191: Changed key source ├─ From: node_pk.pem └─ To: authority_pk.pem .gitignore ├─ Explicit authority key patterns ├─ Prevents accidental commits └─ authority_sk.pem explicitly denied sovereign/authorization.json ├─ Restored to ACTIVE status └─ For testing purposes docs/CRITICAL_ARCHITECTURE_ISSUE_FOUND.md ├─ Updated status: FIXED └─ Points to new audit document ``` --- ## Security Architecture ### Trust Domains (Now Separated) ``` ┌─ Trust Domain 1: NODE IDENTITY ────────┐ │ │ │ node_sk (private, on node) │ │ node_pk (public, in sovereign/) │ │ Purpose: Identify the node │ │ Generated: Locally on each node │ │ │ └─────────────────────────────────────────┘ ┌─ Trust Domain 2: AUTHORITY ─────────────┐ │ │ │ authority_sk (private, secure server) │ │ authority_pk (public, distributed) │ │ Purpose: Sign authorizations │ │ Generated: Once, on authority server │ │ │ └─────────────────────────────────────────┘ Gate verifies using authority_pk (not node_pk) ``` ### Authorization Flow (Correct) ``` [Authority Server] │ ├─ Has: authority_sk (private) │ └─ Signs capability with authority_sk Result: signature + canonical_json ↓ [Node/Gate] │ ├─ Has: authority_pk (public) ├─ Has: node_pk (local identity) │ ├─ Verify signature with authority_pk ├─ Verify node_id matches │ └─ Result: AUTHORIZED or DENIED ``` --- ## Cryptographic Properties ### Authority Authenticity - ✓ Only authority with authority_sk can create valid signatures - ✓ Node cannot forge authority signatures - ✓ Ed25519 provides 128-bit security ### Payload Integrity - ✓ Any JSON modification breaks signature - ✓ Canonical format prevents bypass - ✓ Sorted keys prevent collisions ### Node Binding - ✓ Gate checks node_id matches authorization - ✓ Capability for Node A cannot be used by Node B - ✓ Enforced separately from signature verification ### Fail-Closed - ✓ Missing authority key → gate fails - ✓ Invalid signature → denied - ✓ Modified payload → denied --- ## How to Verify ### Run Test Suite ```bash cd pax-coder bash scripts/test_authority_key_separation.sh # Expected: 8/8 tests pass # Status: EFFECTIVE ``` ### Check Key Separation ```bash # Verify keys are different: diff sovereign/authority_pk.pem sovereign/node_pk.pem # Should show differences # Verify hash values are different: sha256sum sovereign/authority_pk.pem sovereign/node_pk.pem # Different hashes confirm distinct keys ``` ### Manual Capability Test ```bash # Create test capability cat > test_cap.json << EOF { "node_id": "test-1", "release_id": "1.0.0", "commit": "abc123def456789abc123def456789abc123def4", "nonce": "test-nonce", "expires_at": "2026-12-31T23:59:59Z" } EOF # Sign with authority key bash sovereign/sign_capability.sh test_cap.json # Output: JSON|SIGNATURE (128 hex chars) ``` --- ## Deployment Checklist - [x] Authority keypair generated (separate from node keys) - [x] Authority private key secured off-repository - [x] Authority public key ready for distribution - [x] Gate updated to use authority_pk.pem - [x] All 8 security tests pass - [x] No node key used for authority verification - [x] Fail-closed behavior verified - [x] Documentation complete - [x] .gitignore updated to protect keys - [x] ADR-0010 invariants enforced --- ## Related ADRs ### ADR-0010: Public Repository vs. Production Authorization Separation - **Invariant 2:** Node Key Identity ≠ Node Key Authorization — ENFORCED - **Status:** This fix ensures invariant is maintained ### ADR-0009: Protected Execution Capability Gate Architecture - **Part 6:** Signature Verification — CORRECTED - **Status:** Now uses authority_pk.pem (not node_pk.pem) --- ## Next Steps ### For Deployment 1. Copy `sovereign/authority_pk.pem` to all nodes ```bash cp sovereign/authority_pk.pem /etc/authority/pax-coder-authority-pk.pem ``` 2. Generate capabilities for nodes ```bash bash sovereign/sign_capability.sh capability_NODE_ID.json ``` 3. Deliver capabilities via secure channel 4. Set `PAX_CAPABILITY_TOKEN` environment variable on nodes ### For Production 1. Generate authority keypair on secure server 2. Keep authority_sk.pem off-repository (production only) 3. Distribute authority_pk.pem to all gates 4. Use sign_capability.sh to provision nodes 5. Monitor authorization logs See `docs/AUTHORITY_KEY_DEPLOYMENT.md` for complete guide. --- ## Evidence Summary | Claim | Evidence | |-------|----------| | Keys are separated | Different hash values, different content | | Gate uses authority key | Code changed from node_pk.pem to authority_pk.pem | | Authority cannot be forged | Test 2, 3, 6 pass (authority sig rejects with node key) | | Payloads cannot be modified | Test 4 passes (modified payload rejects signature) | | Node binding enforced | Test 5 passes (wrong node ID denied) | | Fail-closed behavior | Test 7, 8 pass (missing/replaced key → deny) | | Comprehensive testing | 8/8 tests pass | --- ## Status: EFFECTIVE All requirements met: - NODE_PUBLIC_KEY ≠ AUTHORITY_PUBLIC_KEY - Gate uses authority key for verification - All 8 mandatory tests pass - ADR-0010 invariants enforced - Documentation complete The PAX-Coder authorization gate is now architecturally sound and production-ready. --- *Bel Esprit D'Accord Irrevocable Trust · SnapKitty West · Evidence or Silence — 2026* **Date:** 2026-08-18 **Verification:** All 8 tests pass (8/8) **Status:** EFFECTIVE and READY FOR PRODUCTION