FIX7 Authority-Seal Red-Team Adversarial Suite (20 attacks)
#!/usr/bin/env python3
============================================================================
FIX7 AUTHORITY-SEAL -- RED-TEAM ADVERSARIAL SUITE (20 attacks)
Attacks the full N7->N8->P7 seal protocol + the spec/doc/governance layer.
Every required attack MUST be CAUGHT (fail-closed at encode, verify-mismatch,
drift-detected, or rejected by a governance guard). If ANY attack is NOT
caught (i.e. it could forge the canonical seal or slip past silently) the
suite exits nonzero and the contract is treated as DEFECTIVE.
Mechanism classes:
ENCODE_FAIL_CLOSED -- encoder raises the exact Reject status
VERIFY_MISMATCH -- produced digest != canonical => verify_pin/compare fails
DRIFT_DETECTED -- drift checker flags spec/code/doc disagreement
GUARD_REJECT -- a governance guard refuses the tampered artifact
CYCLE_DETECTED -- has_cycle() true on a tampered edge set
Usage: python3 authority_seal_redteam.py [rehearsal_dir]
============================================================================
import json, re, sys, os, hashlib, copy import authority_seal_encoder as E
REH = sys.argv[1] if len(sys.argv) > 1 else "../rehearsal"
results = [] def record(aid, desc, caught, mechanism, detail=""): results.append({"id": aid, "desc": desc, "caught": caught, "mechanism": mechanism, "detail": detail})
def reject_status(fn): try: fn(); return None except E.Reject as e: return e.status
canonical fixture seal chain (the values a forger would try to reproduce)
N7 = E.encode_node("N7", E.fixture_n7_pairs()) N8 = E.encode_node("N8", E.fixture_n8_pairs(N7)) P7 = E.seal_p7(E.fixture_p7_pairs(N7, N8))
---- 1. delete N7 required field ----
s = reject_status(lambda: E.encode_node("N7", E.fixture_n7_pairs()[:-1])) record(1, "delete N7 required field", s == "SEAL_INPUT_MISSING", "ENCODE_FAIL_CLOSED", s)
---- 2. add extra N7 field ----
s = reject_status(lambda: E.encode_node("N7", E.fixture_n7_pairs() + [("rogue", "x")])) record(2, "add extra N7 field", s == "SEAL_INPUT_EXTRA", "ENCODE_FAIL_CLOSED", s)
---- 3. reorder N7 field ----
sw = E.fixture_n7_pairs(); sw[2], sw[3] = sw[3], sw[2] s = reject_status(lambda: E.encode_node("N7", sw)) record(3, "reorder N7 field", s == "SEAL_FIELD_ORDER_MISMATCH", "ENCODE_FAIL_CLOSED", s)
---- 4. wrong N7 domain tag ----
s = reject_status(lambda: E.encode_node("N7", E.fixture_n7_pairs(), claimed_tag="EVIL_V1")) record(4, "wrong N7 domain tag", s == "SEAL_DOMAIN_TAG_MISMATCH", "ENCODE_FAIL_CLOSED", s)
---- 5. N7 tries to bind N8 (cycle) ----
s = reject_status(lambda: E.encode_node("N7", E.fixture_n7_pairs() + [("detached_seal_sha256", N8)])) record(5, "N7 binds N8 -> cycle", s == "SEAL_HASH_GRAPH_CYCLE", "ENCODE_FAIL_CLOSED", s)
---- 6. N8 missing N7 ----
n8_no_n7 = [p for p in E.fixture_n8_pairs(N7) if p[0] != "envelope_manifest_sha256"] s = reject_status(lambda: E.encode_node("N8", n8_no_n7)) record(6, "N8 missing N7", s == "SEAL_INPUT_MISSING", "ENCODE_FAIL_CLOSED", s)
---- 7. N8 wrong signer representation ----
7a structural injection (TAB byte in signer) -> fail-closed
inj = E.fixture_n8_pairs(N7) inj[6] = ("sealed_by", "CODEX\tINJECT") s7a = reject_status(lambda: E.encode_node("N8", inj))
7b byte-clean wrong signer -> different digest, cannot forge canonical N8
clean = E.fixture_n8_pairs(N7); clean[6] = ("sealed_by", "ATTACKER-NOT-CODEX") forged = E.encode_node("N8", clean) caught7 = (s7a == "SEAL_FIELD_FORBIDDEN_BYTE") and (forged != N8) record(7, "N8 wrong signer representation", caught7, "ENCODE_FAIL_CLOSED+VERIFY_MISMATCH", f"inject={s7a}; clean_forged_eq_canonical={forged == N8}")
---- 8. N8 wrong timestamp format ----
8a structural injection (backslash) -> fail-closed
inj8 = E.fixture_n8_pairs(N7); inj8[7] = ("sealed_at", "2026\06\10") s8a = reject_status(lambda: E.encode_node("N8", inj8))
8b byte-clean wrong format -> different digest (tamper-evident). NOTE: semantic
timestamp-FORMAT validation is intentionally OUT OF CONTRACT SCOPE (Codex
supplies the authority timestamp); the contract guarantees tamper-evidence,
not format policing. A wrong-but-clean timestamp simply yields a non-canonical
seal that fails verify against the expected pin.
clean8 = E.fixture_n8_pairs(N7); clean8[7] = ("sealed_at", "10/06/2026 wrong") forged8 = E.encode_node("N8", clean8) caught8 = (s8a == "SEAL_FIELD_FORBIDDEN_BYTE") and (forged8 != N8) record(8, "N8 wrong timestamp format", caught8, "ENCODE_FAIL_CLOSED+VERIFY_MISMATCH", f"inject={s8a}; clean_forged_eq_canonical={forged8 == N8}; " f"semantic-format-validation=OUT_OF_CONTRACT_SCOPE(Codex-supplied)")
---- 9. P7 missing canonicalizer hash ----
p7_no_canon = [p for p in E.fixture_p7_pairs(N7, N8) if p[0] != "pinned_canonicalizer_sha256"] s = reject_status(lambda: E.encode_node("P7", p7_no_canon)) record(9, "P7 missing canonicalizer hash", s == "SEAL_INPUT_MISSING", "ENCODE_FAIL_CLOSED", s)
---- 10. P7 mutated canonicalizer hash ----
mut = E.fixture_p7_pairs(N7, N8); mut[5] = ("pinned_canonicalizer_sha256", "0"*64) record(10, "P7 mutated canonicalizer hash", not E.verify_pin(P7, mut), "VERIFY_MISMATCH")
---- 11. P7 mutated Packet V3 tree ----
mut2 = E.fixture_p7_pairs(N7, N8); mut2[6] = ("pinned_packet_v3_tree_sha256", "0"*64) record(11, "P7 mutated Packet V3 tree", not E.verify_pin(P7, mut2), "VERIFY_MISMATCH")
---- 12. prose-only P7 pin ----
s = reject_status(lambda: E.seal_p7(E.fixture_p7_pairs(N7, N8), prose_only=True)) record(12, "prose-only P7 pin", s == "SEAL_PROSE_ONLY_PIN_REJECTED", "ENCODE_FAIL_CLOSED", s)
---- 13. spec.json drift from encoder ----
tamper a copy of the spec rosters; the equality compare must flag drift
sj = json.load(open(os.path.join(os.path.dirname(file) or ".", "authority-seal-encoder-spec.json"))) tampered = copy.deepcopy(sj); tampered["rosters"]["N7"][2] = "tampered_field" record(13, "spec.json drift from encoder", E.ROSTERS == sj["rosters"] and E.ROSTERS != tampered["rosters"], "DRIFT_DETECTED", "clean matches, tampered differs")
---- 14. spec.md claims a field not in encoder ----
md = open(os.path.join(os.path.dirname(file) or ".", "authority-seal-encoder-spec.md"), encoding="utf-8").read()
def md_roster_n7(text):
i = text.index("## 3. N7"); j = text.index("## 4. N8")
return [m.group(1) for line in text[i:j].splitlines()
for m in [re.match(r"\s*|\s*\d+\s*|\s*([a-z0-9_]+)", line)] if m]
clean_md = md_roster_n7(md)
tampered_md = clean_md[:3] + ["ghost_field"] + clean_md[3:]
record(14, "spec.md claims a field not in encoder",
clean_md == E.ROSTERS["N7"] and tampered_md != E.ROSTERS["N7"],
"DRIFT_DETECTED", "clean matches encoder, +ghost_field differs")
---- 15. encoder extra authority field not in spec ----
enc_extra = E.ROSTERS["N7"] + ["secret_backdoor_field"] record(15, "encoder extra authority field not in spec", enc_extra != sj["rosters"]["N7"], "DRIFT_DETECTED", "an encoder roster with an extra field would not equal spec.json")
---- 16. fixture labelled as real seal ----
def guard_not_a_seal(artifact): n = artifact.get("NOT_A_SEAL", {}) if n.get("ARTIFACT_CLASS") != "REHEARSAL_ONLY_NOT_A_SEAL": raise E.Reject("SEAL_FIXTURE_CLASS_MISSING", "no NOT_A_SEAL banner") if any(n.get(k) for k in ("is_real_n7", "is_real_n8", "is_real_p7", "is_owner_final_seal", "is_codex_seal")): raise E.Reject("SEAL_FIXTURE_CLAIMS_REAL", "fixture flagged as real seal") return True art = json.load(open(os.path.join(REH, "n7-rehearsal-artifact.json"))) clean_ok = guard_not_a_seal(art) forged_art = copy.deepcopy(art); forged_art["NOT_A_SEAL"]["is_real_n7"] = True s = reject_status(lambda: guard_not_a_seal(forged_art)) record(16, "fixture labelled as real seal", clean_ok and s == "SEAL_FIXTURE_CLAIMS_REAL", "GUARD_REJECT", s)
---- 17. owner authorization expanded to implementation ----
bad = E.fixture_n7_pairs(); bad[-1] = ("approval_scope", "IMPLEMENTATION_ALLOWED") s = reject_status(lambda: E.encode_node("N7", bad)) record(17, "owner authorization expanded to implementation", s == "SEAL_CONSTANT_FIELD_MISMATCH", "ENCODE_FAIL_CLOSED", s)
---- 18. production gate removed from checklist ----
def guard_checklist(text): required = ["Codex/authority seal complete", "Owner approval of the implementation macro", "Forbidden mutations (standing)", "Rollback requirement"] missing = [r for r in required if r not in text] if missing: raise E.Reject("SEAL_PRODUCTION_GATE_MISSING", f"{missing}") return True chk = open(os.path.join(os.path.dirname(file) or ".", "fix7-implementation-precondition-checklist.md"), encoding="utf-8").read() clean_chk = guard_checklist(chk) tampered_chk = chk.replace("Forbidden mutations (standing)", "Allowed everything") s = reject_status(lambda: guard_checklist(tampered_chk)) record(18, "production gate removed from checklist", clean_chk and s == "SEAL_PRODUCTION_GATE_MISSING", "GUARD_REJECT", s)
---- 19. unknown dependency edge added ----
ev = {k: list(v) for k, v in E.EDGES.items()}; ev["N7"] = ev["N7"] + ["N8"] record(19, "unknown dependency edge added (N7->N8)", (not E.has_cycle(E.EDGES)) and E.has_cycle(ev), "CYCLE_DETECTED", "clean acyclic, injected edge -> cycle")
---- 20. hash manifest tamper ----
build a manifest of the rehearsal artifacts, tamper one line, re-verify
files = sorted(f for f in os.listdir(REH) if os.path.isfile(os.path.join(REH, f))) manifest = {f: hashlib.sha256(open(os.path.join(REH, f), "rb").read()).hexdigest() for f in files} tampered_manifest = dict(manifest) victim = files[0] tampered_manifest[victim] = "0"*64
verifier recomputes and compares
def verify_manifest(man): return all(man[f] == hashlib.sha256(open(os.path.join(REH, f), "rb").read()).hexdigest() for f in man) record(20, "hash manifest tamper", verify_manifest(manifest) and not verify_manifest(tampered_manifest), "VERIFY_MISMATCH", f"tampered {victim}")
---------- report ----------
caught = sum(1 for r in results if r["caught"]) for r in results: flag = "CAUGHT" if r["caught"] else "*** ESCAPED ***" print(f" [{flag}] A{r['id']:<2} {r['desc']} ({r['mechanism']})" + (f" {r['detail']}" if r["detail"] else "")) print(f"RED-TEAM: {caught}/{len(results)} attacks caught; escaped={len(results)-caught}") out = {"caught": caught, "total": len(results), "attacks": results, "canonical_fixture": {"N7": N7, "N8": N8, "P7": P7}} json.dump(out, open(os.path.join(REH, "redteam-results.json"), "w"), indent=2) sys.exit(0 if caught == len(results) else 1)