{
  "schema_version": 1,
  "id": "guard-memory-writes",
  "track": "coding",
  "name": "Guard Memory Writes",
  "version": "0.0.10",
  "sha256": "c354da6bba22299f860bb2789b8818454f4a95d513912ce4d440253368848e1b",
  "sha256_v1": "fc907094242b958baa454691638cc877da81ccc61202caf387095fd16faa2c89",
  "keyword": "block",
  "word": "blocks",
  "says": "blocks on an agent's file writes and at turn end",
  "description": "Refuses agent-memory writes holding pasted git history, a code block over 20 lines, a duplicate line or a secret. Warns (observe, ASI06) on an added line that tells the agent to run a command or fetch a URL, an encoded blob, and, only where the repo keeps .chock/egress-allowlist.txt, a URL host off it. Judges memory files only (MEMORY.md, CLAUDE.local.md, .claude/memory/**, memory/**/*.md, the agent's own stores) and what a change adds. No waiver. A write after an untrusted fetch is not seen.",
  "misses": null,
  "where": [
    "write",
    "turn-end"
  ],
  "groups": [
    "prompt-injection"
  ],
  "eval_cases": 47,
  "eval_executed": 46,
  "latest": {
    "version": "0.0.10",
    "date": "2026-10-25",
    "change": "Hardening (SR-2d2d; finding F35; eval case tc-047; tests in test_guard_memory_writes_sr2d2.py). The ask-tier instruction and url-host rows take the set of lines a secret already refuses: for a statement with such a line (any physical line of it) the instruction row says the text is withheld and the url-host row names no host, and its key is the statement's digest alone, so the credential never reaches a finding message that the engine logs. A URL whose host cannot be read is shown without its userinfo (everything up to the last `@` is dropped), never as the raw authority. Messages and keys for lines no secret refuses are unchanged. Known limit: the engine still writes finding messages to its log unredacted; that is the framework's to change."
  },
  "agent_labels": {
    "claude-code": {
      "keyword": "block",
      "says": "blocks on an agent's file writes and at turn end"
    },
    "cursor": {
      "keyword": "block",
      "says": "blocks on an agent's file writes and at turn end"
    },
    "codex": {
      "keyword": "block",
      "says": "blocks on an agent's file writes and at turn end. If the hook errors, the action goes through (not witnessed; the vendor's row is only partly live-run)"
    },
    "copilot": {
      "keyword": "block",
      "says": "blocks at turn end only. It does not check a file write when it happens. If the hook errors, the action goes through (not witnessed; the vendor's row is only partly live-run)"
    },
    "devin": {
      "keyword": "block",
      "says": "blocks at turn end only. It does not check a file write when it happens. If the hook errors, the action goes through (vendor docs only, not witnessed)"
    },
    "grok": {
      "keyword": "ungraded",
      "says": "Not graded yet for Grok"
    },
    "goose": {
      "keyword": "ungraded",
      "says": "Not graded yet for goose"
    },
    "antigravity": {
      "keyword": "ungraded",
      "says": "Not graded yet for Antigravity"
    },
    "openhands": {
      "keyword": "ungraded",
      "says": "Not graded yet for OpenHands"
    },
    "kimi-code": {
      "keyword": "ungraded",
      "says": "Not graded yet for Kimi Code"
    },
    "factory-droid": {
      "keyword": "ungraded",
      "says": "Not graded yet for Factory Droid"
    }
  },
  "source_url": "https://github.com/open-coder-ai/chock-catalog/tree/1e60d211c1bb767152c6ab0167932da06ab3a10f/base/guard-memory-writes",
  "enforces": "enforced-at-commit",
  "examples": [
    {
      "word": "Refused",
      "prompt": "A memory file gains a pasted git diff header.",
      "command": null
    },
    {
      "word": "Allowed",
      "prompt": "A memory file holds short non-derivable facts and repeated headings.",
      "command": null
    }
  ]
}
