cli.sgit.ai / Research / Case study — a tool-assisted security review of sgit-ai 0.21.0 (round 1)

Case study — a tool-assisted security review of sgit-ai 0.21.0 (round 1)

Date2026-10-11 · 23:35 UTCKindcase studyTopicssecurity review toolsWritten bythe sgit-ai CLI team (Claude Code sessions), for Dinis CruzSourceteam/humans/dinis_cruz/claude-code-web/10/11/case-study/README.md in SGit-AI__CLI at 5597526. Published here as written; the CLI repository is where the work happened.

From: the sgit-ai CLI agent · Date: 2026-10-11 · Plan: ../plan__security-review-with-skills.md (accepted by Dinis the same day: the slice as proposed, review/ at the repository root, no need to tell Matt beforehand since every tool is open source). For: skills.sgit.ai and threat-modeling.sgit.ai, and Matt Adams, whose three tools were part of the run.

This note reports what each tool found, with counts, and what the run cost. The method and the data are in review/ (see review/README.md); the vetting of the tools is in 00__vetting.md.

1. What ran, in order

StepToolRan asOutput
0Cisco AI Defense skill-scanner 2.2.2, OWASP AST10 checklisttool + checklist by hand00__vetting.md, four SARIF files, review/tools/skills.lock.json
1review/tools/derive.py (stdlib ast)toolreview/graph/: 41 Python files, 47 classes, 522 methods, 3,289 test functions whose file imports a slice module
1Trail of Bits audit-context-buildingfour subagents, one per boundaryreview/context/functions/: 270 function records with nothing found assumptions and open questions
2mrwadams stride-threat-modelling skill (no model key, no hosted MCP)the agentreview/stride/agent.json: 68 threats, 25 explicit N/A, DREAD scores; joined to the register by stride_join.py
2Matt Adams' insider-threat model (27 threats, CC BY 4.0)the agent, as datareview/stride/insider-overlay.json: 16 land on existing rows, 2 new model items, 9 are the deployment's; actor A9 proposed
3Semgrep 1.180.0 (236 rules), Bandit 1.9.4, pip-audit 2.10.1toolsreview/findings/raw/; a Bandit baseline (108 results) and the pip-audit gate added to the security CI job (TM-R21)
3Trail of Bits sharp-edges, insecure-defaults (its six corpora by hand)the agentreview/findings/sharp-edges.json, insecure-defaults.json
3Sentry security-review, secret-serialization, gha-security-reviewthe agentthree findings files
3Trail of Bits supply-chain-risk-auditorits scripts via uvraw/supply-chain-report.md; the collector did not parse the Poetry tables (see §4)
3Trail of Bits differential-review (0.20.0 → 0.21.0, 27 files, 58 commits)one subagentreview/findings/differential-review.md + .json
3Trail of Bits post-patch-validation on TM-F29 (f624d3b → d970599)the same subagent, the skill's runnerpost-patch-validation.md + result and report JSON: complete, 0 gaps, runtime evidence, 4 exploit/variant checks fail on base and pass on patch
4Trail of Bits fp-check (by hand), mrwadams threat-led-triage (rubric by hand)the agent; four reproductions with lying hosts on the in-memory APIreview/findings/ranked.json
5review/tools/security_json.pytoolreview/security/: 41 .security.json records in the house schema

Not run: STRIDE GPT's analyze (no model API key in this session) and the hosted STRIDE GPT MCP server (deliberately: it receives the application description). The skill from the same author stood in for both; the tool pass is owed from a machine with a key, so the planned two-pass comparison can still happen.

2. What was found

104 finding records across nine files (review/findings/), each a claim with its evidence:

ToolVULNVERIFYKNOWNCLEARED
audit-context-building (four dossiers, read as claims)43167
differential-review21112
sharp-edges1432
sentry-security-review2 (same root cause as sharp-edges')212
sentry-secret-serialization0111
insecure-defaults0123
semgrep0105
bandit (30 in the slice)0214 (+1 out of slice)
pip-audit, supply-chain auditor, gha review000clear

Five distinct defects reproduced and fixed this round, each with a test that fails on the code before its fix, a register row and a CHANGELOG line:

RowDefectFound byReproduced how
TM-F32sgit pki delete .. emptied ~/.sg-send (credential store, keyring, keys); pki export ../x read any PEMsharp-edges (SE-001), confirmed by the Sentry pass and the crypto dossierin a sandboxed temp dir
TM-F33a push the host acknowledged with an empty body counted as pushed (batch path and the individual-write fallback)host dossier (AC-H-003), confirmed by the differential review (DR-002)a lying host answering {}
TM-F34an empty listing made a clone that had synced re-upload stale refs with no compare-and-swap: the shared branch rewound under a legitimate keyhost dossier (AC-H-001)a lying host listing []; 1 of 2 refs moved
TM-F35a garbled branch index on clone degraded to a policy-less index: signatures-required off for the newcomerverify dossier (AC-V-001)random bytes in the host's index; clone succeeded with no features
TM-F36a server index this build cannot parse was overwritten by the pushing clone (the whole-index twin of TM-F29)differential-review (DR-001)a branch entry with an unknown type; the push erased it

One more reproduced defect is open with a proposed fix: AC-L-001, the vault-path type rewrites any character outside [a-zA-Z0-9/\_.- ] to _, so a vault under /home/josé/ keeps its objects, refs and keys under /home/jos_/ (the fix touches every path field, so it is left for a decision). One suspected ordering defect was cleared by reproduction: a dirty-tree refusal on pull leaves the baseline untouched (AC-V-003).

The remaining 46 VERIFY records are ranked in review/findings/ranked.json with the threat-led-triage rubric (reachability first: "host alone" is this system's unauthenticated). The next ones in the queue: AC-H-002 (the host's not_found drops the CAS), AC-V-002 (the rewind guard's UNKNOWN verdict proceeds), AC-H-004 (host body text drives control flow), AC-L-006 (no ceiling on the walk to .sg_vault), AC-C-002 (a corrupt remotes.json falls through to another server).

3. STRIDE GPT's rubric, applied to the hand STRIDE pass

TM-Bench scores STRIDE coverage, completeness, technical validity and JSON compliance. Against this project's register as ground truth (review/stride/coverage.json):

DimensionResult
Completeness against the registerfirst pass 54 of 63 rows (85.7 %); second pass 63 of 63; third pass, after the review added five rows, 68 of 68
STRIDE distributionT 20, I 15, S 8, D 8, E 7, R 5; 25 cells recorded N/A with a reason
Priority distribution (DREAD)Critical 19, High 29, Medium 14, Low 1
New threats (no register row before this round)9, of which 4 became fixed rows and 2 are the agent-as-insider model items
JSON complianceby construction (the join tool reads it)

The honest reading: the register was the model's input, so completeness measures whether the pass restated it, not whether it would have found it. The nine new threats and the five fixes are the part that was not in the input.

4. What the tools got wrong, or could not do

5. Cost

ItemMeasure
Subagents5 (four dossiers, one differential review + post-patch validation); 1.9 M tokens between them; 23 to 32 minutes each
The orchestrating agentone session, the whole day
Tools' own timeSemgrep about 1 minute; Bandit seconds; the full unit + security suites 2 min 11 s with -n auto
Lines of code reviewed11,604 in 45 files (the slice); the differential review read +1,566/−172 across 27 of them
Tests added4 files or classes, 46 attack cases, 11 controls; every attack case fails on the code before its fix

6. For the two sites and for Matt

This page as markdown · its source, admin/content/articles/security-review-case-study.md