From 471c270b1f2dac1c749a39b984088f02d07644d8 Mon Sep 17 00:00:00 2001 From: Zack Whitson Date: Fri, 7 Aug 2026 00:16:32 -0500 Subject: [PATCH 1/2] Verify the skill against CLI v0.2.35 and correct the detection boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The skill and READMEs said a local run never performs injection or taint analysis. As of CLI v0.2.35 that is false: the shared SAST engine and its source-to-sink taint tracking run locally over JavaScript, TypeScript and TSX, covering SQL injection, mass assignment, un-awaited database writes, swallowed errors, coercion-prone `==`, and N+1 queries in loops. Leaving the old sentence in place would have the agent tell developers their code was never checked for a class the CLI now checks. What is still hosted is now stated precisely instead of categorically: the rest of the rule pack, every non-JavaScript language, and the symbol graph. The skill directs the agent to read the receipt's own "What did not run" section rather than assert either boundary from memory, since it moves. Also new, and both verified against the 0.2.35 tarball rather than the changelog: - v0.2.32 infers the scope of a turn when no allow policy exists and marks those files `allowed (inferred)`. A clean first run now exits 0 where it used to exit 1, so the skill says to treat an inferred allow as weaker evidence than a declared boundary. - v0.2.34 attaches a Suggested fixes section to some findings. The skill says to present and never auto-apply one, and to keep rotation first for a credential, whose diff is masked and cannot apply cleanly by design. Local security findings are REVIEW_REQUIRED at most and never fail a verdict on their own; the skill now says so, so an agent does not escalate one as blocking. The CLI floor and the "verified against" line move to v0.2.35 across the canonical skill and all three READMEs. Every documented command was rechecked against `--help` from the real 0.2.35 binary and still holds, including `verify-policy trust-key`, which 0.2.35 now lists in its own banner. The README's verbatim receipt excerpt is a real 0.2.35 run reproducing the same scenario, not the 0.2.30 capture edited by hand — same policy digest d13f4367…, new session, new profile `local-registry-v2`. validate.mjs pins the replacement claims so the next version bump cannot quietly restore the old wording: the v0.2.35 floor, `stay hosted-only`, the instruction to read "What did not run", and the REVIEW_REQUIRED ceiling. No version bump and no tag: v0.1.7 is the founder's call. Co-Authored-By: Claude Opus 5 --- README.md | 56 +++++++++++++------ plugins/codetruss-claude/README.md | 6 +- .../skills/codetruss/SKILL.md | 24 +++++++- plugins/codetruss/README.md | 4 +- plugins/codetruss/skills/codetruss/SKILL.md | 24 +++++++- scripts/validate.mjs | 16 +++--- skills/codetruss/SKILL.md | 24 +++++++- 7 files changed, 116 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index b522330..6b087f0 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,10 @@ marketplace. - Git - Node.js 20.9 or newer -- CodeTruss CLI v0.2.30 or newer from +- CodeTruss CLI v0.2.35 or newer from Skill instructions in this repository are verified against the shipped CLI -v0.2.30. The skill can explain the official installer when the CLI is missing, +v0.2.35. The skill can explain the official installer when the CLI is missing, but it must not install software without the developer's confirmation. ## What a receipt looks like @@ -59,9 +59,9 @@ also touched a denied path and committed a live key: ```markdown # CodeTruss receipt — FAILED -- **Session:** `20260807T032401919Z-42bd50` +- **Session:** `20260807T051345990Z-4f2f16` - **Task:** Add a SESSION_TTL constant to src/auth.ts -- **Starting commit:** `decff98665b27d53ec643546829342bbb1b4c878` +- **Starting commit:** `14482ad37ea1f3ea5c9547071b58c3cdffb7c0b0` - **Policy SHA-256:** `d13f4367129bb7683c486d4d4e8e876bc1e9a7f541cd0e539945743b16d95a03` ## Verdict: FAILED @@ -69,14 +69,15 @@ also touched a denied path and committed a live key: - 1 high/critical security or dependency finding(s) affect changed files - 1 file(s) changed in denied paths: infra/deploy.sh - 1 file(s) changed outside approved scope: .codetruss.yml +- sensitive surfaces changed: .codetruss.yml (policy) ## Changed files (3) | Path | Change | Scope | Sensitive | Lines | |---|---|---|---|---:| -| `.codetruss.yml` | added | unexpected | policy | +16/−0 | +| `.codetruss.yml` | added | unexpected | policy | +5/−0 | | `infra/deploy.sh` | added | denied | — | +3/−0 | -| `src/auth.ts` | modified | allowed | — | +2/−0 | +| `src/auth.ts` | modified | allowed | — | +1/−0 | ## Introduced or worsened analyzer findings (1) @@ -86,24 +87,42 @@ also touched a denied path and committed a live key: ## Analysis profile -The 13 deterministic registry analyzers ran locally on this machine. +Profile: `local-registry-v2`. + +The 13 deterministic registry analyzers ran locally on this machine, plus a local +security pass: the shared SAST engine — the same rules and the same +source-to-sink taint tracking as the hosted audit — over the JavaScript, +TypeScript and TSX in this repository. + +### What the local security pass checked + +- **SQL injection (CWE-89).** Untrusted input tracked from request sources + through string building into query execution. +- **Mass assignment (CWE-915).** A raw request body spread into a database + write, and write helpers whose payload type accepts arbitrary keys. ### What did not run -- **Security static analysis (SAST).** No injection or taint analysis was - performed. SQL injection, command injection, code injection, path traversal, - SSRF, open redirect, XSS and insecure deserialization were never checked, so - this receipt says nothing either way about those classes. +- **The rest of the security rule pack.** Command injection, code injection, + path traversal, SSRF, open redirect, XSS and insecure deserialization were + **not** checked here. Those rules run in a hosted scan; absence of a finding + in those classes means they were not analyzed, not that the code is clean. +- **Non-JavaScript languages.** The local pass covers JavaScript, TypeScript and + TSX only. ``` `codetruss verify latest` re-checks the signature over those bytes and prints -`verified 20260807T032401919Z-42bd50 (FAILED)`. +`verified 20260807T051345990Z-4f2f16 (FAILED)`. ## What runs where Local and deterministic, with no account and no network required: - the 13 registry analyzers listed in the receipt's analysis profile; +- since CLI v0.2.35, a security pass running the shared SAST engine and its + source-to-sink taint tracking over the repository's JavaScript, TypeScript and + TSX: SQL injection, mass assignment, un-awaited database writes, swallowed + errors, coercion-prone `==`, and N+1 queries in loops; - scope classification of every changed file against the approved allow/deny boundary, including untracked and sensitive-surface detection; - secret detection on changed files; @@ -113,14 +132,17 @@ Local and deterministic, with no account and no network required: Hosted, and only when the developer explicitly asks for it: -- security static analysis and the cross-file symbol graph, which back the +- the rest of the security rule pack — command injection, code injection, path + traversal, SSRF, open redirect, XSS, insecure deserialization — and every + non-JavaScript language; +- the cross-file symbol graph, which together with the full rule pack backs the full-codebase audit and the Health scores; - receipt `sync` to a CodeTruss account. -A local receipt never contains injection or taint analysis, and it says so in -its own "What did not run" section. Optional provider-backed `--llm` review is -force-disabled under agent hooks, so a hook receipt is always deterministic -evidence only. +A local receipt names its own remaining gaps in its "What did not run" section, +and local security findings are `REVIEW_REQUIRED` at most — they never fail a +verdict on their own. Optional provider-backed `--llm` review is force-disabled +under agent hooks, so a hook receipt is always deterministic evidence only. Measured behaviour on public repositories is published at . CLI downloads, checksums, and the SBOM are at diff --git a/plugins/codetruss-claude/README.md b/plugins/codetruss-claude/README.md index 14d373e..54f01af 100644 --- a/plugins/codetruss-claude/README.md +++ b/plugins/codetruss-claude/README.md @@ -19,9 +19,9 @@ Prerequisites: - Git - Node.js 20.9 or newer -- CodeTruss CLI v0.2.30 or newer from +- CodeTruss CLI v0.2.35 or newer from -Skill instructions are verified against the shipped CLI v0.2.30. +Skill instructions are verified against the shipped CLI v0.2.35. The plugin contains no analyzer, bundled hook, MCP server, background service, or upload path. It delegates hook installation to the tested CLI after developer @@ -36,7 +36,7 @@ receipt sync require separate explicit developer actions. Troubleshooting: - Run `codetruss --version`; install or upgrade from the CLI page when it is - missing or older than v0.2.30. + missing or older than v0.2.35. - Run `codetruss setup` for the guided local policy, verification-fingerprint, and hook flow. Do not replace it with hand-edited setup steps. - Run `codetruss hooks status claude` and `codetruss hooks doctor claude` diff --git a/plugins/codetruss-claude/skills/codetruss/SKILL.md b/plugins/codetruss-claude/skills/codetruss/SKILL.md index af922a0..2130e7d 100644 --- a/plugins/codetruss-claude/skills/codetruss/SKILL.md +++ b/plugins/codetruss-claude/skills/codetruss/SKILL.md @@ -13,7 +13,7 @@ agent. - Work inside the developer's Git repository and inspect existing policy before proposing changes. -- Run `codetruss --version` first. This skill targets v0.2.30 or newer. If the +- Run `codetruss --version` first. This skill targets v0.2.35 or newer. If the CLI is missing or older, explain the prerequisite, then obtain explicit consent before downloading or installing software, including an upgrade. - Offer only the official install paths from `https://codetruss.com/cli`. Let @@ -29,10 +29,19 @@ agent. as `REVIEW_REQUIRED`, exit `2` as `FAILED`, and exit `3` as a usage or environment failure. Exits 1 and 2 still produce receipts; other commands may use nonzero exits differently, so read their output. -- A receipt also names what did not run. SAST and the hosted symbol graph are - hosted-only, so a local run never performs injection or taint analysis. +- A receipt also names what did not run, and that boundary moved in v0.2.35. A + local run now executes the shared SAST engine over the JavaScript, TypeScript + and TSX in the repository, covering SQL injection, mass assignment, + un-awaited database writes, swallowed errors, coercion-prone `==`, and N+1 + queries in loops. The rest of the rule pack (command injection, code + injection, path traversal, SSRF, open redirect, XSS, insecure + deserialization), every non-JavaScript language, and the hosted symbol graph + stay hosted-only. Read the receipt's own "What did not run" section instead + of asserting either way from memory. Report a `PASS` as the deterministic passes finding nothing new, never as evidence that the change is secure. +- Local security findings are `REVIEW_REQUIRED` at most. They never fail a + verdict on their own, so do not report one as a blocking failure. - Describe a valid signature as post-generation integrity evidence. Do not call it trusted execution, proof of authorship, or automatic compliance evidence. @@ -94,6 +103,15 @@ plugin-bundled hook logic. verification results, evidence limitations, and receipt path. Distinguish a policy dispute from a product or shell failure. +Since v0.2.32, a run with no allow policy infers the scope of the turn and marks +those files `allowed (inferred)` on the receipt: treat an inferred allow as +weaker evidence than a declared boundary and still propose a real `.codetruss.yml`. + +Since v0.2.34, a finding may carry a **Suggested fixes** entry with a diff and a +required safety note: present it, never apply it automatically, and keep the +note's rotation-first ordering for a credential, whose diff is deliberately +masked and cannot apply cleanly. + For a wrapped agent run, preserve the exact task and policy: ```bash diff --git a/plugins/codetruss/README.md b/plugins/codetruss/README.md index b56cc30..7f7accf 100644 --- a/plugins/codetruss/README.md +++ b/plugins/codetruss/README.md @@ -7,7 +7,7 @@ Prerequisites: - Git - Node.js 20.9 or newer -- CodeTruss CLI v0.2.30 or newer from +- CodeTruss CLI v0.2.35 or newer from The plugin contains no analyzer, MCP server, background service, or upload path. Deterministic checks stay local. Provider-backed review, authentication, and @@ -16,7 +16,7 @@ receipt sync require separate explicit developer actions. Troubleshooting: - Run `codetruss --version`; install or upgrade from the CLI page when it is - missing or older than v0.2.30. + missing or older than v0.2.35. - Run `codetruss setup` for the guided local policy, verification-fingerprint, and hook flow. Do not replace it with hand-edited setup steps. - Run `codetruss hooks status codex` and `codetruss hooks doctor codex` before diff --git a/plugins/codetruss/skills/codetruss/SKILL.md b/plugins/codetruss/skills/codetruss/SKILL.md index af922a0..2130e7d 100644 --- a/plugins/codetruss/skills/codetruss/SKILL.md +++ b/plugins/codetruss/skills/codetruss/SKILL.md @@ -13,7 +13,7 @@ agent. - Work inside the developer's Git repository and inspect existing policy before proposing changes. -- Run `codetruss --version` first. This skill targets v0.2.30 or newer. If the +- Run `codetruss --version` first. This skill targets v0.2.35 or newer. If the CLI is missing or older, explain the prerequisite, then obtain explicit consent before downloading or installing software, including an upgrade. - Offer only the official install paths from `https://codetruss.com/cli`. Let @@ -29,10 +29,19 @@ agent. as `REVIEW_REQUIRED`, exit `2` as `FAILED`, and exit `3` as a usage or environment failure. Exits 1 and 2 still produce receipts; other commands may use nonzero exits differently, so read their output. -- A receipt also names what did not run. SAST and the hosted symbol graph are - hosted-only, so a local run never performs injection or taint analysis. +- A receipt also names what did not run, and that boundary moved in v0.2.35. A + local run now executes the shared SAST engine over the JavaScript, TypeScript + and TSX in the repository, covering SQL injection, mass assignment, + un-awaited database writes, swallowed errors, coercion-prone `==`, and N+1 + queries in loops. The rest of the rule pack (command injection, code + injection, path traversal, SSRF, open redirect, XSS, insecure + deserialization), every non-JavaScript language, and the hosted symbol graph + stay hosted-only. Read the receipt's own "What did not run" section instead + of asserting either way from memory. Report a `PASS` as the deterministic passes finding nothing new, never as evidence that the change is secure. +- Local security findings are `REVIEW_REQUIRED` at most. They never fail a + verdict on their own, so do not report one as a blocking failure. - Describe a valid signature as post-generation integrity evidence. Do not call it trusted execution, proof of authorship, or automatic compliance evidence. @@ -94,6 +103,15 @@ plugin-bundled hook logic. verification results, evidence limitations, and receipt path. Distinguish a policy dispute from a product or shell failure. +Since v0.2.32, a run with no allow policy infers the scope of the turn and marks +those files `allowed (inferred)` on the receipt: treat an inferred allow as +weaker evidence than a declared boundary and still propose a real `.codetruss.yml`. + +Since v0.2.34, a finding may carry a **Suggested fixes** entry with a diff and a +required safety note: present it, never apply it automatically, and keep the +note's rotation-first ordering for a credential, whose diff is deliberately +masked and cannot apply cleanly. + For a wrapped agent run, preserve the exact task and policy: ```bash diff --git a/scripts/validate.mjs b/scripts/validate.mjs index a1c15d0..5843282 100644 --- a/scripts/validate.mjs +++ b/scripts/validate.mjs @@ -19,7 +19,7 @@ assert.match(canonicalSkill, /^---\nname: codetruss\ndescription: .{80,1024}\n-- for (const required of [ 'obtain explicit consent before downloading or installing software', - 'This skill targets v0.2.30 or newer.', + 'This skill targets v0.2.35 or newer.', 'use `codetruss setup` as the single guided setup path', '`codetruss verify-policy status` and require exit 0 with the same fingerprint', 'An existing `.codetruss.yml` remains authoritative', @@ -27,7 +27,9 @@ for (const required of [ 'Do not broaden `allow`, remove `deny`, add `--no-verify`', 'For `codetruss run` and `codetruss review`, treat exit `0` as `PASS`', 'post-generation integrity evidence', - 'a local run never performs injection or taint analysis', + 'stay hosted-only', + 'Read the receipt\'s own "What did not run" section instead', + 'Local security findings are `REVIEW_REQUIRED` at most.', 'never as\n evidence that the change is secure', ]) { assert.ok(canonicalSkill.includes(required), `missing trust-boundary rule: ${required}`) @@ -171,7 +173,7 @@ assert.deepEqual(codexMarketplace.plugins[0].policy, { }) const readme = await read('README.md') -assert.match(readme, /CodeTruss CLI v0\.2\.30 or newer/) +assert.match(readme, /CodeTruss CLI v0\.2\.35 or newer/) assert.match(readme, /--skill codetruss --agent claude-code codex -y/) assert.match(readme, /codetruss-plugins\/tree\/v0\.1\.5/) assert.doesNotMatch(readme, /official listing remains pending review/) @@ -183,8 +185,8 @@ assert.match( ) assert.match(readme, /\/plugin marketplace add DeliriumPulse\/codetruss-plugins/) assert.match(readme, /\/plugin install codetruss@codetruss/) -assert.match(readme, /verified against the shipped CLI\s+v0\.2\.30/) -assert.match(readme, /The 13 deterministic registry analyzers ran locally on this machine\./) +assert.match(readme, /verified against the shipped CLI\s+v0\.2\.35/) +assert.match(readme, /The 13 deterministic registry analyzers ran locally on this machine, plus a local\s+security pass/) assert.match(readme, /https:\/\/codetruss\.com\/benchmark/) assert.match(readme, /https:\/\/codetruss\.com\/cli/) @@ -193,13 +195,13 @@ for (const path of [ 'plugins/codetruss-claude/README.md', ]) { const pluginReadme = await read(path) - assert.match(pluginReadme, /CodeTruss CLI v0\.2\.30 or newer/) + assert.match(pluginReadme, /CodeTruss CLI v0\.2\.35 or newer/) assert.match(pluginReadme, /Run `codetruss setup` for the guided local policy/) } const claudePluginReadme = await read('plugins/codetruss-claude/README.md') assert.match(claudePluginReadme, /\/plugin install codetruss@codetruss/) -assert.match(claudePluginReadme, /verified against the shipped CLI v0\.2\.30/) +assert.match(claudePluginReadme, /verified against the shipped CLI v0\.2\.35/) const submission = await read('PLUGIN-SUBMISSION.md') assert.match(submission, /platform\.claude\.com\/plugins\/submit/) diff --git a/skills/codetruss/SKILL.md b/skills/codetruss/SKILL.md index af922a0..2130e7d 100644 --- a/skills/codetruss/SKILL.md +++ b/skills/codetruss/SKILL.md @@ -13,7 +13,7 @@ agent. - Work inside the developer's Git repository and inspect existing policy before proposing changes. -- Run `codetruss --version` first. This skill targets v0.2.30 or newer. If the +- Run `codetruss --version` first. This skill targets v0.2.35 or newer. If the CLI is missing or older, explain the prerequisite, then obtain explicit consent before downloading or installing software, including an upgrade. - Offer only the official install paths from `https://codetruss.com/cli`. Let @@ -29,10 +29,19 @@ agent. as `REVIEW_REQUIRED`, exit `2` as `FAILED`, and exit `3` as a usage or environment failure. Exits 1 and 2 still produce receipts; other commands may use nonzero exits differently, so read their output. -- A receipt also names what did not run. SAST and the hosted symbol graph are - hosted-only, so a local run never performs injection or taint analysis. +- A receipt also names what did not run, and that boundary moved in v0.2.35. A + local run now executes the shared SAST engine over the JavaScript, TypeScript + and TSX in the repository, covering SQL injection, mass assignment, + un-awaited database writes, swallowed errors, coercion-prone `==`, and N+1 + queries in loops. The rest of the rule pack (command injection, code + injection, path traversal, SSRF, open redirect, XSS, insecure + deserialization), every non-JavaScript language, and the hosted symbol graph + stay hosted-only. Read the receipt's own "What did not run" section instead + of asserting either way from memory. Report a `PASS` as the deterministic passes finding nothing new, never as evidence that the change is secure. +- Local security findings are `REVIEW_REQUIRED` at most. They never fail a + verdict on their own, so do not report one as a blocking failure. - Describe a valid signature as post-generation integrity evidence. Do not call it trusted execution, proof of authorship, or automatic compliance evidence. @@ -94,6 +103,15 @@ plugin-bundled hook logic. verification results, evidence limitations, and receipt path. Distinguish a policy dispute from a product or shell failure. +Since v0.2.32, a run with no allow policy infers the scope of the turn and marks +those files `allowed (inferred)` on the receipt: treat an inferred allow as +weaker evidence than a declared boundary and still propose a real `.codetruss.yml`. + +Since v0.2.34, a finding may carry a **Suggested fixes** entry with a diff and a +required safety note: present it, never apply it automatically, and keep the +note's rotation-first ordering for a credential, whose diff is deliberately +masked and cannot apply cleanly. + For a wrapped agent run, preserve the exact task and policy: ```bash From 1f5d81000b91280cabba367c5094c4329b6b8a88 Mon Sep 17 00:00:00 2001 From: Zack Whitson Date: Fri, 7 Aug 2026 00:33:15 -0500 Subject: [PATCH 2/2] Quote the whole receipt section, not the half that flatters the local pass The README calls this block a verbatim excerpt, and the two security sections were trimmed. That trim cut in the wrong direction twice: the local pass looked like it checks two rule classes when it checks six, and the gap list looked like two items when it is five. Understating what runs is the same category of error as overstating it, and this repository exists to keep the skill from doing either. Both sections are now quoted whole, and verified equal to the real 0.2.35 receipt after normalizing line wrapping rather than by eye. Co-Authored-By: Claude Opus 5 --- README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b087f0..61a00a6 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,9 @@ TypeScript and TSX in this repository. through string building into query execution. - **Mass assignment (CWE-915).** A raw request body spread into a database write, and write helpers whose payload type accepts arbitrary keys. +- **Un-awaited database writes, swallowed errors, coercion-prone `==` + comparisons, and N+1 queries in loops** — the defect classes coding agents + most often introduce. ### What did not run @@ -108,7 +111,21 @@ TypeScript and TSX in this repository. **not** checked here. Those rules run in a hosted scan; absence of a finding in those classes means they were not analyzed, not that the code is clean. - **Non-JavaScript languages.** The local pass covers JavaScript, TypeScript and - TSX only. + TSX only. Python, Go, Java, C#, PHP, Ruby and Rust in this repository received + secret scanning and the other registry passes, but no security rule or taint + analysis. +- **Hosted symbol graph.** No cross-file call or data-flow graph was built, so + architecture and dead-code conclusions cover only what the local passes can + see in isolation. +- **Optional LLM review.** No model read this diff. It is opt-in via `--llm` and + is force-disabled under agent hooks, so a hook receipt is always deterministic + evidence only. +- **Hosted Health scores.** Not calculated, reported as **N/A**. The scores are + defined over the graph and the complete SAST pass; a number derived from this + pass set would overstate what ran. + +Local security findings are reported for review and do not fail the verdict on +their own. ``` `codetruss verify latest` re-checks the signature over those bytes and prints