pax-coder / SECURITY_FIX_SUMMARY.md
SNAPKITTYWEST's picture
chore: push pax-coder from SNAPKITTYWEST GitHub
ef6eb55 verified
|
Raw History Blame Contribute Delete
10.9 kB

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

$ 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

cd pax-coder
bash scripts/test_authority_key_separation.sh

# Expected: 8/8 tests pass
# Status: EFFECTIVE

Check Key Separation

# 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

# 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

  • Authority keypair generated (separate from node keys)
  • Authority private key secured off-repository
  • Authority public key ready for distribution
  • Gate updated to use authority_pk.pem
  • All 8 security tests pass
  • No node key used for authority verification
  • Fail-closed behavior verified
  • Documentation complete
  • .gitignore updated to protect keys
  • 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

    cp sovereign/authority_pk.pem /etc/authority/pax-coder-authority-pk.pem
    
  2. Generate capabilities for nodes

    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