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
```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