{
  "schema_version": 1,
  "id": "java-security",
  "track": "coding",
  "name": "Java Security Rules",
  "version": "0.7.0",
  "sha256": "9ef2d2c9c8a10ee629b2ce34d21e17a69b84ecdf07ff11dd475c3f62b99cd60b",
  "sha256_v1": "2b1a85881946e1bb651571832c4bed47f3f22e6255759ed21d3a170dec970058",
  "keyword": "block",
  "word": "blocks",
  "says": "blocks on an agent's file writes and at turn end",
  "description": "trigger: writing Java or Kotlin (Spring, Jakarta EE, Quarkus, Android), SQL/JPA/MyBatis, templates, application.properties/.yml, web.xml, pom.xml, Gradle; \"customize java security\" opens the guided page. avoid: injection, XXE, SSRF, unsafe deserialization, path traversal, weak crypto, trust-all TLS, Spring Security off, exposed secrets, known-exploited deps, SpotBugs/Sonar/PMD/Checkstyle findings. 129 rules, 16 packs, each allow|deny|ask in .chock/security.json; absent = deny (quality: allow).",
  "misses": null,
  "where": [
    "write",
    "turn-end"
  ],
  "groups": [],
  "eval_cases": 177,
  "eval_executed": 167,
  "latest": {
    "version": "0.7.0",
    "date": "2026-10-02",
    "change": "Owner-approved loosening (plan decision D2, roadmap 4.5 #11): a rule no selection speaks for now takes its pack's tier default. The nine security packs (79 rules) still deny; the seven quality packs -- bugs, concurrency, resources, exceptions, performance, style, testing (50 rules) -- now allow, so a legacy file's existing quality findings no longer refuse an edit. A pack kind with no written default, or a pack this build lacks, denies. A verdict a selection file spells keeps its value; only silence changed meaning. A file that spells every rule (what the setup page wrote when nothing was unticked) reads exactly as before. A rule a file leaves unspoken now takes its tier's default: that includes every quality rule in a version-1 file, which predates the quality packs, and any quality row someone unticked on the page (shown then as `unspoken -> deny`). Such a file now allows those quality rules. To keep enforcing a quality pack, spell it: `{\"version\": 2, \"packs\": {\"exceptions\": {\"verdict\": \"deny\"}}}`. The description says `absent = deny (quality: allow)`, its wording shortened to stay within the 500-char budget. The setup page preselects each rule's pack default (from the pack's kind). It marks a row weakened when its verdict (an unticked row: the pack default it falls to) is weaker than the stricter of that default and the repository's current selection, and it leaves a quality rule at allow unspoken unless something stricter stood before. Not yet mirrored by the engine: chock's check-baseline and chock_guidance still read a silent quality rule as deny. Deleting a quality pack's entry from a committed selection is therefore not reported as a loosening, and guidance may name a quality rule that no longer enforces. Security rules are unaffected: silence denies them in both. Known limit: an empty catch around a security check (`checkServerTrusted`, `parseClaimsJws`, `verify`) was refused only by the quality rule exceptions-empty-catch, so with no selection it now passes; spell the exceptions pack as deny to keep that refusal."
  },
  "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/java-security",
  "enforces": "enforced-at-commit",
  "examples": [
    {
      "word": "Refused",
      "prompt": "A MyBatis mapper orders by a column taken from the request, written as ORDER BY ${col}.",
      "command": null
    },
    {
      "word": "Allowed",
      "prompt": "A MyBatis mapper binds a parameter as WHERE id =",
      "command": null
    }
  ]
}
