diff --git a/Makefile b/Makefile index 53e84e7..e4fb933 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,8 @@ validate: $(PY) tools/check_fog_node.py --check-contract contracts/fog-node.contract.json --receipt evidence/fog-node.check-receipt.json @echo "--- Validating host-interface envelopes ---" @$(MAKE) --no-print-directory validate-host-interfaces PY=$(PY) + @echo "--- Validating seam registry (13 seams) ---" + $(PY) tools/validate_seam_registry.py validate-host-interfaces: @echo "GOOD host-interface envelopes (must pass):" diff --git a/contracts/seam-registry.json b/contracts/seam-registry.json new file mode 100644 index 0000000..1a85521 --- /dev/null +++ b/contracts/seam-registry.json @@ -0,0 +1,261 @@ +[ + { + "type": "SeamDefinition", + "seam_id": "SEAM-001", + "name": "EFI/NVRAM \u2192 OS", + "boundary_from": "EFI/NVRAM", + "boundary_to": "OS", + "attack_vector": "efi_rootkit.bin; csr-active-config=0x67 (SIP disabled)", + "known_exploits": [], + "gate_requirements": [ + "boot attestation" + ], + "implementation_status": "open", + "linked_repos": [ + "SourceOS-Linux/agent-machine#T2-3" + ], + "priority": "critical", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-002", + "name": "MDM \u2192 usernoted", + "boundary_from": "MDM", + "boundary_to": "usernoted", + "attack_vector": "Unauthorized MDM enrollment (IBM MaaS360)", + "known_exploits": [], + "gate_requirements": [ + "MDM profile audit: flag unrecognized profiles" + ], + "implementation_status": "open", + "linked_repos": [ + "SourceOS-Linux/agent-machine#T2-3" + ], + "priority": "critical", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-003", + "name": "SEP \u2192 Keybag", + "boundary_from": "SEP", + "boundary_to": "Keybag", + "attack_vector": "SEP non-participation in keybag operations (ANOMALY-007)", + "known_exploits": [], + "gate_requirements": [ + "SEP participation check" + ], + "implementation_status": "open", + "linked_repos": [ + "SourceOS-Linux/agent-machine#T2-3" + ], + "priority": "critical", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-004", + "name": "DNS \u2192 Application", + "boundary_from": "DNS", + "boundary_to": "Application", + "attack_vector": "Resolution returning 102.165.31.x (adversary IPs)", + "known_exploits": [], + "gate_requirements": [ + "DNS pinning", + "DNSSEC" + ], + "implementation_status": "open", + "linked_repos": [ + "SociOS-Linux/source-os#linux/dns-pinning" + ], + "priority": "critical", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-005", + "name": "TLS \u2192 Cipher Suite", + "boundary_from": "TLS", + "boundary_to": "CipherSuite", + "attack_vector": "RC4_128_MD5 cipher downgrade", + "known_exploits": [], + "gate_requirements": [ + "TLS 1.2 minimum", + "cipher allowlist" + ], + "implementation_status": "open", + "linked_repos": [ + "SociOS-Linux/source-os#linux/tls-enforcement" + ], + "priority": "critical", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-006", + "name": "OAuth Token \u2192 Device", + "boundary_from": "OAuthToken", + "boundary_to": "Device", + "attack_vector": "Token exfiltration via MITM", + "known_exploits": [], + "gate_requirements": [ + "device-bound tokens" + ], + "implementation_status": "open", + "linked_repos": [ + "SocioProphet/mcp-a2a-zero-trust" + ], + "priority": "high", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-007", + "name": "Knox/MDM \u2192 Android", + "boundary_from": "Knox/MDM", + "boundary_to": "Android", + "attack_vector": "Knox privilege above Android permissions", + "known_exploits": [], + "gate_requirements": [ + "Knox audit", + "SemWifiSwitch check" + ], + "implementation_status": "open", + "linked_repos": [ + "future" + ], + "priority": "medium", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-008", + "name": "ManagedSpace \u2192 Spatial Auth", + "boundary_from": "ManagedSpace", + "boundary_to": "SpatialAuthorization", + "attack_vector": "displayUUID instability from firmware manipulation (ANOMALY-008)", + "known_exploits": [], + "gate_requirements": [ + "displayUUID stability check", + "attestation timestamp on spatial authorization" + ], + "implementation_status": "open", + "linked_repos": [ + "SourceOS-Linux/agent-machine#T2-3" + ], + "priority": "high", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-009", + "name": "Intelligence \u2192 Action Auth", + "boundary_from": "Intelligence", + "boundary_to": "ActionAuthorization", + "attack_vector": "Agent self-authorizing actions", + "known_exploits": [], + "gate_requirements": [ + "dndAllowIntelligentManagement:false enforced", + "autonomous_action gated" + ], + "implementation_status": "partially_gated", + "linked_repos": [ + "SocioProphet/ontogenesis#T1-4", + "SocioProphet/mcp-a2a-zero-trust#T4-2" + ], + "priority": "high", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-010", + "name": "Workflow Def \u2192 Execution", + "boundary_from": "WorkflowDefinition", + "boundary_to": "Execution", + "attack_vector": "Unsigned workflow injected", + "known_exploits": [], + "gate_requirements": [ + "workflow signing", + "state-machine admission gate" + ], + "implementation_status": "designed", + "linked_repos": [ + "SociOS-Linux/source-os", + "SourceOS-Linux/agent-machine" + ], + "priority": "high", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-011", + "name": "Agent Output \u2192 Ledger", + "boundary_from": "AgentOutput", + "boundary_to": "Ledger", + "attack_vector": "Local ledger tampered by MDM operator", + "known_exploits": [], + "gate_requirements": [ + "external append-only ledger", + "crypto hash chain" + ], + "implementation_status": "designed", + "linked_repos": [ + "SourceOS-Linux/agent-machine#T2-3", + "SociOS-Linux/source-os#T6-2" + ], + "priority": "critical", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-012", + "name": "Third-Party \u2192 Audio/Camera", + "boundary_from": "ThirdParty", + "boundary_to": "Audio/Camera", + "attack_vector": "avfoundation access undeclared", + "known_exploits": [], + "gate_requirements": [ + "avfoundation access logged", + "undeclared access = kill switch" + ], + "implementation_status": "open", + "linked_repos": [ + "SociOS-Linux/source-os#T6-2" + ], + "priority": "high", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + }, + { + "type": "SeamDefinition", + "seam_id": "SEAM-013", + "name": "Claude Desktop Telemetry \u2192 Platform Data", + "boundary_from": "ClaudeDesktopTelemetry", + "boundary_to": "PlatformData", + "attack_vector": "sessionSampleRate:100 (100% of sessions); sensitive output can route through a fully-sampled telemetry surface", + "known_exploits": [], + "gate_requirements": [ + "telemetry boundary check in ActivationDecision (advisory)", + "sensitive output must not route through a 100%-sampled surface" + ], + "implementation_status": "open", + "linked_repos": [ + "SourceOS-Linux/agent-machine#T2-1" + ], + "priority": "critical", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" + } +] diff --git a/docs/seam-registry.md b/docs/seam-registry.md new file mode 100644 index 0000000..fab40b2 --- /dev/null +++ b/docs/seam-registry.md @@ -0,0 +1,23 @@ +# Seam Registry (13 seams) + +Machine-readable contract: [`contracts/seam-registry.json`](../contracts/seam-registry.json) — SeamDefinition instances (canonical schema: SourceOS-Linux/sourceos-spec T0-2, vendored here). Validated by `tools/validate_seam_registry.py` in `make validate`. + +A **seam** is an ungated boundary between system layers that represents an attack surface. Each names where trust is not yet enforced, the exploit vector, and the gate that closes it. + +| Seam | Boundary | Attack vector | Gate | Status | Priority | Linked | +|---|---|---|---|---|---|---| +| SEAM-001 | EFI/NVRAM → OS | efi_rootkit.bin; csr-active-config=0x67 (SIP disabled) | boot attestation | open | critical | SourceOS-Linux/agent-machine#T2-3 | +| SEAM-002 | MDM → usernoted | Unauthorized MDM enrollment (IBM MaaS360) | MDM profile audit: flag unrecognized profiles | open | critical | SourceOS-Linux/agent-machine#T2-3 | +| SEAM-003 | SEP → Keybag | SEP non-participation in keybag operations (ANOMALY-007) | SEP participation check | open | critical | SourceOS-Linux/agent-machine#T2-3 | +| SEAM-004 | DNS → Application | Resolution returning 102.165.31.x (adversary IPs) | DNS pinning; DNSSEC | open | critical | SociOS-Linux/source-os#linux/dns-pinning | +| SEAM-005 | TLS → CipherSuite | RC4_128_MD5 cipher downgrade | TLS 1.2 minimum; cipher allowlist | open | critical | SociOS-Linux/source-os#linux/tls-enforcement | +| SEAM-006 | OAuthToken → Device | Token exfiltration via MITM | device-bound tokens | open | high | SocioProphet/mcp-a2a-zero-trust | +| SEAM-007 | Knox/MDM → Android | Knox privilege above Android permissions | Knox audit; SemWifiSwitch check | open | medium | future | +| SEAM-008 | ManagedSpace → SpatialAuthorization | displayUUID instability from firmware manipulation (ANOMALY-008) | displayUUID stability check; attestation timestamp on spatial authorization | open | high | SourceOS-Linux/agent-machine#T2-3 | +| SEAM-009 | Intelligence → ActionAuthorization | Agent self-authorizing actions | dndAllowIntelligentManagement:false enforced; autonomous_action gated | partially_gated | high | SocioProphet/ontogenesis#T1-4, SocioProphet/mcp-a2a-zero-trust#T4-2 | +| SEAM-010 | WorkflowDefinition → Execution | Unsigned workflow injected | workflow signing; state-machine admission gate | designed | high | SociOS-Linux/source-os, SourceOS-Linux/agent-machine | +| SEAM-011 | AgentOutput → Ledger | Local ledger tampered by MDM operator | external append-only ledger; crypto hash chain | designed | critical | SourceOS-Linux/agent-machine#T2-3, SociOS-Linux/source-os#T6-2 | +| SEAM-012 | ThirdParty → Audio/Camera | avfoundation access undeclared | avfoundation access logged; undeclared access = kill switch | open | high | SociOS-Linux/source-os#T6-2 | +| SEAM-013 | ClaudeDesktopTelemetry → PlatformData | sessionSampleRate:100 (100% of sessions); sensitive output can route through a fully-sampled telemetry surface | telemetry boundary check in ActivationDecision (advisory); sensitive output must not route through a 100%-sampled surface | open | critical | SourceOS-Linux/agent-machine#T2-1 | + +> Runtime enforcement (eBPF `agent-class-filter.c` / `kill-switch.c`, `boot-attestation.sh`) lives in `source-os` and is deferred to a Linux kernel environment. This registry is the **contract** those runtimes implement against. diff --git a/schemas/seam-definition.schema.json b/schemas/seam-definition.schema.json new file mode 100644 index 0000000..5ee7159 --- /dev/null +++ b/schemas/seam-definition.schema.json @@ -0,0 +1,101 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/SeamDefinition.json", + "title": "SeamDefinition", + "description": "VENDORED from SourceOS-Linux/sourceos-spec (T0-2, canonical owner). A typed architectural seam: an ungated boundary between two system layers that represents an attack surface. Seams are the estate's threat-model spine \u2014 each names where trust is not yet enforced, the vector that exploits it, and the gate that would close it. Canonical instance URN: urn:srcos:seam-definition:. Schema version 1.0.0.", + "type": "object", + "additionalProperties": false, + "required": [ + "seam_id", + "name", + "boundary_from", + "boundary_to", + "attack_vector", + "gate_requirements", + "implementation_status", + "priority" + ], + "properties": { + "type": { + "const": "SeamDefinition", + "description": "Object discriminator, matching the repo convention (examples are mapped to their schema by this field). Optional." + }, + "seam_id": { + "type": "string", + "minLength": 1, + "pattern": "^SEAM-[0-9]{3}$", + "description": "Stable seam identifier, e.g. SEAM-013. Slugged into the URN urn:srcos:seam-definition:." + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Human-readable seam name." + }, + "boundary_from": { + "type": "string", + "minLength": 1, + "description": "The layer the seam originates at (e.g. MDM)." + }, + "boundary_to": { + "type": "string", + "minLength": 1, + "description": "The layer the seam crosses into (e.g. usernoted)." + }, + "attack_vector": { + "type": "string", + "minLength": 1, + "description": "How the ungated boundary is exploited." + }, + "known_exploits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Concrete observed exploits or indicators for this seam." + }, + "gate_requirements": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "description": "What must be enforced to close the seam. Required and non-empty: a seam with no stated gate is not actionable." + }, + "implementation_status": { + "type": "string", + "enum": [ + "open", + "designed", + "partially_gated", + "implemented" + ], + "description": "Gate maturity for this seam." + }, + "linked_repos": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Repos (and optionally issues) that own the gate work." + }, + "priority": { + "type": "string", + "enum": [ + "critical", + "high", + "medium" + ], + "description": "Remediation priority." + }, + "first_identified": { + "type": "string", + "format": "date", + "description": "Date the seam was first identified." + }, + "last_reviewed": { + "type": "string", + "format": "date", + "description": "Date the seam was last reviewed." + } + } +} diff --git a/tools/validate_seam_registry.py b/tools/validate_seam_registry.py new file mode 100644 index 0000000..d091aad --- /dev/null +++ b/tools/validate_seam_registry.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +"""Validate the seam registry (T6-3) — 13 architectural seams as SeamDefinition +instances, validated against the vendored SeamDefinition schema (canonical owner: +SourceOS-Linux/sourceos-spec, T0-2). + +Asserts: every seam validates; all 13 SEAM-001..013 are present; the SEAM-013 +entry references the Claude Desktop telemetry boundary; every seam declares at +least one gate requirement (a seam with no gate is not actionable). +""" + +from __future__ import annotations + +import json +import sys +from pathlib import Path + +try: + import jsonschema +except ImportError: + print("ERR: jsonschema not installed", file=sys.stderr) + sys.exit(2) + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "seam-definition.schema.json" +REGISTRY = ROOT / "contracts" / "seam-registry.json" +EXPECTED = {f"SEAM-{n:03d}" for n in range(1, 14)} + + +def fail(msg: str) -> None: + print(f"FAIL: {msg}", file=sys.stderr) + sys.exit(1) + + +def main() -> int: + schema = json.loads(SCHEMA.read_text(encoding="utf-8")) + jsonschema.Draft202012Validator.check_schema(schema) + validator = jsonschema.Draft202012Validator(schema) + + seams = json.loads(REGISTRY.read_text(encoding="utf-8")) + if not isinstance(seams, list): + fail("seam-registry.json must be a JSON array of SeamDefinition objects") + + ids = set() + for seam in seams: + errs = sorted(validator.iter_errors(seam), key=lambda e: list(e.path)) + if errs: + fail(f"{seam.get('seam_id', '?')} schema-invalid: {errs[0].message}") + if not seam.get("gate_requirements"): + fail(f"{seam.get('seam_id')} has no gate_requirements (not actionable)") + ids.add(seam["seam_id"]) + + missing = EXPECTED - ids + if missing: + fail(f"registry missing seams: {sorted(missing)}") + + seam013 = next((s for s in seams if s["seam_id"] == "SEAM-013"), None) + if seam013 is None or "telemetry" not in (seam013["attack_vector"] + " " + seam013["name"]).lower(): + fail("SEAM-013 must reference the Claude Desktop telemetry boundary") + + print(f"OK: seam registry — {len(seams)} seams validated (SEAM-001..013 present, SEAM-013 telemetry)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())