{"id":51857351,"url":"https://github.com/airblackbox/tombstone","last_synced_at":"2026-07-24T02:01:31.309Z","repository":{"id":362971318,"uuid":"1261470591","full_name":"airblackbox/tombstone","owner":"airblackbox","description":"Provable, crypto-shredded erasure on a tamper-evident ledger. Prove a person is deleted everywhere, while the audit trail stays intact.","archived":false,"fork":false,"pushed_at":"2026-07-12T21:20:27.000Z","size":2658,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-12T22:09:32.058Z","etag":null,"topics":["audit-log","crypto-shredding","data-lineage","gdpr","privacy","right-to-be-forgotten"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/airblackbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-06T18:20:57.000Z","updated_at":"2026-07-12T21:20:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/airblackbox/tombstone","commit_stats":null,"previous_names":["shotwellj/tombstone","airblackbox/tombstone"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/airblackbox/tombstone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airblackbox%2Ftombstone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airblackbox%2Ftombstone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airblackbox%2Ftombstone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airblackbox%2Ftombstone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/airblackbox","download_url":"https://codeload.github.com/airblackbox/tombstone/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airblackbox%2Ftombstone/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35823269,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-24T02:00:07.870Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audit-log","crypto-shredding","data-lineage","gdpr","privacy","right-to-be-forgotten"],"created_at":"2026-07-24T02:01:30.296Z","updated_at":"2026-07-24T02:01:31.291Z","avatar_url":"https://github.com/airblackbox.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tombstone\n\n**Stop your AI agents from looping, running away, or wiping your data. In two lines. With a receipt.**\n\n![Tombstone blocks an agent from deleting real files, then proves it](demo.gif)\n\nTombstone is an open-source control plane for AI agents. It wraps the tools you\nhand an agent and intercepts the dangerous calls before they run: a runaway loop\nthat burns your token budget, the same call repeated forever, a delete or drop or\noverwrite on data you marked protected. Every decision, allowed or blocked, is\nsealed into a tamper-evident ledger, so you always have proof of exactly what\nyour agent tried to do.\n\nObservability tools chart the disaster in a dashboard after it happens.\nTombstone stops it first, then proves it.\n\nRuns locally. Framework-agnostic. Your data and your agents never leave your\nenvironment.\n\n## Guard any agent in two lines\n\n```python\nfrom tombstone.easy import Tombstone\n\ntb = Tombstone(protect=[\"./data\"], budget=50)   # a ledger + guard, ready\ntools = tb.guard_all(tools)                       # wrap your tools\n```\n\nHand `tools` to your agent the way you already do. That is the whole\nintegration. It works with plain Python tool functions (CrewAI, AutoGen, a raw\nOpenAI or Anthropic tool loop) and with LangChain tools.\n\nThree independent stops from one wrapper:\n\n- **Runaway budget.** After `budget` tool calls, the next one is blocked. A cost\n  ceiling for an agent that keeps going forever.\n- **Loop detector.** The same call repeated in a row is blocked. Catches an agent\n  stuck repeating itself.\n- **Protected paths.** A delete, drop, or overwrite on anything under a protected\n  path is blocked before it runs.\n\nCheck the ledger any time:\n\n```python\nok, msg = tb.verify()   # (True, 'chain intact (N entries verified)')\n```\n\n## Proof: two runaways, one wrapper\n\nThe loop detector catches an agent repeating itself:\nround 1: calling the tool\nround 2: calling the tool\nround 3: calling the tool\nround 4: calling the tool\nround 5: calling the tool\nSTOPPED at round 5: loop detected: 'call:keep going' repeated 5x in a row\nverify: (True, 'chain intact (5 entries verified)')\n\nThe budget catches an agent that keeps doing new things forever:\nround 1: calling the tool\nround 2: calling the tool\nround 3: calling the tool\nround 4: calling the tool\nround 5: calling the tool\nround 6: calling the tool\nSTOPPED at round 6: step budget exceeded (6 \u003e 5): possible runaway\nverify: (True, 'chain intact (6 entries verified)')\n\nSame two lines of setup. One catches repetition, the other catches endless\nnovelty. Most agent guardrail tools give you one, not both.\n\n## Try it in 30 seconds\ngit clone https://github.com/airblackbox/tombstone\ncd tombstone\npip install cryptography\nPYTHONPATH=. python3 demo/demo_agent_guardrail.py\n\nYou will watch an agent get blocked from deleting real files, a runaway loop get\nkilled at step 5, and the signed receipt on a ledger that verifies.\n\nWatch two real agents spiral until the run is killed:\nPYTHONPATH=. python3 demo/runaway_agents.py\n\nOr watch the whole thing in the browser, a destructive block plus a runaway plus\na live tamper test:\npip install flask\npython3 cockpit.py     # then open http://127.0.0.1:5001\n\n## How the proof works\n\nEvery decision is one entry in an append-only, hash-chained ledger. Each entry\ncommits to the previous one, so altering any past entry breaks verification, and\nan HMAC-authenticated head makes truncation detectable too. You do not have to\ntrust Tombstone: run `ledger.verify()` yourself, or re-run any demo and check the\nledger it wrote.\n\n## Honest scope\n\nEnforcement covers actions taken through guarded tools. If you also hand the\nagent a raw, unguarded capability (a bare `os.remove`), it can bypass the guard.\nThe rule is simple: give agents only guarded tools for anything risky. Tombstone\nis the wrapper you put around every dangerous tool, not a kernel hook.\n\n## Install\npip install cryptography      # core\npip install flask             # optional, for the browser cockpit\n\nApache 2.0. 13 security tests pass (`pytest tests/`).\n\n---\n\n## Beyond the agent guard: provable data erasure\n\nThe same tamper-evident spine powers Tombstone's second capability: erasing a\nperson's data so it is unrecoverable everywhere, even in copies, while the audit\nlog proving it existed and was deleted stays intact. That is what a tombstone is.\n\n### How it works\n\n- Personal data is encrypted with a per-subject key (AES-256-GCM) before it\n  touches disk.\n- The ledger stores only a SHA-256 commitment to the ciphertext, never the data.\n  Each entry is hash-chained to the previous one, so altering any past entry\n  breaks verification.\n- Erasure = destroying the subject's key (crypto-shredding). The ciphertext\n  becomes permanent noise. The ledger stays intact.\n\n### The five-step proof\npython demo/demo.py\n\n1. Store a subject's data (encrypted; ledger holds only a hash).\n2. Verify the ledger is tamper-evident.\n3. Read the data back (proves it was really stored).\n4. Erase the subject (destroy the key).\n5. Prove erasure: data is unrecoverable AND the ledger still verifies.\n\n### Lineage and containment (v0.2)\n\nErasing data in one place is the easy case. The real problem is that data gets\ncopied and derived across systems, and you have to cover all of it.\n\n- Lineage: every copy or derivation is recorded as a flow on the ledger.\n  `vault.lineage.graph(subject)` shows where data went; `locations(subject)`\n  lists the full footprint; `trace(subject, start)` follows it downstream.\n- Containment: copies stored via `vault.store_at(...)` inherit the subject's one\n  key, so destroying that key crypto-shreds every copy at once.\n  `vault.verify_erasure_coverage(subject)` walks every location and proves each\n  copy is unreadable after erasure.\npython demo/demo_lineage.py      # trace the sprawl, erase across all of it\npython demo/demo_containment.py  # one key-shred kills every real copy\n\nHonest scope: containment is guaranteed for data that went through Tombstone (it\ninherits the key). A plaintext copy made by bypassing Tombstone entirely cannot\nbe crypto-shredded by anyone; lineage tracking is how you catch those flows and\nroute them through the system in the first place.\n\n### Flow-control proxy (v0.3)\n\nA real HTTP forward proxy that inspects request bodies and blocks personal-data\nleaks before they leave, recording every decision on the tamper-evident ledger.\npython demo/demo_proxy.py\n\nThe demo starts a real destination server and a real proxy, then sends two live\nHTTP requests: a clean one (forwarded) and one carrying a subject's email\n(blocked with HTTP 451, never reaches the destination). The ledger records both\ndecisions, with personal data masked so the audit log itself never leaks.\n\nHonest scope: this is a laptop-scale reference implementation of the\negress-control pattern. It inspects plain HTTP bodies. It does NOT do TLS\ninterception or production-grade throughput. The value is the working pattern:\nreal payload inspection plus policy plus a tamper-evident decision log.\n\n### Hardening: attack yourself (v0.4)\n\nA security tool is only as good as the attacks it survives. Tombstone ships an\nadversarial test suite that tries to defeat its own guarantees:\npython attack.py          # readable attack report\npytest tests/             # the same attacks as assertions\n\nAttacks and current status:\n\n- Forge a past entry (alter contents, keep hash): DEFENDED (hash mismatch).\n- Reorder entries: DEFENDED (broken prev_hash link).\n- Truncate the log (delete recent entries to hide them): DEFENDED. The ledger\n  keeps an HMAC-authenticated head recording chain length and tip; truncation\n  makes the log disagree with the head, and the head cannot be forged without\n  the secret key.\n- Recover data after crypto-shred: DEFENDED (vault read fails; no plaintext on\n  disk, only ciphertext for a destroyed key).\n- Sneak obfuscated PII past the proxy (spacing, [at]/[dot] tricks): DEFENDED via\n  payload normalization.\n\nHonest limits (the next hardening targets, not yet done):\n- The head-signing secret currently lives next to the ledger. Truly hardened, it\n  belongs in a separate KMS/HSM so an attacker with full disk access still\n  cannot forge the head.\n- Secure key deletion on SSDs is hard (wear-leveling). The robust answer is\n  envelope encryption: wrap subject keys under a KMS master key whose\n  destruction is attestable, so erasure never depends on physically scrubbing\n  bytes.\n- Content inspection is an arms race. Normalization defeats trivial evasion;\n  encoding, encryption, or splitting across requests still requires deeper\n  inspection.\n\n### Envelope encryption (v0.5)\n\nErasure no longer trusts the disk. Every subject key is wrapped (encrypted) under\na master key; only the wrapped form is ever written. Two erasure paths, neither\ndepending on physically scrubbing bytes:\n\n- Erase one subject: destroy their wrapped key.\n- Crypto-erase everyone at once: destroy the master key. Every wrapped subject\n  key becomes permanently un-unwrappable, even copies an attacker hoarded.\npython demo/demo_envelope.py   # destroy the master, watch everyone die at once\n\nHonest limit: the master key still lives in a local file. Truly hardened, it\nbelongs in a KMS/HSM that performs and attests its own destruction. The\nwrap/unwrap interface is exactly what a KMS slots into; that integration is the\nnext deployment-hardening step.\n\n### Merkle-tree proofs (v0.6)\n\nThe hash chain proves the whole log is intact; a Merkle tree (RFC 6962 hashing,\nthe Certificate Transparency scheme) adds efficient single-entry proofs:\n\n- Inclusion proof: prove \"entry X is in the log\" with about log2(n) hashes,\n  without revealing other entries. Prove an erasure is recorded without dumping\n  everyone else's events.\n- Consistency proof: prove the log only ever grew, never rewrote history.\npython demo/demo_merkle.py   # prove one erasure privately; reject a forgery\n\nLayered integrity: the hash chain catches content tampering, the authenticated\nhead catches truncation, and the Merkle tree gives efficient inclusion and\nconsistency proofs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fairblackbox%2Ftombstone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fairblackbox%2Ftombstone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fairblackbox%2Ftombstone/lists"}