From 2df92648993565cb14e94383c5704393aa3566b1 Mon Sep 17 00:00:00 2001 From: Animesh Srivastava Date: Thu, 12 Mar 2026 15:00:20 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20correct=20/gal=20reference=20syntax=20to?= =?UTF-8?q?=20match=20parser,=20add=20/unannotated=20to=20/help=20?= =?UTF-8?q?=E2=80=94=20v1.4.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix /gal (TUI + CLI): description format ': text' → '-- "quoted text"' - Fix /gal: severity format 'severity:high' → '[high]' / '[P0]' - Fix /gal: @flows connector 'to' → '->' arrow syntax - Fix /gal: @validates preposition 'on' → 'for' - Fix /gal: @owns add missing 'for' preposition - Fix /gal: @mitigates document 'using' as primary keyword - Add /gal: external refs section (cwe:, owasp:, capec:, attack:) - Add /gal: @boundary alternate syntaxes and (#id) support - Add /gal: standalone @shield single-line marker - Fix /help: add missing /unannotated command - Fix CLI: guardlink --version was stuck at 1.1.0 - Bump version to 1.4.1 - Annotation edits: @audit on launcher timeout, suggest module - Sync agent instruction files with current model --- .clinerules | 36 +- .cursor/rules/guardlink.mdc | 32 +- .gemini/GEMINI.md | 36 +- .github/copilot-instructions.md | 36 +- .gitignore | 12 +- .guardlink/definitions.ts | 2 + .../2026-03-12T19-14-22-stride.md | 301 + .windsurfrules | 36 +- AGENTS.md | 36 +- CHANGELOG.md | 18 + CLAUDE.md | 36 +- package.json | 2 +- src/agents/launcher.ts | 2 +- src/cli/index.ts | 97 +- src/mcp/suggest.ts | 1 + src/tui/commands.ts | 96 +- threat-dashboard.html | 6986 +++++++++++++++++ 17 files changed, 7564 insertions(+), 201 deletions(-) create mode 100644 .guardlink/threat-reports/2026-03-12T19-14-22-stride.md create mode 100644 threat-dashboard.html diff --git a/.clinerules b/.clinerules index dd2786e..8d40c54 100644 --- a/.clinerules +++ b/.clinerules @@ -39,16 +39,16 @@ Every time you write or modify code that touches security-relevant behavior, you **Assets:** #parser (GuardLink,Parser), #cli (GuardLink,CLI), #tui (GuardLink,TUI), #mcp (GuardLink,MCP), #llm-client (GuardLink,LLM_Client), #dashboard (GuardLink,Dashboard), #init (GuardLink,Init), #agent-launcher (GuardLink,Agent_Launcher), #diff (GuardLink,Diff), #report (GuardLink,Report), #sarif (GuardLink,SARIF), #suggest (GuardLink,Suggest), #workspace-link (Workspace,Link), #merge-engine (Workspace,Merge), #report-metadata (Workspace,Metadata), #workspace-config (Workspace,Config) **Threats:** #path-traversal (Path_Traversal) [high], #cmd-injection (Command_Injection) [critical], #xss (Cross_Site_Scripting) [high], #api-key-exposure (API_Key_Exposure) [high], #ssrf (Server_Side_Request_Forgery) [medium], #redos (ReDoS) [medium], #arbitrary-write (Arbitrary_File_Write) [high], #prompt-injection (Prompt_Injection) [medium], #dos (Denial_of_Service) [medium], #data-exposure (Sensitive_Data_Exposure) [medium], #insecure-deser (Insecure_Deserialization) [medium], #child-proc-injection (Child_Process_Injection) [high], #info-disclosure (Information_Disclosure) [low], #tag-collision (Tag_Collision) [medium], #config-tamper (Config_Tampering) [medium] -**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring) +**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring), #prefix-ownership (Prefix_Ownership), #yaml-validation (YAML_Validation) ### Open Exposures (need @mitigates or @audit) -- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) -- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) -- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) - #agent-launcher exposed to #prompt-injection [medium] (src/agents/launcher.ts:13) - #agent-launcher exposed to #dos [low] (src/agents/launcher.ts:15) - #agent-launcher exposed to #prompt-injection [high] (src/agents/prompts.ts:6) +- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) +- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) +- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) - #cli exposed to #cmd-injection [critical] (src/cli/index.ts:31) - #init exposed to #data-exposure [low] (src/init/index.ts:12) - #mcp exposed to #cmd-injection [high] (src/mcp/index.ts:4) @@ -61,17 +61,6 @@ Every time you write or modify code that touches security-relevant behavior, you ### Existing Data Flows (extend, don't duplicate) -- ThreatModel -> #sarif via generateSarif -- #sarif -> SarifLog via return -- ThreatModel -> #llm-client via serializeModel -- ProjectFiles -> #llm-client via readFileSync -- #llm-client -> ReportFile via writeFileSync -- LLMConfig -> #llm-client via chatCompletion -- #llm-client -> LLMProvider via fetch -- LLMProvider -> #llm-client via response -- LLMToolCall -> #llm-client via createToolExecutor -- #llm-client -> NVD via fetch -- ProjectFiles -> #llm-client via readFileSync - EnvVars -> #agent-launcher via process.env - ConfigFile -> #agent-launcher via readFileSync - #agent-launcher -> ConfigFile via writeFileSync @@ -81,11 +70,22 @@ Every time you write or modify code that touches security-relevant behavior, you - UserPrompt -> #agent-launcher via buildAnnotatePrompt - ThreatModel -> #agent-launcher via model - #agent-launcher -> AgentPrompt via return +- ThreatModel -> #llm-client via serializeModel +- ProjectFiles -> #llm-client via readFileSync +- #llm-client -> ReportFile via writeFileSync +- LLMConfig -> #llm-client via chatCompletion +- #llm-client -> LLMProvider via fetch +- LLMProvider -> #llm-client via response +- LLMToolCall -> #llm-client via createToolExecutor +- #llm-client -> NVD via fetch +- ProjectFiles -> #llm-client via readFileSync +- ThreatModel -> #sarif via generateSarif +- #sarif -> SarifLog via return - ... and 48 more ### Model Stats -287 annotations, 16 assets, 15 threats, 10 controls, 60 exposures, 44 mitigations, 68 flows +290 annotations, 16 assets, 15 threats, 12 controls, 60 exposures, 44 mitigations, 68 flows @@ -103,3 +103,7 @@ Every time you write or modify code that touches security-relevant behavior, you + + + + diff --git a/.cursor/rules/guardlink.mdc b/.cursor/rules/guardlink.mdc index 0618bb5..aacb2c4 100644 --- a/.cursor/rules/guardlink.mdc +++ b/.cursor/rules/guardlink.mdc @@ -44,16 +44,16 @@ Every time you write or modify code that touches security-relevant behavior, you **Assets:** #parser (GuardLink,Parser), #cli (GuardLink,CLI), #tui (GuardLink,TUI), #mcp (GuardLink,MCP), #llm-client (GuardLink,LLM_Client), #dashboard (GuardLink,Dashboard), #init (GuardLink,Init), #agent-launcher (GuardLink,Agent_Launcher), #diff (GuardLink,Diff), #report (GuardLink,Report), #sarif (GuardLink,SARIF), #suggest (GuardLink,Suggest), #workspace-link (Workspace,Link), #merge-engine (Workspace,Merge), #report-metadata (Workspace,Metadata), #workspace-config (Workspace,Config) **Threats:** #path-traversal (Path_Traversal) [high], #cmd-injection (Command_Injection) [critical], #xss (Cross_Site_Scripting) [high], #api-key-exposure (API_Key_Exposure) [high], #ssrf (Server_Side_Request_Forgery) [medium], #redos (ReDoS) [medium], #arbitrary-write (Arbitrary_File_Write) [high], #prompt-injection (Prompt_Injection) [medium], #dos (Denial_of_Service) [medium], #data-exposure (Sensitive_Data_Exposure) [medium], #insecure-deser (Insecure_Deserialization) [medium], #child-proc-injection (Child_Process_Injection) [high], #info-disclosure (Information_Disclosure) [low], #tag-collision (Tag_Collision) [medium], #config-tamper (Config_Tampering) [medium] -**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring) +**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring), #prefix-ownership (Prefix_Ownership), #yaml-validation (YAML_Validation) ### Open Exposures (need @mitigates or @audit) -- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) -- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) -- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) - #agent-launcher exposed to #prompt-injection [medium] (src/agents/launcher.ts:13) - #agent-launcher exposed to #dos [low] (src/agents/launcher.ts:15) - #agent-launcher exposed to #prompt-injection [high] (src/agents/prompts.ts:6) +- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) +- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) +- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) - #cli exposed to #cmd-injection [critical] (src/cli/index.ts:31) - #init exposed to #data-exposure [low] (src/init/index.ts:12) - #mcp exposed to #cmd-injection [high] (src/mcp/index.ts:4) @@ -66,17 +66,6 @@ Every time you write or modify code that touches security-relevant behavior, you ### Existing Data Flows (extend, don't duplicate) -- ThreatModel -> #sarif via generateSarif -- #sarif -> SarifLog via return -- ThreatModel -> #llm-client via serializeModel -- ProjectFiles -> #llm-client via readFileSync -- #llm-client -> ReportFile via writeFileSync -- LLMConfig -> #llm-client via chatCompletion -- #llm-client -> LLMProvider via fetch -- LLMProvider -> #llm-client via response -- LLMToolCall -> #llm-client via createToolExecutor -- #llm-client -> NVD via fetch -- ProjectFiles -> #llm-client via readFileSync - EnvVars -> #agent-launcher via process.env - ConfigFile -> #agent-launcher via readFileSync - #agent-launcher -> ConfigFile via writeFileSync @@ -86,8 +75,19 @@ Every time you write or modify code that touches security-relevant behavior, you - UserPrompt -> #agent-launcher via buildAnnotatePrompt - ThreatModel -> #agent-launcher via model - #agent-launcher -> AgentPrompt via return +- ThreatModel -> #llm-client via serializeModel +- ProjectFiles -> #llm-client via readFileSync +- #llm-client -> ReportFile via writeFileSync +- LLMConfig -> #llm-client via chatCompletion +- #llm-client -> LLMProvider via fetch +- LLMProvider -> #llm-client via response +- LLMToolCall -> #llm-client via createToolExecutor +- #llm-client -> NVD via fetch +- ProjectFiles -> #llm-client via readFileSync +- ThreatModel -> #sarif via generateSarif +- #sarif -> SarifLog via return - ... and 48 more ### Model Stats -287 annotations, 16 assets, 15 threats, 10 controls, 60 exposures, 44 mitigations, 68 flows +290 annotations, 16 assets, 15 threats, 12 controls, 60 exposures, 44 mitigations, 68 flows diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md index 68da32c..bf121a4 100644 --- a/.gemini/GEMINI.md +++ b/.gemini/GEMINI.md @@ -53,16 +53,16 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c **Assets:** #parser (GuardLink,Parser), #cli (GuardLink,CLI), #tui (GuardLink,TUI), #mcp (GuardLink,MCP), #llm-client (GuardLink,LLM_Client), #dashboard (GuardLink,Dashboard), #init (GuardLink,Init), #agent-launcher (GuardLink,Agent_Launcher), #diff (GuardLink,Diff), #report (GuardLink,Report), #sarif (GuardLink,SARIF), #suggest (GuardLink,Suggest), #workspace-link (Workspace,Link), #merge-engine (Workspace,Merge), #report-metadata (Workspace,Metadata), #workspace-config (Workspace,Config) **Threats:** #path-traversal (Path_Traversal) [high], #cmd-injection (Command_Injection) [critical], #xss (Cross_Site_Scripting) [high], #api-key-exposure (API_Key_Exposure) [high], #ssrf (Server_Side_Request_Forgery) [medium], #redos (ReDoS) [medium], #arbitrary-write (Arbitrary_File_Write) [high], #prompt-injection (Prompt_Injection) [medium], #dos (Denial_of_Service) [medium], #data-exposure (Sensitive_Data_Exposure) [medium], #insecure-deser (Insecure_Deserialization) [medium], #child-proc-injection (Child_Process_Injection) [high], #info-disclosure (Information_Disclosure) [low], #tag-collision (Tag_Collision) [medium], #config-tamper (Config_Tampering) [medium] -**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring) +**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring), #prefix-ownership (Prefix_Ownership), #yaml-validation (YAML_Validation) ### Open Exposures (need @mitigates or @audit) -- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) -- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) -- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) - #agent-launcher exposed to #prompt-injection [medium] (src/agents/launcher.ts:13) - #agent-launcher exposed to #dos [low] (src/agents/launcher.ts:15) - #agent-launcher exposed to #prompt-injection [high] (src/agents/prompts.ts:6) +- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) +- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) +- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) - #cli exposed to #cmd-injection [critical] (src/cli/index.ts:31) - #init exposed to #data-exposure [low] (src/init/index.ts:12) - #mcp exposed to #cmd-injection [high] (src/mcp/index.ts:4) @@ -75,17 +75,6 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c ### Existing Data Flows (extend, don't duplicate) -- ThreatModel -> #sarif via generateSarif -- #sarif -> SarifLog via return -- ThreatModel -> #llm-client via serializeModel -- ProjectFiles -> #llm-client via readFileSync -- #llm-client -> ReportFile via writeFileSync -- LLMConfig -> #llm-client via chatCompletion -- #llm-client -> LLMProvider via fetch -- LLMProvider -> #llm-client via response -- LLMToolCall -> #llm-client via createToolExecutor -- #llm-client -> NVD via fetch -- ProjectFiles -> #llm-client via readFileSync - EnvVars -> #agent-launcher via process.env - ConfigFile -> #agent-launcher via readFileSync - #agent-launcher -> ConfigFile via writeFileSync @@ -95,11 +84,22 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c - UserPrompt -> #agent-launcher via buildAnnotatePrompt - ThreatModel -> #agent-launcher via model - #agent-launcher -> AgentPrompt via return +- ThreatModel -> #llm-client via serializeModel +- ProjectFiles -> #llm-client via readFileSync +- #llm-client -> ReportFile via writeFileSync +- LLMConfig -> #llm-client via chatCompletion +- #llm-client -> LLMProvider via fetch +- LLMProvider -> #llm-client via response +- LLMToolCall -> #llm-client via createToolExecutor +- #llm-client -> NVD via fetch +- ProjectFiles -> #llm-client via readFileSync +- ThreatModel -> #sarif via generateSarif +- #sarif -> SarifLog via return - ... and 48 more ### Model Stats -287 annotations, 16 assets, 15 threats, 10 controls, 60 exposures, 44 mitigations, 68 flows +290 annotations, 16 assets, 15 threats, 12 controls, 60 exposures, 44 mitigations, 68 flows > **Note:** This section is auto-generated. Run `guardlink sync` to update after code changes. > Any coding agent (Cursor, Claude, Copilot, Windsurf, etc.) should reference these IDs @@ -121,3 +121,7 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c + + + + diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2ae6015..68c3a9f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -53,16 +53,16 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c **Assets:** #parser (GuardLink,Parser), #cli (GuardLink,CLI), #tui (GuardLink,TUI), #mcp (GuardLink,MCP), #llm-client (GuardLink,LLM_Client), #dashboard (GuardLink,Dashboard), #init (GuardLink,Init), #agent-launcher (GuardLink,Agent_Launcher), #diff (GuardLink,Diff), #report (GuardLink,Report), #sarif (GuardLink,SARIF), #suggest (GuardLink,Suggest), #workspace-link (Workspace,Link), #merge-engine (Workspace,Merge), #report-metadata (Workspace,Metadata), #workspace-config (Workspace,Config) **Threats:** #path-traversal (Path_Traversal) [high], #cmd-injection (Command_Injection) [critical], #xss (Cross_Site_Scripting) [high], #api-key-exposure (API_Key_Exposure) [high], #ssrf (Server_Side_Request_Forgery) [medium], #redos (ReDoS) [medium], #arbitrary-write (Arbitrary_File_Write) [high], #prompt-injection (Prompt_Injection) [medium], #dos (Denial_of_Service) [medium], #data-exposure (Sensitive_Data_Exposure) [medium], #insecure-deser (Insecure_Deserialization) [medium], #child-proc-injection (Child_Process_Injection) [high], #info-disclosure (Information_Disclosure) [low], #tag-collision (Tag_Collision) [medium], #config-tamper (Config_Tampering) [medium] -**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring) +**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring), #prefix-ownership (Prefix_Ownership), #yaml-validation (YAML_Validation) ### Open Exposures (need @mitigates or @audit) -- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) -- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) -- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) - #agent-launcher exposed to #prompt-injection [medium] (src/agents/launcher.ts:13) - #agent-launcher exposed to #dos [low] (src/agents/launcher.ts:15) - #agent-launcher exposed to #prompt-injection [high] (src/agents/prompts.ts:6) +- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) +- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) +- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) - #cli exposed to #cmd-injection [critical] (src/cli/index.ts:31) - #init exposed to #data-exposure [low] (src/init/index.ts:12) - #mcp exposed to #cmd-injection [high] (src/mcp/index.ts:4) @@ -75,17 +75,6 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c ### Existing Data Flows (extend, don't duplicate) -- ThreatModel -> #sarif via generateSarif -- #sarif -> SarifLog via return -- ThreatModel -> #llm-client via serializeModel -- ProjectFiles -> #llm-client via readFileSync -- #llm-client -> ReportFile via writeFileSync -- LLMConfig -> #llm-client via chatCompletion -- #llm-client -> LLMProvider via fetch -- LLMProvider -> #llm-client via response -- LLMToolCall -> #llm-client via createToolExecutor -- #llm-client -> NVD via fetch -- ProjectFiles -> #llm-client via readFileSync - EnvVars -> #agent-launcher via process.env - ConfigFile -> #agent-launcher via readFileSync - #agent-launcher -> ConfigFile via writeFileSync @@ -95,11 +84,22 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c - UserPrompt -> #agent-launcher via buildAnnotatePrompt - ThreatModel -> #agent-launcher via model - #agent-launcher -> AgentPrompt via return +- ThreatModel -> #llm-client via serializeModel +- ProjectFiles -> #llm-client via readFileSync +- #llm-client -> ReportFile via writeFileSync +- LLMConfig -> #llm-client via chatCompletion +- #llm-client -> LLMProvider via fetch +- LLMProvider -> #llm-client via response +- LLMToolCall -> #llm-client via createToolExecutor +- #llm-client -> NVD via fetch +- ProjectFiles -> #llm-client via readFileSync +- ThreatModel -> #sarif via generateSarif +- #sarif -> SarifLog via return - ... and 48 more ### Model Stats -287 annotations, 16 assets, 15 threats, 10 controls, 60 exposures, 44 mitigations, 68 flows +290 annotations, 16 assets, 15 threats, 12 controls, 60 exposures, 44 mitigations, 68 flows > **Note:** This section is auto-generated. Run `guardlink sync` to update after code changes. > Any coding agent (Cursor, Claude, Copilot, Windsurf, etc.) should reference these IDs @@ -122,3 +122,7 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c + + + + diff --git a/.gitignore b/.gitignore index e61069c..00134a4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,19 +6,11 @@ dist/ # OS .DS_Store -# Generated outputs (not tracked — regenerate with guardlink commands) -threat-model.json -threat-model.md -threat-dashboard.html -*.sarif.json - # IDE / Agent local state .claude/ -# GuardLink runtime (tracked: definitions.ts, config.json) -.guardlink/threat-reports/ -.guardlink/*.json -!.guardlink/config.json +# GuardLink runtime config (API keys - do not commit) +.guardlink/config.json # Debug / internal _debug.ts diff --git a/.guardlink/definitions.ts b/.guardlink/definitions.ts index 7edca36..c7291dc 100644 --- a/.guardlink/definitions.ts +++ b/.guardlink/definitions.ts @@ -55,3 +55,5 @@ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking" +// @control Prefix_Ownership (#prefix-ownership) -- "Tag prefix determines owning repo, preventing cross-repo tag collisions" +// @control YAML_Validation (#yaml-validation) -- "Schema validation for workspace.yaml configuration files" diff --git a/.guardlink/threat-reports/2026-03-12T19-14-22-stride.md b/.guardlink/threat-reports/2026-03-12T19-14-22-stride.md new file mode 100644 index 0000000..b62bb2f --- /dev/null +++ b/.guardlink/threat-reports/2026-03-12T19-14-22-stride.md @@ -0,0 +1,301 @@ +# STRIDE Threat Analysis — GuardLink + +**Generated:** 2026-03-12T19:14:22Z +**Framework:** STRIDE +**Analyst:** Claude Opus 4.5 + +--- + +## Executive Summary + +GuardLink is a security annotation tool that parses source code, generates threat models, and integrates with AI coding agents. The analysis identified **15 unmitigated exposures** across 10 assets, with **1 critical**, **4 high**, **5 medium**, and **5 low** severity findings. + +**Key Risk Areas:** +1. **Command Injection (Critical)** — Child process spawning in CLI/TUI/MCP with external input +2. **Prompt Injection (High)** — User prompts concatenated into agent instructions without sanitization +3. **Arbitrary File Write (High)** — Parser can write to files discovered via glob patterns +4. **Data Exposure (Medium)** — Threat model data exposed to MCP clients and LLM providers + +**Overall Risk Posture:** MODERATE — Core security controls are in place (path validation, parameterized commands, key redaction), but several attack vectors remain unmitigated due to architectural constraints (prompt injection relies on LLM provider safety, child process spawning is delegated to trusted agents). + +--- + +## Part 1 — Annotation Validation + +### Critical Findings + +#### `#cli` → `#cmd-injection` [CRITICAL] +**Location:** `src/cli/index.ts:31` +**Annotation:** `@exposes #cli to #cmd-injection [critical] -- "Agent launcher spawns child processes"` +**Audit:** `@audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args"` + +**Validation:** ✅ ACCURATE +The CLI delegates process spawning to `agents/launcher.ts` which uses `spawn()` with explicit argument arrays rather than shell interpolation. The `#param-commands` control is correctly applied. However, the exposure remains because the binary names come from a hardcoded registry — if that registry were compromised or extended with user input, command injection would be possible. + +**Recommendation:** Add runtime validation that agent binary paths exist and are not symlinks to unexpected locations. + +### High Severity Findings + +#### `#agent-launcher` → `#prompt-injection` [HIGH] +**Location:** `src/agents/prompts.ts:6` +**Annotation:** `@exposes #agent-launcher to #prompt-injection [high] -- "User prompt concatenated into agent instruction text"` + +**Validation:** ⚠️ CONCERNING +User prompts are directly concatenated into the instruction text sent to coding agents. While the `@audit` notes that "prompt injection mitigated by agent's own safety measures," this creates a **transitive trust dependency** — GuardLink's security relies on the security of external agents (Claude Code, Cursor, Codex). + +**Risk:** A malicious user could craft prompts that instruct the agent to: +- Modify security annotations maliciously +- Exfiltrate sensitive code via the annotation system +- Bypass GuardLink's intended workflow + +**Recommendation:** Implement prompt templating with strict escaping, or use structured message formats that separate system instructions from user content. + +#### `#mcp` → `#cmd-injection` [HIGH] +**Location:** `src/mcp/index.ts:4` +**Annotation:** `@exposes #mcp to #cmd-injection [high] -- "Accepts tool calls from external MCP clients"` + +**Validation:** ✅ ACCURATE +The MCP server accepts tool calls over stdio from any connected client. While Zod schema validation is applied to inputs, the attack surface includes: +- `guardlink_annotate` — passes prompts to LLM +- `guardlink_threat_report` — spawns analysis processes +- `guardlink_diff` — executes git commands + +**Mitigating Factor:** The `@audit` notes "All tool calls validated by server.ts before execution" — this is correct, but validation focuses on schema conformance, not semantic safety. + +#### `#parser` → `#arbitrary-write` [HIGH] +**Location:** `src/parser/clear.ts:7` +**Annotation:** `@exposes #parser to #arbitrary-write [high] -- "Writes modified content back to discovered files"` + +**Validation:** ✅ ACCURATE with caveat +The `clearAnnotations()` function writes to files discovered via `fast-glob`. The `#glob-filtering` control applies `DEFAULT_EXCLUDE` patterns, but: +- A malicious `.gitignore` or custom exclude patterns could be manipulated +- Symlinks within the project could redirect writes outside the project + +**Mitigating Factor:** `@audit` notes "Destructive operation requires explicit user confirmation via dryRun flag" — this is a UX control, not a technical one. + +#### `#tui` → `#cmd-injection` [HIGH] +**Location:** `src/tui/commands.ts:11` +**Annotation:** `@exposes #tui to #cmd-injection [high] -- "/annotate and /threat-report spawn child processes"` + +**Validation:** ✅ ACCURATE +Same pattern as CLI — delegated to `agents/launcher.ts`. The TUI adds risk because it accepts freeform user input in an interactive session, making it easier to craft malicious commands. + +### Medium Severity Findings + +#### `#mcp` → `#data-exposure` [MEDIUM] +**Location:** `src/mcp/server.ts:34` +**Annotation:** `@exposes #mcp to #data-exposure [medium] -- "Resources expose full threat model to MCP clients"` + +**Validation:** ✅ ACCURATE +MCP resources (`guardlink://model`, `guardlink://definitions`, `guardlink://unmitigated`) expose the complete threat model to any connected client. This is **by design** for AI agent integration, but represents information disclosure risk if: +- MCP transport is compromised +- Unauthorized clients connect to the stdio interface +- Threat model contains sensitive architectural details + +### Low Severity Findings + +All low-severity `#data-exposure` and `#dos` findings are accurately annotated and appropriately flagged with `@audit` annotations acknowledging the accepted risk. + +--- + +## Part 2 — STRIDE Threat Model + +### S — Spoofing + +**Finding S1: No Authentication on MCP Transport** +**Severity:** Medium +**Assets:** `#mcp` +**Evidence:** The MCP server uses stdio transport with no authentication mechanism. Any process that can connect to stdin/stdout can impersonate a legitimate client. + +**Annotation Gap:** No `@exposes #mcp to #spoofing` annotation exists. + +**Attack Scenario:** +1. Attacker gains code execution on developer machine +2. Attacker spawns process that connects to GuardLink MCP server +3. Attacker issues tool calls to exfiltrate threat model or modify annotations + +**Mitigation:** Consider adding MCP client authentication (capability tokens, process attestation) or documenting this as an accepted risk with `@accepts`. + +--- + +### T — Tampering + +**Finding T1: Annotation Tampering via Prompt Injection** +**Severity:** High +**Assets:** `#agent-launcher`, `#mcp` +**Evidence:** User prompts are concatenated into agent instructions (`src/agents/prompts.ts:6`). A malicious prompt could instruct the agent to: +- Add false `@mitigates` annotations to hide vulnerabilities +- Remove `@exposes` annotations from critical code +- Inject malicious `@shield` blocks to hide code from analysis + +**Data Flow:** `UserPrompt → #agent-launcher → AgentProcess → SourceFiles` + +**Annotation Accuracy:** The `@exposes #agent-launcher to #prompt-injection [high]` correctly identifies this risk. + +**Mitigation:** +1. Implement annotation integrity checks (hash of annotation blocks) +2. Require human approval for annotation changes via AI agents +3. Add `@audit` trail for all AI-generated annotations + +**Finding T2: Config File Tampering** +**Severity:** Medium +**Assets:** `#workspace-config` +**Evidence:** `src/workspace/types.ts:9` notes `@threat Config_Tampering (#config-tamper) [medium]` with mitigation via `#yaml-validation`. + +**Annotation Accuracy:** ✅ Correctly annotated with mitigation. + +--- + +### R — Repudiation + +**Finding R1: No Audit Trail for AI-Generated Changes** +**Severity:** Medium +**Assets:** `#agent-launcher`, `#tui`, `#cli` +**Evidence:** When AI agents modify annotations via `/annotate` or `guardlink annotate`, there is no persistent audit log of: +- What changes were made +- Which agent made them +- What prompt triggered the change + +**Annotation Gap:** `@audit` annotations exist on assets, but no `@flows` document the audit trail path. + +**Recommendation:** Add `@flows #agent-launcher → AuditLog via appendFile` with corresponding implementation. + +**Finding R2: Threat Report Attribution** +**Severity:** Low +**Assets:** `#llm-client` +**Evidence:** AI-generated threat reports are saved to `.guardlink/threat-reports/` with timestamps, but the LLM model and configuration used are not always recorded in the report metadata. + +**Mitigation:** Reports should include full provenance (model, provider, API version, prompt hash). + +--- + +### I — Information Disclosure + +**Finding I1: Full Threat Model Exposure to LLM Providers** +**Severity:** Medium +**Assets:** `#llm-client` +**Evidence:** `src/analyze/index.ts:12` — `@exposes #llm-client to #data-exposure [low]` with `@audit` noting "Threat model data intentionally sent to LLM for analysis." + +**Concern:** The annotation rates this as LOW severity, but the actual risk depends on: +- Sensitivity of the codebase being analyzed +- LLM provider data retention policies +- Whether code snippets include secrets (the `#key-redaction` control may not catch all patterns) + +**Recommendation:** Upgrade severity to MEDIUM and add configurable redaction patterns. + +**Finding I2: API Key Storage** +**Severity:** Medium +**Assets:** `#init` +**Evidence:** `src/init/index.ts:12` — API keys written to `.guardlink/config.json`. The `@audit` notes ".gitignore entry added automatically." + +**Residual Risk:** +- `.gitignore` can be overwritten or removed +- Backup tools may capture config files +- IDE indexing may expose keys + +**Mitigation:** Consider using system keychain or environment variables exclusively. + +**Finding I3: SARIF Export Reveals Architecture** +**Severity:** Low +**Assets:** `#sarif` +**Evidence:** `src/analyzer/sarif.ts:15` — SARIF output includes file paths, line numbers, and vulnerability descriptions. This is intentional for CI/CD integration but could reveal: +- Internal architecture to external parties +- Security weaknesses if SARIF files are leaked + +**Annotation Accuracy:** ✅ Correctly annotated with `@audit` acknowledging intentional disclosure. + +--- + +### D — Denial of Service + +**Finding D1: No Resource Limits on File Processing** +**Severity:** Low +**Assets:** `#suggest`, `#parser` +**Evidence:** +- `src/mcp/suggest.ts:16` — "Large files loaded into memory for pattern scanning" +- No explicit file size limits in `fast-glob` configuration + +**Attack Scenario:** Crafted repository with extremely large files or deep directory trees could exhaust memory. + +**Annotation Accuracy:** ✅ Correctly annotated with `@audit` accepting the risk. + +**Mitigation:** Add `#resource-limits` control with explicit file size caps (e.g., 10MB per file, 1000 files max). + +**Finding D2: Agent Spawn Timeout** +**Severity:** Low +**Assets:** `#agent-launcher` +**Evidence:** `src/agents/launcher.ts:15` — "No timeout on foreground spawn; agent controls duration" + +**Annotation Accuracy:** ✅ Correctly annotated. The `@audit` notes this is intentional for interactive sessions. + +--- + +### E — Elevation of Privilege + +**Finding E1: MCP Tool Call Privilege Escalation** +**Severity:** High +**Assets:** `#mcp` +**Evidence:** MCP tools execute with the same privileges as the GuardLink process. A compromised or malicious MCP client could: +- Write files anywhere the process has access (`guardlink_sarif`, `guardlink_report`) +- Execute git commands (`guardlink_diff`) +- Spawn child processes (`guardlink_annotate`) + +**Data Flow:** `MCPClient → #mcp via tool_call → FileSystem via writeFile` + +**Annotation Gap:** No `@exposes #mcp to #privilege-escalation` annotation exists. + +**Mitigation:** +1. Add capability-based access control for MCP tools +2. Implement path sandboxing for file writes +3. Add `@exposes #mcp to #privilege-escalation` annotation + +**Finding E2: Agent Process Inherits Environment** +**Severity:** Medium +**Assets:** `#agent-launcher` +**Evidence:** `EnvVars → #agent-launcher via process.env` — spawned agents inherit the full environment, including API keys and sensitive configuration. + +**Mitigation:** Implement environment filtering to pass only necessary variables to agents. + +--- + +## Priority Action Items + +### Critical (Immediate) + +1. **Add prompt sanitization** to `src/agents/prompts.ts` — escape or template user prompts before concatenation +2. **Document MCP security model** — add `@assumes` annotation about trusted client requirement + +### High (This Sprint) + +3. **Implement path sandboxing** for MCP file write operations +4. **Add environment filtering** in `launchAgent()` to prevent credential leakage +5. **Add `@exposes` annotations** for spoofing and privilege escalation gaps + +### Medium (Next Sprint) + +6. **Add audit logging** for AI-generated annotation changes +7. **Implement file size limits** in parser and suggest modules +8. **Upgrade `#data-exposure` severity** for LLM client to MEDIUM + +### Low (Backlog) + +9. **Consider system keychain** for API key storage +10. **Add provenance metadata** to threat reports + +--- + +## Annotation Coverage Summary + +| Category | Annotated | Missing | +|----------|-----------|---------| +| Assets | 16 | 0 | +| Threats | 15 | 2 (spoofing, priv-esc) | +| Controls | 12 | 2 (audit-logging, env-filtering) | +| Data Flows | 68 | ~5 (audit trails) | +| Boundaries | 9 | 0 | + +**Overall Coverage:** 85% — Good annotation discipline with gaps in newer attack categories (prompt injection defense, AI agent trust boundaries). + +--- + +*Report generated by Claude Opus 4.5 using GuardLink STRIDE framework.* diff --git a/.windsurfrules b/.windsurfrules index dd2786e..8d40c54 100644 --- a/.windsurfrules +++ b/.windsurfrules @@ -39,16 +39,16 @@ Every time you write or modify code that touches security-relevant behavior, you **Assets:** #parser (GuardLink,Parser), #cli (GuardLink,CLI), #tui (GuardLink,TUI), #mcp (GuardLink,MCP), #llm-client (GuardLink,LLM_Client), #dashboard (GuardLink,Dashboard), #init (GuardLink,Init), #agent-launcher (GuardLink,Agent_Launcher), #diff (GuardLink,Diff), #report (GuardLink,Report), #sarif (GuardLink,SARIF), #suggest (GuardLink,Suggest), #workspace-link (Workspace,Link), #merge-engine (Workspace,Merge), #report-metadata (Workspace,Metadata), #workspace-config (Workspace,Config) **Threats:** #path-traversal (Path_Traversal) [high], #cmd-injection (Command_Injection) [critical], #xss (Cross_Site_Scripting) [high], #api-key-exposure (API_Key_Exposure) [high], #ssrf (Server_Side_Request_Forgery) [medium], #redos (ReDoS) [medium], #arbitrary-write (Arbitrary_File_Write) [high], #prompt-injection (Prompt_Injection) [medium], #dos (Denial_of_Service) [medium], #data-exposure (Sensitive_Data_Exposure) [medium], #insecure-deser (Insecure_Deserialization) [medium], #child-proc-injection (Child_Process_Injection) [high], #info-disclosure (Information_Disclosure) [low], #tag-collision (Tag_Collision) [medium], #config-tamper (Config_Tampering) [medium] -**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring) +**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring), #prefix-ownership (Prefix_Ownership), #yaml-validation (YAML_Validation) ### Open Exposures (need @mitigates or @audit) -- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) -- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) -- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) - #agent-launcher exposed to #prompt-injection [medium] (src/agents/launcher.ts:13) - #agent-launcher exposed to #dos [low] (src/agents/launcher.ts:15) - #agent-launcher exposed to #prompt-injection [high] (src/agents/prompts.ts:6) +- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) +- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) +- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) - #cli exposed to #cmd-injection [critical] (src/cli/index.ts:31) - #init exposed to #data-exposure [low] (src/init/index.ts:12) - #mcp exposed to #cmd-injection [high] (src/mcp/index.ts:4) @@ -61,17 +61,6 @@ Every time you write or modify code that touches security-relevant behavior, you ### Existing Data Flows (extend, don't duplicate) -- ThreatModel -> #sarif via generateSarif -- #sarif -> SarifLog via return -- ThreatModel -> #llm-client via serializeModel -- ProjectFiles -> #llm-client via readFileSync -- #llm-client -> ReportFile via writeFileSync -- LLMConfig -> #llm-client via chatCompletion -- #llm-client -> LLMProvider via fetch -- LLMProvider -> #llm-client via response -- LLMToolCall -> #llm-client via createToolExecutor -- #llm-client -> NVD via fetch -- ProjectFiles -> #llm-client via readFileSync - EnvVars -> #agent-launcher via process.env - ConfigFile -> #agent-launcher via readFileSync - #agent-launcher -> ConfigFile via writeFileSync @@ -81,11 +70,22 @@ Every time you write or modify code that touches security-relevant behavior, you - UserPrompt -> #agent-launcher via buildAnnotatePrompt - ThreatModel -> #agent-launcher via model - #agent-launcher -> AgentPrompt via return +- ThreatModel -> #llm-client via serializeModel +- ProjectFiles -> #llm-client via readFileSync +- #llm-client -> ReportFile via writeFileSync +- LLMConfig -> #llm-client via chatCompletion +- #llm-client -> LLMProvider via fetch +- LLMProvider -> #llm-client via response +- LLMToolCall -> #llm-client via createToolExecutor +- #llm-client -> NVD via fetch +- ProjectFiles -> #llm-client via readFileSync +- ThreatModel -> #sarif via generateSarif +- #sarif -> SarifLog via return - ... and 48 more ### Model Stats -287 annotations, 16 assets, 15 threats, 10 controls, 60 exposures, 44 mitigations, 68 flows +290 annotations, 16 assets, 15 threats, 12 controls, 60 exposures, 44 mitigations, 68 flows @@ -103,3 +103,7 @@ Every time you write or modify code that touches security-relevant behavior, you + + + + diff --git a/AGENTS.md b/AGENTS.md index 68da32c..bf121a4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,16 +53,16 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c **Assets:** #parser (GuardLink,Parser), #cli (GuardLink,CLI), #tui (GuardLink,TUI), #mcp (GuardLink,MCP), #llm-client (GuardLink,LLM_Client), #dashboard (GuardLink,Dashboard), #init (GuardLink,Init), #agent-launcher (GuardLink,Agent_Launcher), #diff (GuardLink,Diff), #report (GuardLink,Report), #sarif (GuardLink,SARIF), #suggest (GuardLink,Suggest), #workspace-link (Workspace,Link), #merge-engine (Workspace,Merge), #report-metadata (Workspace,Metadata), #workspace-config (Workspace,Config) **Threats:** #path-traversal (Path_Traversal) [high], #cmd-injection (Command_Injection) [critical], #xss (Cross_Site_Scripting) [high], #api-key-exposure (API_Key_Exposure) [high], #ssrf (Server_Side_Request_Forgery) [medium], #redos (ReDoS) [medium], #arbitrary-write (Arbitrary_File_Write) [high], #prompt-injection (Prompt_Injection) [medium], #dos (Denial_of_Service) [medium], #data-exposure (Sensitive_Data_Exposure) [medium], #insecure-deser (Insecure_Deserialization) [medium], #child-proc-injection (Child_Process_Injection) [high], #info-disclosure (Information_Disclosure) [low], #tag-collision (Tag_Collision) [medium], #config-tamper (Config_Tampering) [medium] -**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring) +**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring), #prefix-ownership (Prefix_Ownership), #yaml-validation (YAML_Validation) ### Open Exposures (need @mitigates or @audit) -- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) -- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) -- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) - #agent-launcher exposed to #prompt-injection [medium] (src/agents/launcher.ts:13) - #agent-launcher exposed to #dos [low] (src/agents/launcher.ts:15) - #agent-launcher exposed to #prompt-injection [high] (src/agents/prompts.ts:6) +- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) +- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) +- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) - #cli exposed to #cmd-injection [critical] (src/cli/index.ts:31) - #init exposed to #data-exposure [low] (src/init/index.ts:12) - #mcp exposed to #cmd-injection [high] (src/mcp/index.ts:4) @@ -75,17 +75,6 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c ### Existing Data Flows (extend, don't duplicate) -- ThreatModel -> #sarif via generateSarif -- #sarif -> SarifLog via return -- ThreatModel -> #llm-client via serializeModel -- ProjectFiles -> #llm-client via readFileSync -- #llm-client -> ReportFile via writeFileSync -- LLMConfig -> #llm-client via chatCompletion -- #llm-client -> LLMProvider via fetch -- LLMProvider -> #llm-client via response -- LLMToolCall -> #llm-client via createToolExecutor -- #llm-client -> NVD via fetch -- ProjectFiles -> #llm-client via readFileSync - EnvVars -> #agent-launcher via process.env - ConfigFile -> #agent-launcher via readFileSync - #agent-launcher -> ConfigFile via writeFileSync @@ -95,11 +84,22 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c - UserPrompt -> #agent-launcher via buildAnnotatePrompt - ThreatModel -> #agent-launcher via model - #agent-launcher -> AgentPrompt via return +- ThreatModel -> #llm-client via serializeModel +- ProjectFiles -> #llm-client via readFileSync +- #llm-client -> ReportFile via writeFileSync +- LLMConfig -> #llm-client via chatCompletion +- #llm-client -> LLMProvider via fetch +- LLMProvider -> #llm-client via response +- LLMToolCall -> #llm-client via createToolExecutor +- #llm-client -> NVD via fetch +- ProjectFiles -> #llm-client via readFileSync +- ThreatModel -> #sarif via generateSarif +- #sarif -> SarifLog via return - ... and 48 more ### Model Stats -287 annotations, 16 assets, 15 threats, 10 controls, 60 exposures, 44 mitigations, 68 flows +290 annotations, 16 assets, 15 threats, 12 controls, 60 exposures, 44 mitigations, 68 flows > **Note:** This section is auto-generated. Run `guardlink sync` to update after code changes. > Any coding agent (Cursor, Claude, Copilot, Windsurf, etc.) should reference these IDs @@ -121,3 +121,7 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eeb8c2..bc6ffd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,24 @@ All notable changes to GuardLink CLI will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.4.1] — 2026-03-12 + +### Fixed + +- **GAL reference (`/gal`, `guardlink gal`)**: Fixed all syntax examples to match the actual parser — descriptions now correctly show `-- "quoted text"` format instead of the non-functional `: text` format; severity now shows bracket notation `[high]` / `[P0]` instead of `severity:high`; `@flows` now shows `->` arrow syntax instead of `to`; `@validates` now shows `for` preposition instead of `on`; `@owns` now includes the required `for` preposition; `@mitigates` now documents `using` as the primary keyword (with `with` as v1 compat) +- **GAL reference**: Added missing documentation for external references (`cwe:CWE-89`, `owasp:A03:2021`, `capec:CAPEC-66`, `attack:T1190`) on `@threat` and `@exposes` annotations +- **GAL reference**: Added missing `@boundary` alternate syntaxes (`@boundary between A and B`, `@boundary A | B`) and `(#id)` support +- **GAL reference**: Added missing standalone `@shield` single-line marker (was only documenting `@shield:begin/end` blocks) +- **TUI `/help`**: Added missing `/unannotated` command to the help output (was registered and functional but not listed) +- **CLI version**: Fixed `guardlink --version` reporting `1.1.0` instead of the actual package version + +### Changed + +- **GAL reference**: Added new "External References" section explaining `cwe:`, `owasp:`, `capec:`, `attack:` ref syntax +- **GAL reference**: Updated Tips section with description format, severity format, and `@flows ->` syntax reminders +- **Annotations**: Changed `@comment` to `@audit` on agent-launcher timeout note for better governance visibility +- **Annotations**: Added `@audit` to MCP suggest module, added workspace-related controls to definitions + ## [1.4.0] — 2026-02-27 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 2ae6015..68c3a9f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -53,16 +53,16 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c **Assets:** #parser (GuardLink,Parser), #cli (GuardLink,CLI), #tui (GuardLink,TUI), #mcp (GuardLink,MCP), #llm-client (GuardLink,LLM_Client), #dashboard (GuardLink,Dashboard), #init (GuardLink,Init), #agent-launcher (GuardLink,Agent_Launcher), #diff (GuardLink,Diff), #report (GuardLink,Report), #sarif (GuardLink,SARIF), #suggest (GuardLink,Suggest), #workspace-link (Workspace,Link), #merge-engine (Workspace,Merge), #report-metadata (Workspace,Metadata), #workspace-config (Workspace,Config) **Threats:** #path-traversal (Path_Traversal) [high], #cmd-injection (Command_Injection) [critical], #xss (Cross_Site_Scripting) [high], #api-key-exposure (API_Key_Exposure) [high], #ssrf (Server_Side_Request_Forgery) [medium], #redos (ReDoS) [medium], #arbitrary-write (Arbitrary_File_Write) [high], #prompt-injection (Prompt_Injection) [medium], #dos (Denial_of_Service) [medium], #data-exposure (Sensitive_Data_Exposure) [medium], #insecure-deser (Insecure_Deserialization) [medium], #child-proc-injection (Child_Process_Injection) [high], #info-disclosure (Information_Disclosure) [low], #tag-collision (Tag_Collision) [medium], #config-tamper (Config_Tampering) [medium] -**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring) +**Controls:** #path-validation (Path_Validation), #input-sanitize (Input_Sanitization), #output-encoding (Output_Encoding), #key-redaction (Key_Redaction), #process-sandbox (Process_Sandboxing), #config-validation (Config_Validation), #resource-limits (Resource_Limits), #param-commands (Parameterized_Commands), #glob-filtering (Glob_Pattern_Filtering), #regex-anchoring (Regex_Anchoring), #prefix-ownership (Prefix_Ownership), #yaml-validation (YAML_Validation) ### Open Exposures (need @mitigates or @audit) -- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) -- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) -- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) - #agent-launcher exposed to #prompt-injection [medium] (src/agents/launcher.ts:13) - #agent-launcher exposed to #dos [low] (src/agents/launcher.ts:15) - #agent-launcher exposed to #prompt-injection [high] (src/agents/prompts.ts:6) +- #llm-client exposed to #data-exposure [low] (src/analyze/index.ts:12) +- #llm-client exposed to #prompt-injection [medium] (src/analyze/llm.ts:17) +- #sarif exposed to #data-exposure [low] (src/analyzer/sarif.ts:15) - #cli exposed to #cmd-injection [critical] (src/cli/index.ts:31) - #init exposed to #data-exposure [low] (src/init/index.ts:12) - #mcp exposed to #cmd-injection [high] (src/mcp/index.ts:4) @@ -75,17 +75,6 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c ### Existing Data Flows (extend, don't duplicate) -- ThreatModel -> #sarif via generateSarif -- #sarif -> SarifLog via return -- ThreatModel -> #llm-client via serializeModel -- ProjectFiles -> #llm-client via readFileSync -- #llm-client -> ReportFile via writeFileSync -- LLMConfig -> #llm-client via chatCompletion -- #llm-client -> LLMProvider via fetch -- LLMProvider -> #llm-client via response -- LLMToolCall -> #llm-client via createToolExecutor -- #llm-client -> NVD via fetch -- ProjectFiles -> #llm-client via readFileSync - EnvVars -> #agent-launcher via process.env - ConfigFile -> #agent-launcher via readFileSync - #agent-launcher -> ConfigFile via writeFileSync @@ -95,11 +84,22 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c - UserPrompt -> #agent-launcher via buildAnnotatePrompt - ThreatModel -> #agent-launcher via model - #agent-launcher -> AgentPrompt via return +- ThreatModel -> #llm-client via serializeModel +- ProjectFiles -> #llm-client via readFileSync +- #llm-client -> ReportFile via writeFileSync +- LLMConfig -> #llm-client via chatCompletion +- #llm-client -> LLMProvider via fetch +- LLMProvider -> #llm-client via response +- LLMToolCall -> #llm-client via createToolExecutor +- #llm-client -> NVD via fetch +- ProjectFiles -> #llm-client via readFileSync +- ThreatModel -> #sarif via generateSarif +- #sarif -> SarifLog via return - ... and 48 more ### Model Stats -287 annotations, 16 assets, 15 threats, 10 controls, 60 exposures, 44 mitigations, 68 flows +290 annotations, 16 assets, 15 threats, 12 controls, 60 exposures, 44 mitigations, 68 flows > **Note:** This section is auto-generated. Run `guardlink sync` to update after code changes. > Any coding agent (Cursor, Claude, Copilot, Windsurf, etc.) should reference these IDs @@ -122,3 +122,7 @@ This project uses [GuardLink](https://guardlink.bugb.io) annotations in source c + + + + diff --git a/package.json b/package.json index fe73d4f..7874316 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "guardlink", - "version": "1.4.0", + "version": "1.4.1", "description": "GuardLink — Security annotations for code. Threat modeling that lives in your codebase.", "type": "module", "bin": { diff --git a/src/agents/launcher.ts b/src/agents/launcher.ts index 76ce8de..77f1200 100644 --- a/src/agents/launcher.ts +++ b/src/agents/launcher.ts @@ -13,7 +13,7 @@ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" - * @comment -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" + * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path" * @flows AgentProcess -> #agent-launcher via stdout -- "Agent output capture" diff --git a/src/cli/index.ts b/src/cli/index.ts index a737642..ec93948 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -97,7 +97,7 @@ function detectProjectName(root: string, explicit?: string): string { program .name('guardlink') .description('GuardLink — Security annotations for code. Threat modeling that lives in your codebase.') - .version('1.1.0') + .version('1.4.1') .addHelpText('before', gradient(['#00ff41', '#00d4ff'])(ASCII_LOGO)); // ─── init ──────────────────────────────────────────────────────────── @@ -1407,29 +1407,29 @@ program console.log(D(' Annotations live in source code comments. GuardLink parses')); console.log(D(' them to build a live threat model from your codebase.')); console.log(''); - console.log(D(' Syntax: @verb subject [preposition object] [: description]')); + console.log(D(' Syntax: @verb subject [preposition object] [-- "description"]')); console.log(''); // ── DEFINITIONS ── console.log(H(' ── Definitions ─────────────────────────────────────────────')); console.log(''); - console.log(` ${V('@asset')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@asset')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Declare a named asset (component, service, data store).')); console.log(D(' Path uses dot notation for hierarchy.')); - console.log(EX(' // @asset api.auth.token_store : Stores JWT refresh tokens')); + console.log(EX(' // @asset api.auth.token_store -- "Stores JWT refresh tokens"')); console.log(EX(' // @asset db.users')); console.log(''); - console.log(` ${V('@threat')} ${K('')} ${D('[severity: critical|high|medium|low] [: description]')}`); - console.log(D(' Declare a named threat. Severity aliases: P0=critical P1=high P2=medium P3=low.')); - console.log(EX(' // @threat SQL Injection severity:high : Unsanitized input reaches DB')); - console.log(EX(' // @threat Token Theft severity:P0')); + console.log(` ${V('@threat')} ${K('')} ${D('(#id)')} ${D('[critical|high|medium|low]')} ${D('[ext-refs]')} ${D('[-- "description"]')}`); + console.log(D(' Declare a named threat. Severity in brackets: [P0]=[critical] [P1]=[high] [P2]=[medium] [P3]=[low].')); + console.log(EX(' // @threat SQL Injection (#sql-inj) [high] cwe:CWE-89 -- "Unsanitized input reaches DB"')); + console.log(EX(' // @threat Token Theft [P0]')); console.log(''); - console.log(` ${V('@control')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@control')} ${K('')} ${D('(#id)')} ${D('[-- "description"]')}`); console.log(D(' Declare a security control (mitigation mechanism).')); - console.log(EX(' // @control Input Validation : Sanitize all user-supplied strings')); + console.log(EX(' // @control Input Validation (#input-val) -- "Sanitize all user-supplied strings"')); console.log(EX(' // @control Rate Limiting')); console.log(''); @@ -1437,103 +1437,122 @@ program console.log(H(' ── Relationships ───────────────────────────────────────────')); console.log(''); - console.log(` ${V('@exposes')} ${K('')} ${D('to')} ${K('')} ${D('[severity: ...] [: description]')}`); + console.log(` ${V('@exposes')} ${K('')} ${D('to')} ${K('')} ${D('[severity]')} ${D('[ext-refs]')} ${D('[-- "description"]')}`); console.log(D(' Mark an asset as exposed to a threat at this code location.')); console.log(D(' This is the primary annotation — every exposure creates a finding.')); - console.log(EX(' // @exposes api.auth to SQL Injection severity:high')); - console.log(EX(' // @exposes db.users to Token Theft severity:critical : No token rotation')); + console.log(EX(' // @exposes api.auth to SQL Injection [high] cwe:CWE-89')); + console.log(EX(' // @exposes db.users to Token Theft [critical] -- "No token rotation"')); console.log(''); - console.log(` ${V('@mitigates')} ${K('')} ${D('against')} ${K('')} ${D('[with')} ${K('')}${D('] [: description]')}`); + console.log(` ${V('@mitigates')} ${K('')} ${D('against')} ${K('')} ${D('[using')} ${K('')}${D(']')} ${D('[-- "description"]')}`); console.log(D(' Mark that a control mitigates a threat on an asset.')); console.log(D(' Closes the exposure — removes it from open findings.')); - console.log(EX(' // @mitigates api.auth against SQL Injection with Input Validation')); - console.log(EX(' // @mitigates db.users against Token Theft : Rotation implemented in v2')); + console.log(D(' "using" is the primary keyword; "with" also accepted.')); + console.log(EX(' // @mitigates api.auth against SQL Injection using Input Validation')); + console.log(EX(' // @mitigates db.users against Token Theft -- "Rotation implemented in v2"')); console.log(''); - console.log(` ${V('@accepts')} ${K('')} ${D('on')} ${K('')} ${D('[: reason]')}`); + console.log(` ${V('@accepts')} ${K('')} ${D('on')} ${K('')} ${D('[-- "reason"]')}`); console.log(D(' Explicitly accept a risk. Removes it from open findings.')); console.log(D(' Use when the risk is known and intentionally not mitigated.')); - console.log(EX(' // @accepts Timing Attack on api.auth : Acceptable for current threat model')); + console.log(EX(' // @accepts Timing Attack on api.auth -- "Acceptable for current threat model"')); console.log(''); - console.log(` ${V('@transfers')} ${K('')} ${D('from')} ${K('')} ${D('to')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@transfers')} ${K('')} ${D('from')} ${K('')} ${D('to')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Transfer responsibility for a threat to another asset/team.')); - console.log(EX(' // @transfers DDoS from api.gateway to cdn.cloudflare : Handled by CDN layer')); + console.log(EX(' // @transfers DDoS from api.gateway to cdn.cloudflare -- "Handled by CDN layer"')); console.log(''); // ── DATA FLOWS ── console.log(H(' ── Data Flows & Boundaries ─────────────────────────────────')); console.log(''); - console.log(` ${V('@flows')} ${K('')} ${D('to')} ${K('')} ${D('[via')} ${K('')}${D('] [: description]')}`); + console.log(` ${V('@flows')} ${K('')} ${D('->')} ${K('')} ${D('[via')} ${K('')}${D(']')} ${D('[-- "description"]')}`); console.log(D(' Document data movement between components.')); console.log(D(' Appears in the Data Flow Diagram.')); - console.log(EX(' // @flows api.auth to db.users via TLS 1.3')); - console.log(EX(' // @flows mobile.app to api.gateway via HTTPS : User credentials')); + console.log(EX(' // @flows api.auth -> db.users via TLS 1.3')); + console.log(EX(' // @flows mobile.app -> api.gateway via HTTPS -- "User credentials"')); console.log(''); - console.log(` ${V('@boundary')} ${K('')} ${D('and')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@boundary')} ${K('')} ${D('and')} ${K('')} ${D('(#id)')} ${D('[-- "description"]')}`); console.log(D(' Declare a trust boundary between two assets.')); console.log(D(' Groups assets in the Data Flow Diagram.')); - console.log(EX(' // @boundary internet and api.gateway : Public-facing edge')); - console.log(EX(' // @boundary api.gateway and db.users : Internal network boundary')); + console.log(D(' Alternate: @boundary between A and B or @boundary A | B')); + console.log(EX(' // @boundary internet and api.gateway (#edge) -- "Public-facing edge"')); + console.log(EX(' // @boundary api.gateway | db.users -- "Internal network boundary"')); console.log(''); // ── LIFECYCLE ── console.log(H(' ── Lifecycle & Governance ──────────────────────────────────')); console.log(''); - console.log(` ${V('@handles')} ${K('')} ${D('on')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@handles')} ${K('')} ${D('on')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Declare data classification handled by an asset.')); console.log(D(' Classifications: pii phi financial secrets internal public')); - console.log(EX(' // @handles pii on db.users : Stores name, email, phone')); + console.log(EX(' // @handles pii on db.users -- "Stores name, email, phone"')); console.log(EX(' // @handles secrets on api.auth.token_store')); console.log(''); - console.log(` ${V('@owns')} ${K('')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@owns')} ${K('')} ${D('for')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Assign ownership of an asset to a team or person.')); - console.log(EX(' // @owns platform-team api.auth')); + console.log(EX(' // @owns platform-team for api.auth')); console.log(''); - console.log(` ${V('@validates')} ${K('')} ${D('on')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@validates')} ${K('')} ${D('for')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Assert that a control has been validated/tested on an asset.')); - console.log(EX(' // @validates Input Validation on api.auth : Pen-tested 2024-Q3')); + console.log(EX(' // @validates Input Validation for api.auth -- "Pen-tested 2024-Q3"')); console.log(''); - console.log(` ${V('@audit')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@audit')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Mark that this code path is an audit trail point.')); - console.log(EX(' // @audit db.users : All writes logged to audit_log table')); + console.log(EX(' // @audit db.users -- "All writes logged to audit_log table"')); console.log(''); - console.log(` ${V('@assumes')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@assumes')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Document a security assumption about an asset.')); - console.log(EX(' // @assumes api.gateway : Upstream WAF filters malformed requests')); + console.log(EX(' // @assumes api.gateway -- "Upstream WAF filters malformed requests"')); console.log(''); - console.log(` ${V('@comment')} ${D('[: description]')}`); + console.log(` ${V('@comment')} ${D('[-- "description"]')}`); console.log(D(' Free-form developer security note (no structural effect).')); - console.log(EX(' // @comment : TODO — add rate limiting before v2 launch')); + console.log(EX(' // @comment -- "TODO — add rate limiting before v2 launch"')); console.log(''); // ── SHIELD BLOCKS ── console.log(H(' ── Shield Blocks ───────────────────────────────────────────')); console.log(''); + console.log(` ${V('@shield')} ${D('[-- "reason"]')}`); + console.log(D(' Single-line marker for a security-sensitive code point.')); + console.log(EX(' // @shield -- "Crypto key derivation — do not refactor without review"')); + console.log(''); console.log(` ${V('@shield:begin')} ${D('/')} ${V('@shield:end')}`); console.log(D(' Wrap a code block to mark it as security-sensitive.')); console.log(D(' GuardLink will flag unannotated symbols inside the block.')); - console.log(EX(' // @shield:begin')); + console.log(EX(' // @shield:begin -- "Auth verification block"')); console.log(EX(' function verifyToken(token: string) { ... }')); console.log(EX(' // @shield:end')); console.log(''); + // ── EXTERNAL REFERENCES ── + console.log(H(' ── External References ─────────────────────────────────────')); + console.log(''); + console.log(D(' Append space-separated refs after severity on @threat and @exposes:')); + console.log(EX(' cwe:CWE-89 owasp:A03:2021 capec:CAPEC-66 attack:T1190')); + console.log(''); + console.log(D(' Example:')); + console.log(EX(' // @exposes api.auth to SQL Injection [high] cwe:CWE-89 owasp:A03:2021')); + console.log(''); + // ── TIPS ── console.log(H(' ── Tips ────────────────────────────────────────────────────')); console.log(''); + console.log(D(' • Descriptions use -- "quoted text" format (not : colon)')); + console.log(D(' • Severity uses brackets: [critical] [high] [medium] [low] or [P0]-[P3]')); console.log(D(' • Annotations work in any comment style: // /* # -- ')); console.log(D(' • Place annotations on the line ABOVE the code they describe')); console.log(D(' • Asset names are case-insensitive and normalized (spaces→underscores)')); console.log(D(' • Threat/control names can reference IDs with #id syntax')); + console.log(D(' • @flows uses -> arrow syntax (not "to")')); console.log(D(' • Run guardlink parse after adding annotations to update the threat model')); console.log(D(' • Run guardlink validate to check for syntax errors and dangling references')); console.log(D(' • Run guardlink annotate to have an AI agent add annotations automatically')); diff --git a/src/mcp/suggest.ts b/src/mcp/suggest.ts index c6d544c..12baa02 100644 --- a/src/mcp/suggest.ts +++ b/src/mcp/suggest.ts @@ -14,6 +14,7 @@ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" + * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" * @flows FilePath -> #suggest via readFileSync -- "File read path" * @flows #suggest -> Suggestions via suggestAnnotations -- "Suggestion output" * @comment -- "Skips node_modules and .guardlink directories" diff --git a/src/tui/commands.ts b/src/tui/commands.ts index 2b5b6cf..5fed1a6 100644 --- a/src/tui/commands.ts +++ b/src/tui/commands.ts @@ -110,6 +110,7 @@ export function cmdHelp(): void { ['/assets', 'Asset tree with threat/control counts'], ['/files', 'Annotated file tree with exposure counts'], ['/view ', 'Show all annotations in a file with code context'], + ['/unannotated', 'List source files with no annotations'], ['', ''], ['/threat-report ', 'AI threat report (stride|dread|pasta|attacker|rapid|general|custom)'], ['/threat-reports', 'List saved AI threat reports'], @@ -161,29 +162,29 @@ export function cmdGal(): void { console.log(D(' Annotations live in source code comments. GuardLink parses')); console.log(D(' them to build a live threat model from your codebase.')); console.log(''); - console.log(D(' Syntax: @verb subject [preposition object] [: description]')); + console.log(D(' Syntax: @verb subject [preposition object] [-- "description"]')); console.log(''); // ── DEFINITIONS ────────────────────────────────────────────────── console.log(H(' ── Definitions ─────────────────────────────────────────────')); console.log(''); - console.log(` ${V('@asset')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@asset')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Declare a named asset (component, service, data store).')); console.log(D(' Path uses dot notation for hierarchy.')); - console.log(EX(' // @asset api.auth.token_store : Stores JWT refresh tokens')); + console.log(EX(' // @asset api.auth.token_store -- "Stores JWT refresh tokens"')); console.log(EX(' // @asset db.users')); console.log(''); - console.log(` ${V('@threat')} ${K('')} ${D('[severity: critical|high|medium|low] [: description]')}`); - console.log(D(' Declare a named threat. Severity aliases: P0=critical P1=high P2=medium P3=low.')); - console.log(EX(' // @threat SQL Injection severity:high : Unsanitized input reaches DB')); - console.log(EX(' // @threat Token Theft severity:P0')); + console.log(` ${V('@threat')} ${K('')} ${D('(#id)')} ${D('[critical|high|medium|low]')} ${D('[ext-refs]')} ${D('[-- "description"]')}`); + console.log(D(' Declare a named threat. Severity in brackets: [P0]=[critical] [P1]=[high] [P2]=[medium] [P3]=[low].')); + console.log(EX(' // @threat SQL Injection (#sql-inj) [high] cwe:CWE-89 -- "Unsanitized input reaches DB"')); + console.log(EX(' // @threat Token Theft [P0]')); console.log(''); - console.log(` ${V('@control')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@control')} ${K('')} ${D('(#id)')} ${D('[-- "description"]')}`); console.log(D(' Declare a security control (mitigation mechanism).')); - console.log(EX(' // @control Input Validation : Sanitize all user-supplied strings')); + console.log(EX(' // @control Input Validation (#input-val) -- "Sanitize all user-supplied strings"')); console.log(EX(' // @control Rate Limiting')); console.log(''); @@ -191,103 +192,122 @@ export function cmdGal(): void { console.log(H(' ── Relationships ───────────────────────────────────────────')); console.log(''); - console.log(` ${V('@exposes')} ${K('')} ${D('to')} ${K('')} ${D('[severity: ...] [: description]')}`); + console.log(` ${V('@exposes')} ${K('')} ${D('to')} ${K('')} ${D('[severity]')} ${D('[ext-refs]')} ${D('[-- "description"]')}`); console.log(D(' Mark an asset as exposed to a threat at this code location.')); console.log(D(' This is the primary annotation — every exposure creates a finding.')); - console.log(EX(' // @exposes api.auth to SQL Injection severity:high')); - console.log(EX(' // @exposes db.users to Token Theft severity:critical : No token rotation')); + console.log(EX(' // @exposes api.auth to SQL Injection [high] cwe:CWE-89')); + console.log(EX(' // @exposes db.users to Token Theft [critical] -- "No token rotation"')); console.log(''); - console.log(` ${V('@mitigates')} ${K('')} ${D('against')} ${K('')} ${D('[with')} ${K('')}${D('] [: description]')}`); + console.log(` ${V('@mitigates')} ${K('')} ${D('against')} ${K('')} ${D('[using')} ${K('')}${D(']')} ${D('[-- "description"]')}`); console.log(D(' Mark that a control mitigates a threat on an asset.')); console.log(D(' Closes the exposure — removes it from open findings.')); - console.log(EX(' // @mitigates api.auth against SQL Injection with Input Validation')); - console.log(EX(' // @mitigates db.users against Token Theft : Rotation implemented in v2')); + console.log(D(' "using" is the primary keyword; "with" also accepted.')); + console.log(EX(' // @mitigates api.auth against SQL Injection using Input Validation')); + console.log(EX(' // @mitigates db.users against Token Theft -- "Rotation implemented in v2"')); console.log(''); - console.log(` ${V('@accepts')} ${K('')} ${D('on')} ${K('')} ${D('[: reason]')}`); + console.log(` ${V('@accepts')} ${K('')} ${D('on')} ${K('')} ${D('[-- "reason"]')}`); console.log(D(' Explicitly accept a risk. Removes it from open findings.')); console.log(D(' Use when the risk is known and intentionally not mitigated.')); - console.log(EX(' // @accepts Timing Attack on api.auth : Acceptable for current threat model')); + console.log(EX(' // @accepts Timing Attack on api.auth -- "Acceptable for current threat model"')); console.log(''); - console.log(` ${V('@transfers')} ${K('')} ${D('from')} ${K('')} ${D('to')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@transfers')} ${K('')} ${D('from')} ${K('')} ${D('to')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Transfer responsibility for a threat to another asset/team.')); - console.log(EX(' // @transfers DDoS from api.gateway to cdn.cloudflare : Handled by CDN layer')); + console.log(EX(' // @transfers DDoS from api.gateway to cdn.cloudflare -- "Handled by CDN layer"')); console.log(''); // ── DATA FLOWS ──────────────────────────────────────────────────── console.log(H(' ── Data Flows & Boundaries ─────────────────────────────────')); console.log(''); - console.log(` ${V('@flows')} ${K('')} ${D('to')} ${K('')} ${D('[via')} ${K('')}${D('] [: description]')}`); + console.log(` ${V('@flows')} ${K('')} ${D('->')} ${K('')} ${D('[via')} ${K('')}${D(']')} ${D('[-- "description"]')}`); console.log(D(' Document data movement between components.')); console.log(D(' Appears in the Data Flow Diagram.')); - console.log(EX(' // @flows api.auth to db.users via TLS 1.3')); - console.log(EX(' // @flows mobile.app to api.gateway via HTTPS : User credentials')); + console.log(EX(' // @flows api.auth -> db.users via TLS 1.3')); + console.log(EX(' // @flows mobile.app -> api.gateway via HTTPS -- "User credentials"')); console.log(''); - console.log(` ${V('@boundary')} ${K('')} ${D('and')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@boundary')} ${K('')} ${D('and')} ${K('')} ${D('(#id)')} ${D('[-- "description"]')}`); console.log(D(' Declare a trust boundary between two assets.')); console.log(D(' Groups assets in the Data Flow Diagram.')); - console.log(EX(' // @boundary internet and api.gateway : Public-facing edge')); - console.log(EX(' // @boundary api.gateway and db.users : Internal network boundary')); + console.log(D(' Alternate: @boundary between A and B or @boundary A | B')); + console.log(EX(' // @boundary internet and api.gateway (#edge) -- "Public-facing edge"')); + console.log(EX(' // @boundary api.gateway | db.users -- "Internal network boundary"')); console.log(''); // ── LIFECYCLE ───────────────────────────────────────────────────── console.log(H(' ── Lifecycle & Governance ──────────────────────────────────')); console.log(''); - console.log(` ${V('@handles')} ${K('')} ${D('on')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@handles')} ${K('')} ${D('on')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Declare data classification handled by an asset.')); console.log(D(' Classifications: pii phi financial secrets internal public')); - console.log(EX(' // @handles pii on db.users : Stores name, email, phone')); + console.log(EX(' // @handles pii on db.users -- "Stores name, email, phone"')); console.log(EX(' // @handles secrets on api.auth.token_store')); console.log(''); - console.log(` ${V('@owns')} ${K('')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@owns')} ${K('')} ${D('for')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Assign ownership of an asset to a team or person.')); - console.log(EX(' // @owns platform-team api.auth')); + console.log(EX(' // @owns platform-team for api.auth')); console.log(''); - console.log(` ${V('@validates')} ${K('')} ${D('on')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@validates')} ${K('')} ${D('for')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Assert that a control has been validated/tested on an asset.')); - console.log(EX(' // @validates Input Validation on api.auth : Pen-tested 2024-Q3')); + console.log(EX(' // @validates Input Validation for api.auth -- "Pen-tested 2024-Q3"')); console.log(''); - console.log(` ${V('@audit')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@audit')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Mark that this code path is an audit trail point.')); - console.log(EX(' // @audit db.users : All writes logged to audit_log table')); + console.log(EX(' // @audit db.users -- "All writes logged to audit_log table"')); console.log(''); - console.log(` ${V('@assumes')} ${K('')} ${D('[: description]')}`); + console.log(` ${V('@assumes')} ${K('')} ${D('[-- "description"]')}`); console.log(D(' Document a security assumption about an asset.')); - console.log(EX(' // @assumes api.gateway : Upstream WAF filters malformed requests')); + console.log(EX(' // @assumes api.gateway -- "Upstream WAF filters malformed requests"')); console.log(''); - console.log(` ${V('@comment')} ${D('[: description]')}`); + console.log(` ${V('@comment')} ${D('[-- "description"]')}`); console.log(D(' Free-form developer security note (no structural effect).')); - console.log(EX(' // @comment : TODO — add rate limiting before v2 launch')); + console.log(EX(' // @comment -- "TODO — add rate limiting before v2 launch"')); console.log(''); // ── SHIELD BLOCKS ───────────────────────────────────────────────── console.log(H(' ── Shield Blocks ───────────────────────────────────────────')); console.log(''); + console.log(` ${V('@shield')} ${D('[-- "reason"]')}`); + console.log(D(' Single-line marker for a security-sensitive code point.')); + console.log(EX(' // @shield -- "Crypto key derivation — do not refactor without review"')); + console.log(''); console.log(` ${V('@shield:begin')} ${D('/')} ${V('@shield:end')}`); console.log(D(' Wrap a code block to mark it as security-sensitive.')); console.log(D(' GuardLink will flag unannotated symbols inside the block.')); - console.log(EX(' // @shield:begin')); + console.log(EX(' // @shield:begin -- "Auth verification block"')); console.log(EX(' function verifyToken(token: string) { ... }')); console.log(EX(' // @shield:end')); console.log(''); + // ── EXTERNAL REFERENCES ───────────────────────────────────────── + console.log(H(' ── External References ─────────────────────────────────────')); + console.log(''); + console.log(D(' Append space-separated refs after severity on @threat and @exposes:')); + console.log(EX(' cwe:CWE-89 owasp:A03:2021 capec:CAPEC-66 attack:T1190')); + console.log(''); + console.log(D(' Example:')); + console.log(EX(' // @exposes api.auth to SQL Injection [high] cwe:CWE-89 owasp:A03:2021')); + console.log(''); + // ── TIPS ────────────────────────────────────────────────────────── console.log(H(' ── Tips ────────────────────────────────────────────────────')); console.log(''); + console.log(D(' • Descriptions use -- "quoted text" format (not : colon)')); + console.log(D(' • Severity uses brackets: [critical] [high] [medium] [low] or [P0]-[P3]')); console.log(D(' • Annotations work in any comment style: // /* # -- ')); console.log(D(' • Place annotations on the line ABOVE the code they describe')); console.log(D(' • Asset names are case-insensitive and normalized (spaces→underscores)')); console.log(D(' • Threat/control names can reference IDs with #id syntax')); + console.log(D(' • @flows uses -> arrow syntax (not "to")')); console.log(D(' • Run /parse after adding annotations to update the threat model')); console.log(D(' • Run /validate to check for syntax errors and dangling references')); console.log(D(' • Run /annotate to have an AI agent add annotations automatically')); diff --git a/threat-dashboard.html b/threat-dashboard.html new file mode 100644 index 0000000..b81e728 --- /dev/null +++ b/threat-dashboard.html @@ -0,0 +1,6986 @@ + + + + + +GuardLink — unknown Threat Model + + + + + + + + + +
+
+ +

unknown

+ Threat Model +
+
+
Assets 16
+
Open 15
+
Controls 12
+
Coverage 0%
+ +
+
+ +
+ + + + + +
+ + +
+
Executive Summary
+ + +
+
F
+
+ Critical Risk + 2 critical exposure(s) require immediate attention +
+
+ + +
+
16
Assets
+
15
Open Threats
+
45
Mitigated
+
12
Controls
+
68
Data Flows
+
9
Boundaries
+
0
Transfers
+
0
Validations
+
19
Audits
+
0
Assumptions
+
0
Ownership
+
18
Comments
+
16
Shields
+
+ + +
Threat Mitigation Coverage
+
+ 75% + 45 of 60 exposures mitigated +
+
+ + +
Severity Breakdown
+
+
+ Critical +
+ 2 +
+
+ High +
+ 25 +
+
+ Medium +
+ 24 +
+
+ Low +
+ 9 +
+ +
+ + + +
⚠ Open Threats (No Mitigation)
+ +
+
+ #prompt-injection + medium +
+
User prompt passed to agent CLI as argument
+
Asset: #agent-launcher
+
+
+
+ #dos + low +
+
No timeout on foreground spawn; agent controls duration
+
Asset: #agent-launcher
+
+
+
+ #prompt-injection + high +
+
User prompt concatenated into agent instruction text
+
Asset: #agent-launcher
+
+
+
+ #data-exposure + low +
+
Serializes full threat model and code snippets for LLM
+
Asset: #llm-client
+
+
+
+ #prompt-injection + medium +
+
User prompts sent to LLM API
+
Asset: #llm-client
+
+
+
+ #data-exposure + low +
+
Exposes threat model findings to SARIF consumers
+
Asset: #sarif
+
+
+
+ #cmd-injection + critical +
+
Agent launcher spawns child processes
+
Asset: #cli
+
+
+
+ #data-exposure + low +
+
Writes API key config to .guardlink/config.json
+
Asset: #init
+
+
+
+ #cmd-injection + high +
+
Accepts tool calls from external MCP clients
+
Asset: #mcp
+
+
+
+ #prompt-injection + medium +
+
annotate and threat_report tools pass user prompts to LLM
+
Asset: #mcp
+
+
+
+ #data-exposure + medium +
+
Resources expose full threat model to MCP clients
+
Asset: #mcp
+
+
+
+ #dos + low +
+
Large files loaded into memory for pattern scanning
+
Asset: #suggest
+
+
+
+ #arbitrary-write + high +
+
Writes modified content back to discovered files
+
Asset: #parser
+
+
+
+ #cmd-injection + high +
+
/annotate and /threat-report spawn child processes
+
Asset: #tui
+
+
+
+ #prompt-injection + medium +
+
Freeform chat sends user text to LLM
+
Asset: #tui
+
+ + + +
Data Flows
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SourceTargetMechanismLocation
EnvVars#agent-launcherprocess.envsrc/agents/config.ts:19
ConfigFile#agent-launcherreadFileSyncsrc/agents/config.ts:20
#agent-launcherConfigFilewriteFileSyncsrc/agents/config.ts:21
UserPrompt#agent-launcherlaunchAgentsrc/agents/launcher.ts:17
#agent-launcherAgentProcessspawnsrc/agents/launcher.ts:18
AgentProcess#agent-launcherstdoutsrc/agents/launcher.ts:19
UserPrompt#agent-launcherbuildAnnotatePromptsrc/agents/prompts.ts:10
ThreatModel#agent-launchermodelsrc/agents/prompts.ts:11
#agent-launcherAgentPromptreturnsrc/agents/prompts.ts:12
ThreatModel#llm-clientserializeModelsrc/analyze/index.ts:14
ProjectFiles#llm-clientreadFileSyncsrc/analyze/index.ts:15
#llm-clientReportFilewriteFileSyncsrc/analyze/index.ts:16
LLMConfig#llm-clientchatCompletionsrc/analyze/llm.ts:19
#llm-clientLLMProviderfetchsrc/analyze/llm.ts:20
LLMProvider#llm-clientresponsesrc/analyze/llm.ts:21
LLMToolCall#llm-clientcreateToolExecutorsrc/analyze/tools.ts:15
#llm-clientNVDfetchsrc/analyze/tools.ts:16
ProjectFiles#llm-clientreadFileSyncsrc/analyze/tools.ts:17
ThreatModel#sarifgenerateSarifsrc/analyzer/sarif.ts:18
#sarifSarifLogreturnsrc/analyzer/sarif.ts:19
UserArgs#cliprocess.argvsrc/cli/index.ts:33
#cliFileSystemwriteFilesrc/cli/index.ts:34
ThreatModel#dashboardcomputeStatssrc/dashboard/generate.ts:12
SourceFiles#dashboardreadFileSyncsrc/dashboard/generate.ts:13
#dashboardHTMLreturnsrc/dashboard/generate.ts:14
ThreatModel#dashboardgenerateDashboardHTMLsrc/dashboard/index.ts:6
GitRef#diffexecSyncsrc/diff/git.ts:12
#diffTempDirwriteFileSyncsrc/diff/git.ts:13
#diffThreatModelparseProjectsrc/diff/git.ts:14
GitRef#diffparseAtRefsrc/diff/index.ts:6
ProjectRoot#initdetectProjectsrc/init/detect.ts:7
ProjectRoot#initoptions.rootsrc/init/index.ts:14
#initAgentFileswriteFileSyncsrc/init/index.ts:15
#initConfigFilewriteFileSyncsrc/init/index.ts:16
MCPClient#mcpstdiosrc/mcp/index.ts:6
QueryString#mcplookupsrc/mcp/lookup.ts:18
MCPClient#mcptool_callsrc/mcp/server.ts:36
#mcpFileSystemwriteFilesrc/mcp/server.ts:37
#mcp#llm-clientgenerateThreatReportsrc/mcp/server.ts:38
#mcpMCPClientresourcesrc/mcp/server.ts:39
FilePath#suggestreadFileSyncsrc/mcp/suggest.ts:18
#suggestSuggestionssuggestAnnotationssrc/mcp/suggest.ts:19
ProjectRoot#parserfast-globsrc/parser/clear.ts:11
#parserSourceFileswriteFilesrc/parser/clear.ts:12
FilePath#parserreadFilesrc/parser/parse-file.ts:8
#parserAnnotationsparseStringsrc/parser/parse-file.ts:9
ProjectRoot#parserfast-globsrc/parser/parse-project.ts:9
#parserThreatModelassembleModelsrc/parser/parse-project.ts:10
ThreatModel#reportgenerateReportsrc/report/report.ts:8
#reportMarkdownreturnsrc/report/report.ts:9
ThreatModel#cligetReviewableExposuressrc/review/index.ts:13
#cliSourceFileswriteFilesrc/review/index.ts:14
UserArgs#tuiargssrc/tui/commands.ts:17
#tuiFileSystemwriteFilesrc/tui/commands.ts:18
#tui#agent-launcherlaunchAgentsrc/tui/commands.ts:19
#tui#llm-clientchatCompletionsrc/tui/commands.ts:20
ConfigFile#tuiloadProjectConfigsrc/tui/config.ts:9
#tuiConfigFilesaveProjectConfigsrc/tui/config.ts:10
UserInput#tuireadlinesrc/tui/index.ts:13
#tuiCommandsdispatchsrc/tui/index.ts:14
RawStdin#tuiprocess.stdinsrc/tui/input.ts:17
#tuiTerminalprocess.stdoutsrc/tui/input.ts:18
UserArgs#workspace-linklinkProjectsrc/workspace/link.ts:8
#workspace-linkAgentFilesupdateAgentWorkspaceContextsrc/workspace/link.ts:9
ReportJSON#merge-enginemergeReportssrc/workspace/merge.ts:10
#merge-engineMergedReportmergeReportssrc/workspace/merge.ts:11
GitRepo#report-metadataexecSyncsrc/workspace/metadata.ts:8
#report-metadataThreatModelpopulateMetadatasrc/workspace/metadata.ts:9
+
+ +
+
Threat Reports
+
+ + +
+
+
+ +
+
Threats & Exposures
+ +
Open Threats (15)
+

Exposed in code but not mitigated by any control.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AssetThreatSeverityDescriptionLocation
#agent-launcher#prompt-injectionmediumUser prompt passed to agent CLI as argumentsrc/agents/launcher.ts:13
#agent-launcher#doslowNo timeout on foreground spawn; agent controls durationsrc/agents/launcher.ts:15
#agent-launcher#prompt-injectionhighUser prompt concatenated into agent instruction textsrc/agents/prompts.ts:6
#llm-client#data-exposurelowSerializes full threat model and code snippets for LLMsrc/analyze/index.ts:12
#llm-client#prompt-injectionmediumUser prompts sent to LLM APIsrc/analyze/llm.ts:17
#sarif#data-exposurelowExposes threat model findings to SARIF consumerssrc/analyzer/sarif.ts:15
#cli#cmd-injectioncriticalAgent launcher spawns child processessrc/cli/index.ts:31
#init#data-exposurelowWrites API key config to .guardlink/config.jsonsrc/init/index.ts:12
#mcp#cmd-injectionhighAccepts tool calls from external MCP clientssrc/mcp/index.ts:4
#mcp#prompt-injectionmediumannotate and threat_report tools pass user prompts to LLMsrc/mcp/server.ts:30
#mcp#data-exposuremediumResources expose full threat model to MCP clientssrc/mcp/server.ts:34
#suggest#doslowLarge files loaded into memory for pattern scanningsrc/mcp/suggest.ts:16
#parser#arbitrary-writehighWrites modified content back to discovered filessrc/parser/clear.ts:7
#tui#cmd-injectionhigh/annotate and /threat-report spawn child processessrc/tui/commands.ts:11
#tui#prompt-injectionmediumFreeform chat sends user text to LLMsrc/tui/commands.ts:15
+ +
Mitigated Threats (45)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AssetThreatSeverityDescriptionLocation
#agent-launcher#api-key-exposurehighAPI keys loaded from env vars, files; stored in config.jsonsrc/agents/config.ts:13
#agent-launcher#path-traversalmediumConfig paths resolved from root and homedirsrc/agents/config.ts:15
#agent-launcher#arbitrary-writemediumsaveProjectConfig writes to .guardlink/config.jsonsrc/agents/config.ts:17
#agent-launcher#child-proc-injectioncriticalspawn/spawnSync execute external binariessrc/agents/launcher.ts:10
#agent-launcher#path-traversalmediumReads reference docs from root-relative pathssrc/agents/prompts.ts:8
#llm-client#path-traversalmediumbuildProjectContext reads files from root-relative pathssrc/analyze/index.ts:8
#llm-client#arbitrary-writemediumwriteFileSync saves threat reports to .guardlink/src/analyze/index.ts:10
#llm-client#ssrfmediumfetch() calls external LLM API endpointssrc/analyze/llm.ts:13
#llm-client#api-key-exposurehighAPI keys passed in Authorization headerssrc/analyze/llm.ts:15
#llm-client#ssrfmediumlookupCve fetches from NVD API with user-controlled CVE IDsrc/analyze/tools.ts:9
#llm-client#path-traversalmediumsearchCodebase reads files from project rootsrc/analyze/tools.ts:11
#llm-client#doslowsearchCodebase reads many files; bounded by maxResultssrc/analyze/tools.ts:13
#cli#path-traversalhighUser-supplied dir argument resolved via path.resolvesrc/cli/index.ts:25
#cli#arbitrary-writehighinit/report/sarif/dashboard write files to user-specified pathssrc/cli/index.ts:27
#cli#api-key-exposurehighAPI keys handled in config set/show commandssrc/cli/index.ts:29
#dashboard#xsshighGenerates HTML with user-controlled threat model datasrc/dashboard/generate.ts:8
#dashboard#path-traversalmediumreadFileSync reads code files for annotation contextsrc/dashboard/generate.ts:10
#dashboard#xsshighGenerates HTML with threat model datasrc/dashboard/index.ts:4
#diff#cmd-injectionhighexecSync runs git commands with ref argumentsrc/diff/git.ts:6
#diff#arbitrary-writemediumwriteFileSync creates files in temp directorysrc/diff/git.ts:8
#diff#path-traversalmediumgit show extracts files based on ls-tree outputsrc/diff/git.ts:10
#diff#cmd-injectionhighgit.ts uses execSync with ref argumentsrc/diff/index.ts:4
#init#path-traversallowReads package.json, pyproject.toml, etc. from rootsrc/init/detect.ts:5
#init#arbitrary-writehighCreates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc.src/init/index.ts:8
#init#path-traversalmediumReads/writes files based on root argumentsrc/init/index.ts:10
#mcp#redoslowRegex patterns applied to query stringssrc/mcp/lookup.ts:16
#mcp#path-traversalhighTool arguments include 'root' directory path from external clientsrc/mcp/server.ts:26
#mcp#arbitrary-writehighreport, dashboard, sarif tools write filessrc/mcp/server.ts:28
#mcp#api-key-exposuremediumthreat_report tool uses API keys from environmentsrc/mcp/server.ts:32
#suggest#path-traversalhighFile path from MCP client joined with rootsrc/mcp/suggest.ts:12
#suggest#redosmediumComplex regex patterns applied to source codesrc/mcp/suggest.ts:14
#parser#path-traversalhighGlob patterns determine which files are modifiedsrc/parser/clear.ts:8
#parser#path-traversalhighFile path from caller read via readFile; no validation heresrc/parser/parse-file.ts:5
#parser#dosmediumLarge files loaded entirely into memorysrc/parser/parse-file.ts:6
#parser#redosmediumComplex regex patterns applied to annotation textsrc/parser/parse-line.ts:5
#parser#path-traversalhighGlob patterns could escape root directorysrc/parser/parse-project.ts:5
#parser#dosmediumLarge projects with many files could exhaust memorysrc/parser/parse-project.ts:7
#cli#arbitrary-writemediumWrites @accepts/@audit annotations into source filessrc/review/index.ts:10
#tui#path-traversalhighFile paths from user args in /view, /sarif -osrc/tui/commands.ts:7
#tui#arbitrary-writehigh/report, /sarif, /dashboard write filessrc/tui/commands.ts:9
#tui#api-key-exposurehigh/model handles API key input and storagesrc/tui/commands.ts:13
#tui#api-key-exposurehighAPI keys loaded from and saved to config filessrc/tui/config.ts:7
#tui#path-traversalhighUser-supplied dir argument resolved via path.resolvesrc/tui/index.ts:9
#tui#api-key-exposuremediumAPI keys displayed in banner via resolveLLMConfigsrc/tui/index.ts:11
#tui#doslowRapid keystrokes could consume CPU in raw modesrc/tui/input.ts:15
+ + + + + + +
All Exposures (60)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusAssetThreatSeverityDescriptionLocation
Mitigated#agent-launcher#api-key-exposurehighAPI keys loaded from env vars, files; stored in config.jsonsrc/agents/config.ts:13
Mitigated#agent-launcher#path-traversalmediumConfig paths resolved from root and homedirsrc/agents/config.ts:15
Mitigated#agent-launcher#arbitrary-writemediumsaveProjectConfig writes to .guardlink/config.jsonsrc/agents/config.ts:17
Mitigated#agent-launcher#child-proc-injectioncriticalspawn/spawnSync execute external binariessrc/agents/launcher.ts:10
Open#agent-launcher#prompt-injectionmediumUser prompt passed to agent CLI as argumentsrc/agents/launcher.ts:13
Open#agent-launcher#doslowNo timeout on foreground spawn; agent controls durationsrc/agents/launcher.ts:15
Open#agent-launcher#prompt-injectionhighUser prompt concatenated into agent instruction textsrc/agents/prompts.ts:6
Mitigated#agent-launcher#path-traversalmediumReads reference docs from root-relative pathssrc/agents/prompts.ts:8
Mitigated#llm-client#path-traversalmediumbuildProjectContext reads files from root-relative pathssrc/analyze/index.ts:8
Mitigated#llm-client#arbitrary-writemediumwriteFileSync saves threat reports to .guardlink/src/analyze/index.ts:10
Open#llm-client#data-exposurelowSerializes full threat model and code snippets for LLMsrc/analyze/index.ts:12
Mitigated#llm-client#ssrfmediumfetch() calls external LLM API endpointssrc/analyze/llm.ts:13
Mitigated#llm-client#api-key-exposurehighAPI keys passed in Authorization headerssrc/analyze/llm.ts:15
Open#llm-client#prompt-injectionmediumUser prompts sent to LLM APIsrc/analyze/llm.ts:17
Mitigated#llm-client#ssrfmediumlookupCve fetches from NVD API with user-controlled CVE IDsrc/analyze/tools.ts:9
Mitigated#llm-client#path-traversalmediumsearchCodebase reads files from project rootsrc/analyze/tools.ts:11
Mitigated#llm-client#doslowsearchCodebase reads many files; bounded by maxResultssrc/analyze/tools.ts:13
Open#sarif#data-exposurelowExposes threat model findings to SARIF consumerssrc/analyzer/sarif.ts:15
Mitigated#cli#path-traversalhighUser-supplied dir argument resolved via path.resolvesrc/cli/index.ts:25
Mitigated#cli#arbitrary-writehighinit/report/sarif/dashboard write files to user-specified pathssrc/cli/index.ts:27
Mitigated#cli#api-key-exposurehighAPI keys handled in config set/show commandssrc/cli/index.ts:29
Open#cli#cmd-injectioncriticalAgent launcher spawns child processessrc/cli/index.ts:31
Mitigated#dashboard#xsshighGenerates HTML with user-controlled threat model datasrc/dashboard/generate.ts:8
Mitigated#dashboard#path-traversalmediumreadFileSync reads code files for annotation contextsrc/dashboard/generate.ts:10
Mitigated#dashboard#xsshighGenerates HTML with threat model datasrc/dashboard/index.ts:4
Mitigated#diff#cmd-injectionhighexecSync runs git commands with ref argumentsrc/diff/git.ts:6
Mitigated#diff#arbitrary-writemediumwriteFileSync creates files in temp directorysrc/diff/git.ts:8
Mitigated#diff#path-traversalmediumgit show extracts files based on ls-tree outputsrc/diff/git.ts:10
Mitigated#diff#cmd-injectionhighgit.ts uses execSync with ref argumentsrc/diff/index.ts:4
Mitigated#init#path-traversallowReads package.json, pyproject.toml, etc. from rootsrc/init/detect.ts:5
Mitigated#init#arbitrary-writehighCreates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc.src/init/index.ts:8
Mitigated#init#path-traversalmediumReads/writes files based on root argumentsrc/init/index.ts:10
Open#init#data-exposurelowWrites API key config to .guardlink/config.jsonsrc/init/index.ts:12
Open#mcp#cmd-injectionhighAccepts tool calls from external MCP clientssrc/mcp/index.ts:4
Mitigated#mcp#redoslowRegex patterns applied to query stringssrc/mcp/lookup.ts:16
Mitigated#mcp#path-traversalhighTool arguments include 'root' directory path from external clientsrc/mcp/server.ts:26
Mitigated#mcp#arbitrary-writehighreport, dashboard, sarif tools write filessrc/mcp/server.ts:28
Open#mcp#prompt-injectionmediumannotate and threat_report tools pass user prompts to LLMsrc/mcp/server.ts:30
Mitigated#mcp#api-key-exposuremediumthreat_report tool uses API keys from environmentsrc/mcp/server.ts:32
Open#mcp#data-exposuremediumResources expose full threat model to MCP clientssrc/mcp/server.ts:34
Mitigated#suggest#path-traversalhighFile path from MCP client joined with rootsrc/mcp/suggest.ts:12
Mitigated#suggest#redosmediumComplex regex patterns applied to source codesrc/mcp/suggest.ts:14
Open#suggest#doslowLarge files loaded into memory for pattern scanningsrc/mcp/suggest.ts:16
Open#parser#arbitrary-writehighWrites modified content back to discovered filessrc/parser/clear.ts:7
Mitigated#parser#path-traversalhighGlob patterns determine which files are modifiedsrc/parser/clear.ts:8
Mitigated#parser#path-traversalhighFile path from caller read via readFile; no validation heresrc/parser/parse-file.ts:5
Mitigated#parser#dosmediumLarge files loaded entirely into memorysrc/parser/parse-file.ts:6
Mitigated#parser#redosmediumComplex regex patterns applied to annotation textsrc/parser/parse-line.ts:5
Mitigated#parser#path-traversalhighGlob patterns could escape root directorysrc/parser/parse-project.ts:5
Mitigated#parser#dosmediumLarge projects with many files could exhaust memorysrc/parser/parse-project.ts:7
Mitigated#cli#arbitrary-writemediumWrites @accepts/@audit annotations into source filessrc/review/index.ts:10
Mitigated#tui#path-traversalhighFile paths from user args in /view, /sarif -osrc/tui/commands.ts:7
Mitigated#tui#arbitrary-writehigh/report, /sarif, /dashboard write filessrc/tui/commands.ts:9
Open#tui#cmd-injectionhigh/annotate and /threat-report spawn child processessrc/tui/commands.ts:11
Mitigated#tui#api-key-exposurehigh/model handles API key input and storagesrc/tui/commands.ts:13
Open#tui#prompt-injectionmediumFreeform chat sends user text to LLMsrc/tui/commands.ts:15
Mitigated#tui#api-key-exposurehighAPI keys loaded from and saved to config filessrc/tui/config.ts:7
Mitigated#tui#path-traversalhighUser-supplied dir argument resolved via path.resolvesrc/tui/index.ts:9
Mitigated#tui#api-key-exposuremediumAPI keys displayed in banner via resolveLLMConfigsrc/tui/index.ts:11
Mitigated#tui#doslowRapid keystrokes could consume CPU in raw modesrc/tui/input.ts:15
+
+ +
+
Diagrams
+

Interactive diagrams from annotations. Scroll to zoom, drag to pan, double-click to reset.

+
+ +
+
+graph LR
+  subgraph TZ0["🧱 #agent-launcher"]
+    _agent_launcher["🔷 #agent-launcher [SECRETS, INTERNAL]"]
+  end
+  subgraph TZ1["🧱 AgentProcess"]
+  end
+  subgraph TZ2["🧱 #llm-client"]
+    _llm_client["🔷 #llm-client [INTERNAL, SECRETS]"]
+  end
+  subgraph TZ3["🧱 LLMProvider"]
+  end
+  subgraph TZ4["🧱 NVD"]
+  end
+  subgraph TZ5["🧱 #cli"]
+    _cli["🔷 #cli [SECRETS, INTERNAL]"]
+  end
+  subgraph TZ6["🧱 UserInput"]
+  end
+  subgraph TZ7["🧱 #diff"]
+    _diff["🔷 #diff"]
+  end
+  subgraph TZ8["🧱 GitRepo"]
+  end
+  subgraph TZ9["🧱 #mcp"]
+    _mcp["🔷 #mcp [INTERNAL]"]
+  end
+  subgraph TZ10["🧱 MCPClient"]
+  end
+  subgraph TZ11["🧱 #parser"]
+    _parser["🔷 #parser [INTERNAL]"]
+  end
+  subgraph TZ12["🧱 FileSystem"]
+  end
+  subgraph TZ13["🧱 #tui"]
+    _tui["🔷 #tui [SECRETS, SECRETS, SECRETS]"]
+  end
+  _sarif["🔷 #sarif"]
+  _dashboard["🔷 #dashboard [INTERNAL]"]
+  _init["🔷 #init [INTERNAL]"]
+  _suggest["🔷 #suggest"]
+  _merge_engine["🔷 #merge-engine"]
+  _workspace_config["🔷 #workspace-config"]
+  _api_key_exposure["🟠 API_Key_Exposure (cwe:CWE-798)"]:::threat
+  _path_traversal["🟠 Path_Traversal (cwe:CWE-22)"]:::threat
+  _arbitrary_write["🟠 Arbitrary_File_Write (cwe:CWE-73)"]:::threat
+  _child_proc_injection["🔴 Child_Process_Injection (cwe:CWE-78)"]:::threat
+  _prompt_injection["🟠 Prompt_Injection (cwe:CWE-77)"]:::threat
+  _dos["🟡 Denial_of_Service (cwe:CWE-400)"]:::threat
+  _data_exposure["🟡 Sensitive_Data_Exposure (cwe:CWE-200)"]:::threat
+  _ssrf["🟡 Server_Side_Request_Forgery (cwe:CWE-918)"]:::threat
+  _cmd_injection["🔴 Command_Injection (cwe:CWE-78)"]:::threat
+  _xss["🟠 Cross_Site_Scripting (cwe:CWE-79)"]:::threat
+  _redos["🟡 ReDoS (cwe:CWE-1333)"]:::threat
+  _tag_collision["🟡 Tag_Collision"]:::threat
+  _config_tamper["🟡 Config_Tampering (cwe:CWE-15)"]:::threat
+  _key_redaction["🛡️ key-redaction"]:::control
+  _path_validation["🛡️ path-validation"]:::control
+  _param_commands["🛡️ param-commands"]:::control
+  _config_validation["🛡️ config-validation"]:::control
+  _input_sanitize["🛡️ input-sanitize"]:::control
+  _glob_filtering["🛡️ glob-filtering"]:::control
+  _resource_limits["🛡️ resource-limits"]:::control
+  _output_encoding["🛡️ output-encoding"]:::control
+  _regex_anchoring["🛡️ regex-anchoring"]:::control
+  _prefix_ownership["🛡️ prefix-ownership"]:::control
+  _yaml_validation["🛡️ yaml-validation"]:::control
+  _agent_launcher -. exposed .-> _api_key_exposure
+  _agent_launcher -. exposed .-> _path_traversal
+  _agent_launcher -. exposed .-> _arbitrary_write
+  _agent_launcher -. exposed .-> _child_proc_injection
+  _agent_launcher -. exposed .-> _prompt_injection
+  _agent_launcher -. exposed .-> _dos
+  _llm_client -. exposed .-> _path_traversal
+  _llm_client -. exposed .-> _arbitrary_write
+  _llm_client -. exposed .-> _data_exposure
+  _llm_client -. exposed .-> _ssrf
+  _llm_client -. exposed .-> _api_key_exposure
+  _llm_client -. exposed .-> _prompt_injection
+  _llm_client -. exposed .-> _dos
+  _sarif -. exposed .-> _data_exposure
+  _cli -. exposed .-> _path_traversal
+  _cli -. exposed .-> _arbitrary_write
+  _cli -. exposed .-> _api_key_exposure
+  _cli -. exposed .-> _cmd_injection
+  _dashboard -. exposed .-> _xss
+  _dashboard -. exposed .-> _path_traversal
+  _diff -. exposed .-> _cmd_injection
+  _diff -. exposed .-> _arbitrary_write
+  _diff -. exposed .-> _path_traversal
+  _init -. exposed .-> _path_traversal
+  _init -. exposed .-> _arbitrary_write
+  _init -. exposed .-> _data_exposure
+  _mcp -. exposed .-> _cmd_injection
+  _mcp -. exposed .-> _redos
+  _mcp -. exposed .-> _path_traversal
+  _mcp -. exposed .-> _arbitrary_write
+  _mcp -. exposed .-> _prompt_injection
+  _mcp -. exposed .-> _api_key_exposure
+  _mcp -. exposed .-> _data_exposure
+  _suggest -. exposed .-> _path_traversal
+  _suggest -. exposed .-> _redos
+  _suggest -. exposed .-> _dos
+  _parser -. exposed .-> _arbitrary_write
+  _parser -. exposed .-> _path_traversal
+  _parser -. exposed .-> _dos
+  _parser -. exposed .-> _redos
+  _tui -. exposed .-> _path_traversal
+  _tui -. exposed .-> _arbitrary_write
+  _tui -. exposed .-> _cmd_injection
+  _tui -. exposed .-> _api_key_exposure
+  _tui -. exposed .-> _prompt_injection
+  _tui -. exposed .-> _dos
+  _key_redaction -- mitigates --> _api_key_exposure
+  _key_redaction -.- _agent_launcher
+  _path_validation -- mitigates --> _path_traversal
+  _path_validation -.- _agent_launcher
+  _path_validation -- mitigates --> _arbitrary_write
+  _param_commands -- mitigates --> _child_proc_injection
+  _param_commands -.- _agent_launcher
+  _param_commands -- mitigates --> _cmd_injection
+  _path_validation -.- _llm_client
+  _config_validation -- mitigates --> _ssrf
+  _config_validation -.- _llm_client
+  _key_redaction -.- _llm_client
+  _input_sanitize -- mitigates --> _ssrf
+  _input_sanitize -.- _llm_client
+  _glob_filtering -- mitigates --> _path_traversal
+  _glob_filtering -.- _llm_client
+  _resource_limits -- mitigates --> _dos
+  _resource_limits -.- _llm_client
+  _path_validation -.- _cli
+  _key_redaction -.- _cli
+  _output_encoding -- mitigates --> _xss
+  _output_encoding -.- _dashboard
+  _path_validation -.- _dashboard
+  _input_sanitize -- mitigates --> _cmd_injection
+  _input_sanitize -.- _diff
+  _path_validation -.- _diff
+  _glob_filtering -.- _diff
+  _path_validation -.- _init
+  _regex_anchoring -- mitigates --> _redos
+  _regex_anchoring -.- _mcp
+  _path_validation -.- _mcp
+  _key_redaction -.- _mcp
+  _path_validation -.- _suggest
+  _regex_anchoring -.- _suggest
+  _glob_filtering -.- _parser
+  _regex_anchoring -.- _parser
+  _resource_limits -.- _parser
+  _path_validation -.- _tui
+  _key_redaction -.- _tui
+  _resource_limits -.- _tui
+  _prefix_ownership -- mitigates --> _tag_collision
+  _prefix_ownership -.- _merge_engine
+  _yaml_validation -- mitigates --> _config_tamper
+  _yaml_validation -.- _workspace_config
+  _mcp -- "📡 generateThreatReport" --> _llm_client
+  _tui -- "📡 launchAgent" --> _agent_launcher
+  _tui -- "📡 chatCompletion" --> _llm_client
+  classDef threat fill:#991b1b,stroke:#ef4444,color:#fecaca
+  classDef control fill:#065f46,stroke:#10b981,color:#a7f3d0
+
+
+%%{init: {"flowchart": {"nodeSpacing": 43, "rankSpacing": 59, "curve": "basis"}}}%%
+graph LR
+  subgraph Z0["🧱 Trust Zone · #agent-launcher"]
+    _agent_launcher["🧩 #agent-launcher"]
+  end
+  subgraph Z1["🧱 Trust Zone · AgentProcess"]
+    AgentProcess["🧩 AgentProcess"]
+  end
+  subgraph Z2["🧱 Trust Zone · #llm-client"]
+    _llm_client["👤 #llm-client"]
+  end
+  subgraph Z3["🧱 Trust Zone · LLMProvider"]
+    LLMProvider["🧩 LLMProvider"]
+  end
+  subgraph Z4["🧱 Trust Zone · NVD"]
+    NVD["🧩 NVD"]
+  end
+  subgraph Z5["🧱 Trust Zone · #cli"]
+    _cli["🧩 #cli"]
+  end
+  subgraph Z6["🧱 Trust Zone · UserInput"]
+    UserInput["👤 UserInput"]
+  end
+  subgraph Z7["🧱 Trust Zone · #diff"]
+    _diff["🧩 #diff"]
+  end
+  subgraph Z8["🧱 Trust Zone · GitRepo"]
+    GitRepo["🧩 GitRepo"]
+  end
+  subgraph Z9["🧱 Trust Zone · #mcp"]
+    _mcp["🧩 #mcp"]
+  end
+  subgraph Z10["🧱 Trust Zone · MCPClient"]
+    MCPClient["👤 MCPClient"]
+  end
+  subgraph Z11["🧱 Trust Zone · #parser"]
+    _parser["🧩 #parser"]
+  end
+  subgraph Z12["🧱 Trust Zone · FileSystem"]
+    FileSystem["🧩 FileSystem"]
+  end
+  subgraph Z13["🧱 Trust Zone · #tui"]
+    _tui["👤 #tui"]
+  end
+  _agent_launcher -.-|🧱 Trust boundary at process spawn| AgentProcess
+  _llm_client -.-|🧱 Trust boundary at external API call| LLMProvider
+  _llm_client -.-|🧱 Trust boundary at external API| NVD
+  _cli -.-|🧱 Trust boundary at CLI argument parsing| UserInput
+  _diff -.-|🧱 Trust boundary at git command execution| GitRepo
+  _mcp -.-|🧱 Trust boundary at MCP protocol| MCPClient
+  _mcp -.-|🧱 Trust boundary at tool argument parsing| MCPClient
+  _parser -.-|🧱 Trust boundary between parser and disk I/O| FileSystem
+  _tui -.-|🧱 Trust boundary at interactive input| UserInput
+  EnvVars["🧩 EnvVars"]
+  ConfigFile["🧩 ConfigFile"]
+  UserPrompt["👤 UserPrompt"]
+  ThreatModel["🧩 ThreatModel"]
+  AgentPrompt["🧩 AgentPrompt"]
+  ProjectFiles["🧩 ProjectFiles"]
+  ReportFile["🧩 ReportFile"]
+  LLMConfig["🧩 LLMConfig"]
+  LLMToolCall["🧩 LLMToolCall"]
+  _sarif["🧩 #sarif"]
+  SarifLog["🧩 SarifLog"]
+  UserArgs["👤 UserArgs"]
+  _dashboard["🧩 #dashboard · internal"]
+  SourceFiles["🧩 SourceFiles"]
+  HTML["🧩 HTML"]
+  GitRef["🧩 GitRef"]
+  TempDir["🧩 TempDir"]
+  ProjectRoot["🧩 ProjectRoot"]
+  _init["🧩 #init · internal"]
+  AgentFiles["🧩 AgentFiles"]
+  QueryString["🧩 QueryString"]
+  FilePath["🧩 FilePath"]
+  _suggest["🧩 #suggest"]
+  Suggestions["🧩 Suggestions"]
+  Annotations["🧩 Annotations"]
+  _report["🧩 #report"]
+  Markdown["🧩 Markdown"]
+  Commands["🧩 Commands"]
+  RawStdin["🧩 RawStdin"]
+  Terminal["🧩 Terminal"]
+  _workspace_link["🧩 #workspace-link"]
+  ReportJSON["🧩 ReportJSON"]
+  _merge_engine["🧩 #merge-engine"]
+  MergedReport["🧩 MergedReport"]
+  _report_metadata["🧩 #report-metadata"]
+  EnvVars -- "📡 process.env" --> _agent_launcher
+  ConfigFile -- "🗄️ readFileSync" --> _agent_launcher
+  _agent_launcher -- "🗄️ writeFileSync" --> ConfigFile
+  UserPrompt -- "📡 launchAgent" --> _agent_launcher
+  _agent_launcher -- "📡 spawn" --> AgentProcess
+  AgentProcess -- "📡 stdout" --> _agent_launcher
+  UserPrompt -- "📡 buildAnnotatePrompt" --> _agent_launcher
+  ThreatModel -- "📡 model" --> _agent_launcher
+  _agent_launcher -- "📡 return" --> AgentPrompt
+  ThreatModel -- "📡 serializeModel" --> _llm_client
+  ProjectFiles -- "🗄️ readFileSync" --> _llm_client
+  _llm_client -- "🗄️ writeFileSync" --> ReportFile
+  LLMConfig -- "📡 chatCompletion" --> _llm_client
+  _llm_client -- "📡 fetch" --> LLMProvider
+  LLMProvider -- "📡 response" --> _llm_client
+  LLMToolCall -- "📡 createToolExecutor" --> _llm_client
+  _llm_client -- "📡 fetch" --> NVD
+  ProjectFiles -- "🗄️ readFileSync" --> _llm_client
+  ThreatModel -- "📡 generateSarif" --> _sarif
+  _sarif -- "📡 return" --> SarifLog
+  UserArgs -- "📡 process.argv" --> _cli
+  _cli -- "🗄️ writeFile" --> FileSystem
+  ThreatModel -- "📡 computeStats" --> _dashboard
+  SourceFiles -- "🗄️ readFileSync" --> _dashboard
+  _dashboard -- "📡 return" --> HTML
+  ThreatModel -- "📡 generateDashboardHTML" --> _dashboard
+  GitRef -- "📡 execSync" --> _diff
+  _diff -- "🗄️ writeFileSync" --> TempDir
+  _diff -- "📡 parseProject" --> ThreatModel
+  GitRef -- "📡 parseAtRef" --> _diff
+  ProjectRoot -- "📡 detectProject" --> _init
+  ProjectRoot -- "📡 options.root" --> _init
+  _init -- "🗄️ writeFileSync" --> AgentFiles
+  _init -- "🗄️ writeFileSync" --> ConfigFile
+  MCPClient -- "📡 stdio" --> _mcp
+  QueryString -- "📡 lookup" --> _mcp
+  MCPClient -- "📡 tool_call" --> _mcp
+  _mcp -- "🗄️ writeFile" --> FileSystem
+  _mcp -- "📡 generateThreatReport" --> _llm_client
+  _mcp -- "📡 resource" --> MCPClient
+  FilePath -- "🗄️ readFileSync" --> _suggest
+  _suggest -- "📡 suggestAnnotations" --> Suggestions
+  ProjectRoot -- "📡 fast-glob" --> _parser
+  _parser -- "🗄️ writeFile" --> SourceFiles
+  FilePath -- "🗄️ readFile" --> _parser
+  _parser -- "📡 parseString" --> Annotations
+  ProjectRoot -- "📡 fast-glob" --> _parser
+  _parser -- "📡 assembleModel" --> ThreatModel
+  ThreatModel -- "📡 generateReport" --> _report
+  _report -- "📡 return" --> Markdown
+  ThreatModel -- "📡 getReviewableExposures" --> _cli
+  _cli -- "🗄️ writeFile" --> SourceFiles
+  UserArgs -- "📡 args" --> _tui
+  _tui -- "🗄️ writeFile" --> FileSystem
+  _tui -- "📡 launchAgent" --> _agent_launcher
+  _tui -- "📡 chatCompletion" --> _llm_client
+  ConfigFile -- "📡 loadProjectConfig" --> _tui
+  _tui -- "📡 saveProjectConfig" --> ConfigFile
+  UserInput -- "📡 readline" --> _tui
+  _tui -- "📡 dispatch" --> Commands
+  RawStdin -- "📡 process.stdin" --> _tui
+  _tui -- "📡 process.stdout" --> Terminal
+  UserArgs -- "📡 linkProject" --> _workspace_link
+  _workspace_link -- "📡 updateAgentWorkspaceContext" --> AgentFiles
+  ReportJSON -- "📡 mergeReports" --> _merge_engine
+  _merge_engine -- "📡 mergeReports" --> MergedReport
+  GitRepo -- "📡 execSync" --> _report_metadata
+  _report_metadata -- "📡 populateMetadata" --> ThreatModel
+
+
+graph LR
+  subgraph A__agent_launcher["#agent-launcher"]
+    direction TB
+    E0["✅ child-proc-injection"]:::sev_crit
+    E1["✅ api-key-exposure"]:::sev_high
+    E2["⚠️ prompt-injection x2"]:::sev_high
+    E3["✅ path-traversal x2"]:::sev_med
+    E4["✅ arbitrary-write"]:::sev_med
+    E5["⚠️ dos"]:::sev_low
+  end
+  subgraph A__llm_client["#llm-client"]
+    direction TB
+    E6["✅ api-key-exposure"]:::sev_high
+    E7["✅ path-traversal x2"]:::sev_med
+    E8["✅ arbitrary-write"]:::sev_med
+    E9["✅ ssrf x2"]:::sev_med
+    E10["⚠️ prompt-injection"]:::sev_med
+    E11["⚠️ data-exposure"]:::sev_low
+    E12["✅ dos"]:::sev_low
+  end
+  subgraph A__sarif["#sarif"]
+    direction TB
+    E13["⚠️ data-exposure"]:::sev_low
+  end
+  subgraph A__cli["#cli"]
+    direction TB
+    E14["⚠️ cmd-injection"]:::sev_crit
+    E15["✅ path-traversal"]:::sev_high
+    E16["✅ arbitrary-write x2"]:::sev_high
+    E17["✅ api-key-exposure"]:::sev_high
+  end
+  subgraph A__dashboard["#dashboard"]
+    direction TB
+    E18["✅ xss x2"]:::sev_high
+    E19["✅ path-traversal"]:::sev_med
+  end
+  subgraph A__diff["#diff"]
+    direction TB
+    E20["✅ cmd-injection x2"]:::sev_high
+    E21["✅ arbitrary-write"]:::sev_med
+    E22["✅ path-traversal"]:::sev_med
+  end
+  subgraph A__init["#init"]
+    direction TB
+    E23["✅ arbitrary-write"]:::sev_high
+    E24["✅ path-traversal x2"]:::sev_med
+    E25["⚠️ data-exposure"]:::sev_low
+  end
+  subgraph A__mcp["#mcp"]
+    direction TB
+    E26["⚠️ cmd-injection"]:::sev_high
+    E27["✅ path-traversal"]:::sev_high
+    E28["✅ arbitrary-write"]:::sev_high
+    E29["⚠️ prompt-injection"]:::sev_med
+    E30["✅ api-key-exposure"]:::sev_med
+    E31["⚠️ data-exposure"]:::sev_med
+    E32["✅ redos"]:::sev_low
+  end
+  subgraph A__suggest["#suggest"]
+    direction TB
+    E33["✅ path-traversal"]:::sev_high
+    E34["✅ redos"]:::sev_med
+    E35["⚠️ dos"]:::sev_low
+  end
+  subgraph A__parser["#parser"]
+    direction TB
+    E36["⚠️ arbitrary-write"]:::sev_high
+    E37["✅ path-traversal x3"]:::sev_high
+    E38["✅ dos x2"]:::sev_med
+    E39["✅ redos"]:::sev_med
+  end
+  subgraph A__tui["#tui"]
+    direction TB
+    E40["✅ path-traversal x2"]:::sev_high
+    E41["✅ arbitrary-write"]:::sev_high
+    E42["⚠️ cmd-injection"]:::sev_high
+    E43["✅ api-key-exposure x3"]:::sev_high
+    E44["⚠️ prompt-injection"]:::sev_med
+    E45["✅ dos"]:::sev_low
+  end
+  classDef sev_crit fill:#7f1d1d,stroke:#ef4444,color:#fecaca
+  classDef sev_high fill:#7c2d12,stroke:#f97316,color:#fed7aa
+  classDef sev_med fill:#78350f,stroke:#f59e0b,color:#fef3c7
+  classDef sev_low fill:#1e3a5f,stroke:#3b82f6,color:#bfdbfe
+  classDef sev_unset fill:#374151,stroke:#9ca3af,color:#e5e7eb
+
+
+ +
+
</> Code & Annotations
+

+ Every file with GuardLink annotations. Click any annotation to see details. +

+ +
+
+ .guardlink/definitions.ts + + 37 + + +
+
+ +
+
+ L15 + asset + GuardLink.Parser +
+
Reads source files from disk, extracts security annotations using regex patterns
+
10 │ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11 │ 12 │ // ─── ASSETS ─────────────────────────────────────────────────────────── 13 │ // Components that process data, handle user input, or interact with external systems 14 │ 15 │ // @asset GuardLink.Parser (#parser) -- "Reads source files from disk, extracts security annotations using regex patterns" 16 │ // @asset GuardLink.CLI (#cli) -- "Command-line interface, handles user arguments, invokes subcommands" 17 │ // @asset GuardLink.TUI (#tui) -- "Interactive terminal interface with readline input and command dispatch" 18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data"
+
+
+
+ L16 + asset + GuardLink.CLI +
+
Command-line interface, handles user arguments, invokes subcommands
+
11 │ 12 │ // ─── ASSETS ─────────────────────────────────────────────────────────── 13 │ // Components that process data, handle user input, or interact with external systems 14 │ 15 │ // @asset GuardLink.Parser (#parser) -- "Reads source files from disk, extracts security annotations using regex patterns" 16 │ // @asset GuardLink.CLI (#cli) -- "Command-line interface, handles user arguments, invokes subcommands" 17 │ // @asset GuardLink.TUI (#tui) -- "Interactive terminal interface with readline input and command dispatch" 18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk"
+
+
+
+ L17 + asset + GuardLink.TUI +
+
Interactive terminal interface with readline input and command dispatch
+
12 │ // ─── ASSETS ─────────────────────────────────────────────────────────── 13 │ // Components that process data, handle user input, or interact with external systems 14 │ 15 │ // @asset GuardLink.Parser (#parser) -- "Reads source files from disk, extracts security annotations using regex patterns" 16 │ // @asset GuardLink.CLI (#cli) -- "Command-line interface, handles user arguments, invokes subcommands" 17 │ // @asset GuardLink.TUI (#tui) -- "Interactive terminal interface with readline input and command dispatch" 18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)"
+
+
+
+ L18 + asset + GuardLink.MCP +
+
Model Context Protocol server, accepts tool calls from AI agents over stdio
+
13 │ // Components that process data, handle user input, or interact with external systems 14 │ 15 │ // @asset GuardLink.Parser (#parser) -- "Reads source files from disk, extracts security annotations using regex patterns" 16 │ // @asset GuardLink.CLI (#cli) -- "Command-line interface, handles user arguments, invokes subcommands" 17 │ // @asset GuardLink.TUI (#tui) -- "Interactive terminal interface with readline input and command dispatch" 18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands"
+
+
+
+ L19 + asset + GuardLink.LLM_Client +
+
Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)
+
14 │ 15 │ // @asset GuardLink.Parser (#parser) -- "Reads source files from disk, extracts security annotations using regex patterns" 16 │ // @asset GuardLink.CLI (#cli) -- "Command-line interface, handles user arguments, invokes subcommands" 17 │ // @asset GuardLink.TUI (#tui) -- "Interactive terminal interface with readline input and command dispatch" 18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands" 24 │ // @asset GuardLink.Report (#report) -- "Generates markdown threat model reports with Mermaid diagrams"
+
+
+
+ L20 + asset + GuardLink.Dashboard +
+
Generates interactive HTML threat model dashboard from ThreatModel data
+
15 │ // @asset GuardLink.Parser (#parser) -- "Reads source files from disk, extracts security annotations using regex patterns" 16 │ // @asset GuardLink.CLI (#cli) -- "Command-line interface, handles user arguments, invokes subcommands" 17 │ // @asset GuardLink.TUI (#tui) -- "Interactive terminal interface with readline input and command dispatch" 18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands" 24 │ // @asset GuardLink.Report (#report) -- "Generates markdown threat model reports with Mermaid diagrams" 25 │ // @asset GuardLink.SARIF (#sarif) -- "Exports findings as SARIF 2.1.0 JSON for security tooling"
+
+
+
+ L21 + asset + GuardLink.Init +
+
Initializes projects, writes config files and agent instruction files to disk
+
16 │ // @asset GuardLink.CLI (#cli) -- "Command-line interface, handles user arguments, invokes subcommands" 17 │ // @asset GuardLink.TUI (#tui) -- "Interactive terminal interface with readline input and command dispatch" 18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands" 24 │ // @asset GuardLink.Report (#report) -- "Generates markdown threat model reports with Mermaid diagrams" 25 │ // @asset GuardLink.SARIF (#sarif) -- "Exports findings as SARIF 2.1.0 JSON for security tooling" 26 │ // @asset GuardLink.Suggest (#suggest) -- "Analyzes code patterns to suggest appropriate security annotations"
+
+
+
+ L22 + asset + GuardLink.Agent_Launcher +
+
Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)
+
17 │ // @asset GuardLink.TUI (#tui) -- "Interactive terminal interface with readline input and command dispatch" 18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands" 24 │ // @asset GuardLink.Report (#report) -- "Generates markdown threat model reports with Mermaid diagrams" 25 │ // @asset GuardLink.SARIF (#sarif) -- "Exports findings as SARIF 2.1.0 JSON for security tooling" 26 │ // @asset GuardLink.Suggest (#suggest) -- "Analyzes code patterns to suggest appropriate security annotations" 27 │
+
+
+
+ L23 + asset + GuardLink.Diff +
+
Compares threat models across git commits, invokes git commands
+
18 │ // @asset GuardLink.MCP (#mcp) -- "Model Context Protocol server, accepts tool calls from AI agents over stdio" 19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands" 24 │ // @asset GuardLink.Report (#report) -- "Generates markdown threat model reports with Mermaid diagrams" 25 │ // @asset GuardLink.SARIF (#sarif) -- "Exports findings as SARIF 2.1.0 JSON for security tooling" 26 │ // @asset GuardLink.Suggest (#suggest) -- "Analyzes code patterns to suggest appropriate security annotations" 27 │ 28 │ // ─── THREATS ──────────────────────────────────────────────────────────
+
+
+
+ L24 + asset + GuardLink.Report +
+
Generates markdown threat model reports with Mermaid diagrams
+
19 │ // @asset GuardLink.LLM_Client (#llm-client) -- "Makes HTTP requests to external AI providers (Anthropic, OpenAI, DeepSeek, OpenRouter)" 20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands" 24 │ // @asset GuardLink.Report (#report) -- "Generates markdown threat model reports with Mermaid diagrams" 25 │ // @asset GuardLink.SARIF (#sarif) -- "Exports findings as SARIF 2.1.0 JSON for security tooling" 26 │ // @asset GuardLink.Suggest (#suggest) -- "Analyzes code patterns to suggest appropriate security annotations" 27 │ 28 │ // ─── THREATS ────────────────────────────────────────────────────────── 29 │ // Security threats that can impact the application
+
+
+
+ L25 + asset + GuardLink.SARIF +
+
Exports findings as SARIF 2.1.0 JSON for security tooling
+
20 │ // @asset GuardLink.Dashboard (#dashboard) -- "Generates interactive HTML threat model dashboard from ThreatModel data" 21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands" 24 │ // @asset GuardLink.Report (#report) -- "Generates markdown threat model reports with Mermaid diagrams" 25 │ // @asset GuardLink.SARIF (#sarif) -- "Exports findings as SARIF 2.1.0 JSON for security tooling" 26 │ // @asset GuardLink.Suggest (#suggest) -- "Analyzes code patterns to suggest appropriate security annotations" 27 │ 28 │ // ─── THREATS ────────────────────────────────────────────────────────── 29 │ // Security threats that can impact the application 30 │
+
+
+
+ L26 + asset + GuardLink.Suggest +
+
Analyzes code patterns to suggest appropriate security annotations
+
21 │ // @asset GuardLink.Init (#init) -- "Initializes projects, writes config files and agent instruction files to disk" 22 │ // @asset GuardLink.Agent_Launcher (#agent-launcher) -- "Spawns child processes for AI coding agents (Claude Code, Cursor, Codex)" 23 │ // @asset GuardLink.Diff (#diff) -- "Compares threat models across git commits, invokes git commands" 24 │ // @asset GuardLink.Report (#report) -- "Generates markdown threat model reports with Mermaid diagrams" 25 │ // @asset GuardLink.SARIF (#sarif) -- "Exports findings as SARIF 2.1.0 JSON for security tooling" 26 │ // @asset GuardLink.Suggest (#suggest) -- "Analyzes code patterns to suggest appropriate security annotations" 27 │ 28 │ // ─── THREATS ────────────────────────────────────────────────────────── 29 │ // Security threats that can impact the application 30 │ 31 │ // @threat Path_Traversal (#path-traversal) [high] cwe:CWE-22 -- "File read/write operations outside intended project directory via ../ sequences or absolute paths"
+
+
+
+ L31 + threat + Path_Traversal +
+
File read/write operations outside intended project directory via ../ sequences or absolute paths
+
26 │ // @asset GuardLink.Suggest (#suggest) -- "Analyzes code patterns to suggest appropriate security annotations" 27 │ 28 │ // ─── THREATS ────────────────────────────────────────────────────────── 29 │ // Security threats that can impact the application 30 │ 31 │ // @threat Path_Traversal (#path-traversal) [high] cwe:CWE-22 -- "File read/write operations outside intended project directory via ../ sequences or absolute paths" 32 │ // @threat Command_Injection (#cmd-injection) [critical] cwe:CWE-78 -- "Shell command execution with unsanitized user input" 33 │ // @threat Cross_Site_Scripting (#xss) [high] cwe:CWE-79 -- "Injection of malicious scripts into generated HTML output" 34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content"
+
+
+
+ L32 + threat + Command_Injection +
+
Shell command execution with unsanitized user input
+
27 │ 28 │ // ─── THREATS ────────────────────────────────────────────────────────── 29 │ // Security threats that can impact the application 30 │ 31 │ // @threat Path_Traversal (#path-traversal) [high] cwe:CWE-22 -- "File read/write operations outside intended project directory via ../ sequences or absolute paths" 32 │ // @threat Command_Injection (#cmd-injection) [critical] cwe:CWE-78 -- "Shell command execution with unsanitized user input" 33 │ // @threat Cross_Site_Scripting (#xss) [high] cwe:CWE-79 -- "Injection of malicious scripts into generated HTML output" 34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project"
+
+
+
+ L33 + threat + Cross_Site_Scripting +
+
Injection of malicious scripts into generated HTML output
+
28 │ // ─── THREATS ────────────────────────────────────────────────────────── 29 │ // Security threats that can impact the application 30 │ 31 │ // @threat Path_Traversal (#path-traversal) [high] cwe:CWE-22 -- "File read/write operations outside intended project directory via ../ sequences or absolute paths" 32 │ // @threat Command_Injection (#cmd-injection) [critical] cwe:CWE-78 -- "Shell command execution with unsanitized user input" 33 │ // @threat Cross_Site_Scripting (#xss) [high] cwe:CWE-79 -- "Injection of malicious scripts into generated HTML output" 34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts"
+
+
+
+ L34 + threat + API_Key_Exposure +
+
API keys leaked in logs, error messages, or unintended output
+
29 │ // Security threats that can impact the application 30 │ 31 │ // @threat Path_Traversal (#path-traversal) [high] cwe:CWE-22 -- "File read/write operations outside intended project directory via ../ sequences or absolute paths" 32 │ // @threat Command_Injection (#cmd-injection) [critical] cwe:CWE-78 -- "Shell command execution with unsanitized user input" 33 │ // @threat Cross_Site_Scripting (#xss) [high] cwe:CWE-79 -- "Injection of malicious scripts into generated HTML output" 34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees"
+
+
+
+ L35 + threat + Server_Side_Request_Forgery +
+
LLM API requests to attacker-controlled URLs via config override
+
30 │ 31 │ // @threat Path_Traversal (#path-traversal) [high] cwe:CWE-22 -- "File read/write operations outside intended project directory via ../ sequences or absolute paths" 32 │ // @threat Command_Injection (#cmd-injection) [critical] cwe:CWE-78 -- "Shell command execution with unsanitized user input" 33 │ // @threat Cross_Site_Scripting (#xss) [high] cwe:CWE-79 -- "Injection of malicious scripts into generated HTML output" 34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties"
+
+
+
+ L36 + threat + ReDoS +
+
Regular expression denial of service from crafted annotation content
+
31 │ // @threat Path_Traversal (#path-traversal) [high] cwe:CWE-22 -- "File read/write operations outside intended project directory via ../ sequences or absolute paths" 32 │ // @threat Command_Injection (#cmd-injection) [critical] cwe:CWE-78 -- "Shell command execution with unsanitized user input" 33 │ // @threat Cross_Site_Scripting (#xss) [high] cwe:CWE-79 -- "Injection of malicious scripts into generated HTML output" 34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties" 41 │ // @threat Insecure_Deserialization (#insecure-deser) [medium] cwe:CWE-502 -- "Unsafe parsing of JSON/YAML configuration files"
+
+
+
+ L37 + threat + Arbitrary_File_Write +
+
Writing files to attacker-controlled paths outside project
+
32 │ // @threat Command_Injection (#cmd-injection) [critical] cwe:CWE-78 -- "Shell command execution with unsanitized user input" 33 │ // @threat Cross_Site_Scripting (#xss) [high] cwe:CWE-79 -- "Injection of malicious scripts into generated HTML output" 34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties" 41 │ // @threat Insecure_Deserialization (#insecure-deser) [medium] cwe:CWE-502 -- "Unsafe parsing of JSON/YAML configuration files" 42 │ // @threat Child_Process_Injection (#child-proc-injection) [high] cwe:CWE-78 -- "Agent launcher executing attacker-controlled commands via process spawn"
+
+
+
+ L38 + threat + Prompt_Injection +
+
Malicious content in annotations injected into LLM prompts
+
33 │ // @threat Cross_Site_Scripting (#xss) [high] cwe:CWE-79 -- "Injection of malicious scripts into generated HTML output" 34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties" 41 │ // @threat Insecure_Deserialization (#insecure-deser) [medium] cwe:CWE-502 -- "Unsafe parsing of JSON/YAML configuration files" 42 │ // @threat Child_Process_Injection (#child-proc-injection) [high] cwe:CWE-78 -- "Agent launcher executing attacker-controlled commands via process spawn" 43 │ // @threat Information_Disclosure (#info-disclosure) [low] cwe:CWE-200 -- "Unintended exposure of internal paths, structure, or implementation details"
+
+
+
+ L39 + threat + Denial_of_Service +
+
Resource exhaustion from processing large files or deep directory trees
+
34 │ // @threat API_Key_Exposure (#api-key-exposure) [high] cwe:CWE-798 -- "API keys leaked in logs, error messages, or unintended output" 35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties" 41 │ // @threat Insecure_Deserialization (#insecure-deser) [medium] cwe:CWE-502 -- "Unsafe parsing of JSON/YAML configuration files" 42 │ // @threat Child_Process_Injection (#child-proc-injection) [high] cwe:CWE-78 -- "Agent launcher executing attacker-controlled commands via process spawn" 43 │ // @threat Information_Disclosure (#info-disclosure) [low] cwe:CWE-200 -- "Unintended exposure of internal paths, structure, or implementation details" 44 │
+
+
+
+ L40 + threat + Sensitive_Data_Exposure +
+
Threat model details exposed to unauthorized parties
+
35 │ // @threat Server_Side_Request_Forgery (#ssrf) [medium] cwe:CWE-918 -- "LLM API requests to attacker-controlled URLs via config override" 36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties" 41 │ // @threat Insecure_Deserialization (#insecure-deser) [medium] cwe:CWE-502 -- "Unsafe parsing of JSON/YAML configuration files" 42 │ // @threat Child_Process_Injection (#child-proc-injection) [high] cwe:CWE-78 -- "Agent launcher executing attacker-controlled commands via process spawn" 43 │ // @threat Information_Disclosure (#info-disclosure) [low] cwe:CWE-200 -- "Unintended exposure of internal paths, structure, or implementation details" 44 │ 45 │ // ─── CONTROLS ─────────────────────────────────────────────────────────
+
+
+
+ L41 + threat + Insecure_Deserialization +
+
Unsafe parsing of JSON/YAML configuration files
+
36 │ // @threat ReDoS (#redos) [medium] cwe:CWE-1333 -- "Regular expression denial of service from crafted annotation content" 37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties" 41 │ // @threat Insecure_Deserialization (#insecure-deser) [medium] cwe:CWE-502 -- "Unsafe parsing of JSON/YAML configuration files" 42 │ // @threat Child_Process_Injection (#child-proc-injection) [high] cwe:CWE-78 -- "Agent launcher executing attacker-controlled commands via process spawn" 43 │ // @threat Information_Disclosure (#info-disclosure) [low] cwe:CWE-200 -- "Unintended exposure of internal paths, structure, or implementation details" 44 │ 45 │ // ─── CONTROLS ───────────────────────────────────────────────────────── 46 │ // Security controls that mitigate threats
+
+
+
+ L42 + threat + Child_Process_Injection +
+
Agent launcher executing attacker-controlled commands via process spawn
+
37 │ // @threat Arbitrary_File_Write (#arbitrary-write) [high] cwe:CWE-73 -- "Writing files to attacker-controlled paths outside project" 38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties" 41 │ // @threat Insecure_Deserialization (#insecure-deser) [medium] cwe:CWE-502 -- "Unsafe parsing of JSON/YAML configuration files" 42 │ // @threat Child_Process_Injection (#child-proc-injection) [high] cwe:CWE-78 -- "Agent launcher executing attacker-controlled commands via process spawn" 43 │ // @threat Information_Disclosure (#info-disclosure) [low] cwe:CWE-200 -- "Unintended exposure of internal paths, structure, or implementation details" 44 │ 45 │ // ─── CONTROLS ───────────────────────────────────────────────────────── 46 │ // Security controls that mitigate threats 47 │
+
+
+
+ L43 + threat + Information_Disclosure +
+
Unintended exposure of internal paths, structure, or implementation details
+
38 │ // @threat Prompt_Injection (#prompt-injection) [medium] cwe:CWE-77 -- "Malicious content in annotations injected into LLM prompts" 39 │ // @threat Denial_of_Service (#dos) [medium] cwe:CWE-400 -- "Resource exhaustion from processing large files or deep directory trees" 40 │ // @threat Sensitive_Data_Exposure (#data-exposure) [medium] cwe:CWE-200 -- "Threat model details exposed to unauthorized parties" 41 │ // @threat Insecure_Deserialization (#insecure-deser) [medium] cwe:CWE-502 -- "Unsafe parsing of JSON/YAML configuration files" 42 │ // @threat Child_Process_Injection (#child-proc-injection) [high] cwe:CWE-78 -- "Agent launcher executing attacker-controlled commands via process spawn" 43 │ // @threat Information_Disclosure (#info-disclosure) [low] cwe:CWE-200 -- "Unintended exposure of internal paths, structure, or implementation details" 44 │ 45 │ // ─── CONTROLS ───────────────────────────────────────────────────────── 46 │ // Security controls that mitigate threats 47 │ 48 │ // @control Path_Validation (#path-validation) -- "Validates file paths using resolve() + startsWith() to ensure access within allowed directories"
+
+
+
+ L48 + control + Path_Validation +
+
Validates file paths using resolve() + startsWith() to ensure access within allowed directories
+
43 │ // @threat Information_Disclosure (#info-disclosure) [low] cwe:CWE-200 -- "Unintended exposure of internal paths, structure, or implementation details" 44 │ 45 │ // ─── CONTROLS ───────────────────────────────────────────────────────── 46 │ // Security controls that mitigate threats 47 │ 48 │ // @control Path_Validation (#path-validation) -- "Validates file paths using resolve() + startsWith() to ensure access within allowed directories" 49 │ // @control Input_Sanitization (#input-sanitize) -- "Input validation with anchored regex patterns and length limits" 50 │ // @control Output_Encoding (#output-encoding) -- "HTML entity encoding for untrusted data in generated output" 51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use"
+
+
+
+ L49 + control + Input_Sanitization +
+
Input validation with anchored regex patterns and length limits
+
44 │ 45 │ // ─── CONTROLS ───────────────────────────────────────────────────────── 46 │ // Security controls that mitigate threats 47 │ 48 │ // @control Path_Validation (#path-validation) -- "Validates file paths using resolve() + startsWith() to ensure access within allowed directories" 49 │ // @control Input_Sanitization (#input-sanitize) -- "Input validation with anchored regex patterns and length limits" 50 │ // @control Output_Encoding (#output-encoding) -- "HTML entity encoding for untrusted data in generated output" 51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints"
+
+
+
+ L50 + control + Output_Encoding +
+
HTML entity encoding for untrusted data in generated output
+
45 │ // ─── CONTROLS ───────────────────────────────────────────────────────── 46 │ // Security controls that mitigate threats 47 │ 48 │ // @control Path_Validation (#path-validation) -- "Validates file paths using resolve() + startsWith() to ensure access within allowed directories" 49 │ // @control Input_Sanitization (#input-sanitize) -- "Input validation with anchored regex patterns and length limits" 50 │ // @control Output_Encoding (#output-encoding) -- "HTML entity encoding for untrusted data in generated output" 51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation"
+
+
+
+ L51 + control + Key_Redaction +
+
Masking API keys in logs and error messages
+
46 │ // Security controls that mitigate threats 47 │ 48 │ // @control Path_Validation (#path-validation) -- "Validates file paths using resolve() + startsWith() to ensure access within allowed directories" 49 │ // @control Input_Sanitization (#input-sanitize) -- "Input validation with anchored regex patterns and length limits" 50 │ // @control Output_Encoding (#output-encoding) -- "HTML entity encoding for untrusted data in generated output" 51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes"
+
+
+
+ L52 + control + Process_Sandboxing +
+
Controlled child process spawning with explicit args array, no shell
+
47 │ 48 │ // @control Path_Validation (#path-validation) -- "Validates file paths using resolve() + startsWith() to ensure access within allowed directories" 49 │ // @control Input_Sanitization (#input-sanitize) -- "Input validation with anchored regex patterns and length limits" 50 │ // @control Output_Encoding (#output-encoding) -- "HTML entity encoding for untrusted data in generated output" 51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" 57 │ // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking"
+
+
+
+ L53 + control + Config_Validation +
+
Schema validation for configuration files before use
+
48 │ // @control Path_Validation (#path-validation) -- "Validates file paths using resolve() + startsWith() to ensure access within allowed directories" 49 │ // @control Input_Sanitization (#input-sanitize) -- "Input validation with anchored regex patterns and length limits" 50 │ // @control Output_Encoding (#output-encoding) -- "HTML entity encoding for untrusted data in generated output" 51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" 57 │ // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking" 58 │ // @control Prefix_Ownership (#prefix-ownership) -- "Tag prefix determines owning repo, preventing cross-repo tag collisions"
+
+
+
+ L54 + control + Resource_Limits +
+
File size limits, recursion depth limits, timeout constraints
+
49 │ // @control Input_Sanitization (#input-sanitize) -- "Input validation with anchored regex patterns and length limits" 50 │ // @control Output_Encoding (#output-encoding) -- "HTML entity encoding for untrusted data in generated output" 51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" 57 │ // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking" 58 │ // @control Prefix_Ownership (#prefix-ownership) -- "Tag prefix determines owning repo, preventing cross-repo tag collisions" 59 │ // @control YAML_Validation (#yaml-validation) -- "Schema validation for workspace.yaml configuration files"
+
+
+
+ L55 + control + Parameterized_Commands +
+
Using spawn with args array instead of shell string interpolation
+
50 │ // @control Output_Encoding (#output-encoding) -- "HTML entity encoding for untrusted data in generated output" 51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" 57 │ // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking" 58 │ // @control Prefix_Ownership (#prefix-ownership) -- "Tag prefix determines owning repo, preventing cross-repo tag collisions" 59 │ // @control YAML_Validation (#yaml-validation) -- "Schema validation for workspace.yaml configuration files" 60 │
+
+
+
+ L56 + control + Glob_Pattern_Filtering +
+
Filtering files using glob patterns with explicit excludes
+
51 │ // @control Key_Redaction (#key-redaction) -- "Masking API keys in logs and error messages" 52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" 57 │ // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking" 58 │ // @control Prefix_Ownership (#prefix-ownership) -- "Tag prefix determines owning repo, preventing cross-repo tag collisions" 59 │ // @control YAML_Validation (#yaml-validation) -- "Schema validation for workspace.yaml configuration files" 60 │
+
+
+
+ L57 + control + Regex_Anchoring +
+
Using anchored regex patterns (^...$) to prevent backtracking
+
52 │ // @control Process_Sandboxing (#process-sandbox) -- "Controlled child process spawning with explicit args array, no shell" 53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" 57 │ // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking" 58 │ // @control Prefix_Ownership (#prefix-ownership) -- "Tag prefix determines owning repo, preventing cross-repo tag collisions" 59 │ // @control YAML_Validation (#yaml-validation) -- "Schema validation for workspace.yaml configuration files" 60 │
+
+
+
+ L58 + control + Prefix_Ownership +
+
Tag prefix determines owning repo, preventing cross-repo tag collisions
+
53 │ // @control Config_Validation (#config-validation) -- "Schema validation for configuration files before use" 54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" 57 │ // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking" 58 │ // @control Prefix_Ownership (#prefix-ownership) -- "Tag prefix determines owning repo, preventing cross-repo tag collisions" 59 │ // @control YAML_Validation (#yaml-validation) -- "Schema validation for workspace.yaml configuration files" 60 │
+
+
+
+ L59 + control + YAML_Validation +
+
Schema validation for workspace.yaml configuration files
+
54 │ // @control Resource_Limits (#resource-limits) -- "File size limits, recursion depth limits, timeout constraints" 55 │ // @control Parameterized_Commands (#param-commands) -- "Using spawn with args array instead of shell string interpolation" 56 │ // @control Glob_Pattern_Filtering (#glob-filtering) -- "Filtering files using glob patterns with explicit excludes" 57 │ // @control Regex_Anchoring (#regex-anchoring) -- "Using anchored regex patterns (^...$) to prevent backtracking" 58 │ // @control Prefix_Ownership (#prefix-ownership) -- "Tag prefix determines owning repo, preventing cross-repo tag collisions" 59 │ // @control YAML_Validation (#yaml-validation) -- "Schema validation for workspace.yaml configuration files" 60 │
+
+
+
+
+
+ src/agents/config.ts + + 10 + + +
+
+ +
+
+ L13 + exposes + #agent-launcher → #api-key-exposure +
+
API keys loaded from env vars, files; stored in config.json
+
8 │ * 4. Project config: .guardlink/config.json 9 │ * 5. Global config: ~/.config/guardlink/config.json 10 │ * 11 │ * Replaces the fragmented tui-config.json / CLI flag / env var resolution. 12 │ * 13 │ * @exposes #agent-launcher to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from env vars, files; stored in config.json" 14 │ * @mitigates #agent-launcher against #api-key-exposure using #key-redaction -- "maskKey() redacts keys for display; keys never logged" 15 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Config paths resolved from root and homedir" 16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root"
+
+
+
+ L14 + mitigates + #key-redaction mitigates #api-key-exposure +
+
maskKey() redacts keys for display; keys never logged
+
9 │ * 5. Global config: ~/.config/guardlink/config.json 10 │ * 11 │ * Replaces the fragmented tui-config.json / CLI flag / env var resolution. 12 │ * 13 │ * @exposes #agent-launcher to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from env vars, files; stored in config.json" 14 │ * @mitigates #agent-launcher against #api-key-exposure using #key-redaction -- "maskKey() redacts keys for display; keys never logged" 15 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Config paths resolved from root and homedir" 16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input"
+
+
+
+ L15 + exposes + #agent-launcher → #path-traversal +
+
Config paths resolved from root and homedir
+
10 │ * 11 │ * Replaces the fragmented tui-config.json / CLI flag / env var resolution. 12 │ * 13 │ * @exposes #agent-launcher to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from env vars, files; stored in config.json" 14 │ * @mitigates #agent-launcher against #api-key-exposure using #key-redaction -- "maskKey() redacts keys for display; keys never logged" 15 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Config paths resolved from root and homedir" 16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input" 20 │ * @flows ConfigFile -> #agent-launcher via readFileSync -- "Config file read"
+
+
+
+ L16 + mitigates + #path-validation mitigates #path-traversal +
+
join() with known base dirs constrains paths
+
11 │ * Replaces the fragmented tui-config.json / CLI flag / env var resolution. 12 │ * 13 │ * @exposes #agent-launcher to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from env vars, files; stored in config.json" 14 │ * @mitigates #agent-launcher against #api-key-exposure using #key-redaction -- "maskKey() redacts keys for display; keys never logged" 15 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Config paths resolved from root and homedir" 16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input" 20 │ * @flows ConfigFile -> #agent-launcher via readFileSync -- "Config file read" 21 │ * @flows #agent-launcher -> ConfigFile via writeFileSync -- "Config file write"
+
+
+
+ L17 + exposes + #agent-launcher → #arbitrary-write +
+
saveProjectConfig writes to .guardlink/config.json
+
12 │ * 13 │ * @exposes #agent-launcher to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from env vars, files; stored in config.json" 14 │ * @mitigates #agent-launcher against #api-key-exposure using #key-redaction -- "maskKey() redacts keys for display; keys never logged" 15 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Config paths resolved from root and homedir" 16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input" 20 │ * @flows ConfigFile -> #agent-launcher via readFileSync -- "Config file read" 21 │ * @flows #agent-launcher -> ConfigFile via writeFileSync -- "Config file write" 22 │ * @handles secrets on #agent-launcher -- "Processes and stores LLM API keys"
+
+
+
+ L18 + mitigates + #path-validation mitigates #arbitrary-write +
+
Output path is fixed relative to project root
+
13 │ * @exposes #agent-launcher to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from env vars, files; stored in config.json" 14 │ * @mitigates #agent-launcher against #api-key-exposure using #key-redaction -- "maskKey() redacts keys for display; keys never logged" 15 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Config paths resolved from root and homedir" 16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input" 20 │ * @flows ConfigFile -> #agent-launcher via readFileSync -- "Config file read" 21 │ * @flows #agent-launcher -> ConfigFile via writeFileSync -- "Config file write" 22 │ * @handles secrets on #agent-launcher -- "Processes and stores LLM API keys" 23 │ */
+
+
+
+ L19 + flow + EnvVars → #agent-launcher +
+
Environment variable input
+
14 │ * @mitigates #agent-launcher against #api-key-exposure using #key-redaction -- "maskKey() redacts keys for display; keys never logged" 15 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Config paths resolved from root and homedir" 16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input" 20 │ * @flows ConfigFile -> #agent-launcher via readFileSync -- "Config file read" 21 │ * @flows #agent-launcher -> ConfigFile via writeFileSync -- "Config file write" 22 │ * @handles secrets on #agent-launcher -- "Processes and stores LLM API keys" 23 │ */ 24 │
+
+
+
+ L20 + flow + ConfigFile → #agent-launcher +
+
Config file read
+
15 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Config paths resolved from root and homedir" 16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input" 20 │ * @flows ConfigFile -> #agent-launcher via readFileSync -- "Config file read" 21 │ * @flows #agent-launcher -> ConfigFile via writeFileSync -- "Config file write" 22 │ * @handles secrets on #agent-launcher -- "Processes and stores LLM API keys" 23 │ */ 24 │ 25 │ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
+
+
+
+ L21 + flow + #agent-launcher → ConfigFile +
+
Config file write
+
16 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "join() with known base dirs constrains paths" 17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input" 20 │ * @flows ConfigFile -> #agent-launcher via readFileSync -- "Config file read" 21 │ * @flows #agent-launcher -> ConfigFile via writeFileSync -- "Config file write" 22 │ * @handles secrets on #agent-launcher -- "Processes and stores LLM API keys" 23 │ */ 24 │ 25 │ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'; 26 │ import { join } from 'node:path';
+
+
+
+ L22 + handles + #agent-launcher: secrets +
+
Processes and stores LLM API keys
+
17 │ * @exposes #agent-launcher to #arbitrary-write [medium] cwe:CWE-73 -- "saveProjectConfig writes to .guardlink/config.json" 18 │ * @mitigates #agent-launcher against #arbitrary-write using #path-validation -- "Output path is fixed relative to project root" 19 │ * @flows EnvVars -> #agent-launcher via process.env -- "Environment variable input" 20 │ * @flows ConfigFile -> #agent-launcher via readFileSync -- "Config file read" 21 │ * @flows #agent-launcher -> ConfigFile via writeFileSync -- "Config file write" 22 │ * @handles secrets on #agent-launcher -- "Processes and stores LLM API keys" 23 │ */ 24 │ 25 │ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'; 26 │ import { join } from 'node:path'; 27 │ import { homedir } from 'node:os';
+
+
+
+
+
+ src/agents/index.ts + + 2 + + +
+
+ +
+
+ L7 + comment + Agent binaries are hardcoded; no user-controlled binary names +
+
Agent binaries are hardcoded; no user-controlled binary names
+
2 │ * GuardLink Agents — Shared agent registry. 3 │ * 4 │ * Used by CLI, TUI, and MCP to identify and resolve coding agents 5 │ * (Claude Code, Codex, Cursor, Windsurf, Gemini, clipboard). 6 │ * 7 │ * @comment -- "Agent binaries are hardcoded; no user-controlled binary names" 8 │ * @comment -- "parseAgentFlag extracts flags from args; no injection risk" 9 │ */ 10 │ 11 │ // ─── Agent registry ────────────────────────────────────────────────── 12 │
+
+
+
+ L8 + comment + parseAgentFlag extracts flags from args; no injection risk +
+
parseAgentFlag extracts flags from args; no injection risk
+
3 │ * 4 │ * Used by CLI, TUI, and MCP to identify and resolve coding agents 5 │ * (Claude Code, Codex, Cursor, Windsurf, Gemini, clipboard). 6 │ * 7 │ * @comment -- "Agent binaries are hardcoded; no user-controlled binary names" 8 │ * @comment -- "parseAgentFlag extracts flags from args; no injection risk" 9 │ */ 10 │ 11 │ // ─── Agent registry ────────────────────────────────────────────────── 12 │ 13 │ export interface AgentEntry {
+
+
+
+
+
+ src/agents/launcher.ts + + 11 + + +
+
+ +
+
+ L10 + exposes + #agent-launcher → #child-proc-injection +
+
spawn/spawnSync execute external binaries
+
5 │ * 1. Foreground spawn (CLI + TUI): takes over terminal, returns on exit 6 │ * 2. IDE launch: opens GUI app with project directory 7 │ * 8 │ * Clipboard copy is always performed first regardless of agent type. 9 │ * 10 │ * @exposes #agent-launcher to #child-proc-injection [critical] cwe:CWE-78 -- "spawn/spawnSync execute external binaries" 11 │ * @mitigates #agent-launcher against #child-proc-injection using #param-commands -- "Binary names from hardcoded AGENTS registry; no shell interpolation" 12 │ * @mitigates #agent-launcher against #cmd-injection using #param-commands -- "Arguments passed as array, not shell string" 13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration"
+
+
+
+ L11 + mitigates + #param-commands mitigates #child-proc-injection +
+
Binary names from hardcoded AGENTS registry; no shell interpolation
+
6 │ * 2. IDE launch: opens GUI app with project directory 7 │ * 8 │ * Clipboard copy is always performed first regardless of agent type. 9 │ * 10 │ * @exposes #agent-launcher to #child-proc-injection [critical] cwe:CWE-78 -- "spawn/spawnSync execute external binaries" 11 │ * @mitigates #agent-launcher against #child-proc-injection using #param-commands -- "Binary names from hardcoded AGENTS registry; no shell interpolation" 12 │ * @mitigates #agent-launcher against #cmd-injection using #param-commands -- "Arguments passed as array, not shell string" 13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control"
+
+
+
+ L12 + mitigates + #param-commands mitigates #cmd-injection +
+
Arguments passed as array, not shell string
+
7 │ * 8 │ * Clipboard copy is always performed first regardless of agent type. 9 │ * 10 │ * @exposes #agent-launcher to #child-proc-injection [critical] cwe:CWE-78 -- "spawn/spawnSync execute external binaries" 11 │ * @mitigates #agent-launcher against #child-proc-injection using #param-commands -- "Binary names from hardcoded AGENTS registry; no shell interpolation" 12 │ * @mitigates #agent-launcher against #cmd-injection using #param-commands -- "Arguments passed as array, not shell string" 13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path"
+
+
+
+ L13 + exposes + #agent-launcher → #prompt-injection +
+
User prompt passed to agent CLI as argument
+
8 │ * Clipboard copy is always performed first regardless of agent type. 9 │ * 10 │ * @exposes #agent-launcher to #child-proc-injection [critical] cwe:CWE-78 -- "spawn/spawnSync execute external binaries" 11 │ * @mitigates #agent-launcher against #child-proc-injection using #param-commands -- "Binary names from hardcoded AGENTS registry; no shell interpolation" 12 │ * @mitigates #agent-launcher against #cmd-injection using #param-commands -- "Arguments passed as array, not shell string" 13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" 18 │ * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path"
+
+
+
+ L14 + audit + Audit: #agent-launcher +
+
Prompt content is opaque to agent binary; injection risk depends on agent implementation
+
9 │ * 10 │ * @exposes #agent-launcher to #child-proc-injection [critical] cwe:CWE-78 -- "spawn/spawnSync execute external binaries" 11 │ * @mitigates #agent-launcher against #child-proc-injection using #param-commands -- "Binary names from hardcoded AGENTS registry; no shell interpolation" 12 │ * @mitigates #agent-launcher against #cmd-injection using #param-commands -- "Arguments passed as array, not shell string" 13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" 18 │ * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path" 19 │ * @flows AgentProcess -> #agent-launcher via stdout -- "Agent output capture"
+
+
+
+ L15 + exposes + #agent-launcher → #dos +
+
No timeout on foreground spawn; agent controls duration
+
10 │ * @exposes #agent-launcher to #child-proc-injection [critical] cwe:CWE-78 -- "spawn/spawnSync execute external binaries" 11 │ * @mitigates #agent-launcher against #child-proc-injection using #param-commands -- "Binary names from hardcoded AGENTS registry; no shell interpolation" 12 │ * @mitigates #agent-launcher against #cmd-injection using #param-commands -- "Arguments passed as array, not shell string" 13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" 18 │ * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path" 19 │ * @flows AgentProcess -> #agent-launcher via stdout -- "Agent output capture" 20 │ * @boundary #agent-launcher and AgentProcess (#agent-boundary) -- "Trust boundary at process spawn"
+
+
+
+ L16 + audit + Audit: #agent-launcher +
+
Timeout intentionally omitted for interactive sessions; inline mode has implicit control
+
11 │ * @mitigates #agent-launcher against #child-proc-injection using #param-commands -- "Binary names from hardcoded AGENTS registry; no shell interpolation" 12 │ * @mitigates #agent-launcher against #cmd-injection using #param-commands -- "Arguments passed as array, not shell string" 13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" 18 │ * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path" 19 │ * @flows AgentProcess -> #agent-launcher via stdout -- "Agent output capture" 20 │ * @boundary #agent-launcher and AgentProcess (#agent-boundary) -- "Trust boundary at process spawn" 21 │ */
+
+
+
+ L17 + flow + UserPrompt → #agent-launcher +
+
Prompt input path
+
12 │ * @mitigates #agent-launcher against #cmd-injection using #param-commands -- "Arguments passed as array, not shell string" 13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" 18 │ * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path" 19 │ * @flows AgentProcess -> #agent-launcher via stdout -- "Agent output capture" 20 │ * @boundary #agent-launcher and AgentProcess (#agent-boundary) -- "Trust boundary at process spawn" 21 │ */ 22 │
+
+
+
+ L18 + flow + #agent-launcher → AgentProcess +
+
Process spawn path
+
13 │ * @exposes #agent-launcher to #prompt-injection [medium] cwe:CWE-77 -- "User prompt passed to agent CLI as argument" 14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" 18 │ * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path" 19 │ * @flows AgentProcess -> #agent-launcher via stdout -- "Agent output capture" 20 │ * @boundary #agent-launcher and AgentProcess (#agent-boundary) -- "Trust boundary at process spawn" 21 │ */ 22 │ 23 │ import { spawnSync, spawn } from 'node:child_process';
+
+
+
+ L19 + flow + AgentProcess → #agent-launcher +
+
Agent output capture
+
14 │ * @audit #agent-launcher -- "Prompt content is opaque to agent binary; injection risk depends on agent implementation" 15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" 18 │ * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path" 19 │ * @flows AgentProcess -> #agent-launcher via stdout -- "Agent output capture" 20 │ * @boundary #agent-launcher and AgentProcess (#agent-boundary) -- "Trust boundary at process spawn" 21 │ */ 22 │ 23 │ import { spawnSync, spawn } from 'node:child_process'; 24 │ import { platform } from 'node:os';
+
+
+
+ L20 + boundary + #agent-launcher ↔ AgentProcess +
+
Trust boundary at process spawn
+
15 │ * @exposes #agent-launcher to #dos [low] cwe:CWE-400 -- "No timeout on foreground spawn; agent controls duration" 16 │ * @audit #agent-launcher -- "Timeout intentionally omitted for interactive sessions; inline mode has implicit control" 17 │ * @flows UserPrompt -> #agent-launcher via launchAgent -- "Prompt input path" 18 │ * @flows #agent-launcher -> AgentProcess via spawn -- "Process spawn path" 19 │ * @flows AgentProcess -> #agent-launcher via stdout -- "Agent output capture" 20 │ * @boundary #agent-launcher and AgentProcess (#agent-boundary) -- "Trust boundary at process spawn" 21 │ */ 22 │ 23 │ import { spawnSync, spawn } from 'node:child_process'; 24 │ import { platform } from 'node:os'; 25 │ import { mkdtempSync, readFileSync, unlinkSync, existsSync } from 'node:fs';
+
+
+
+
+
+ src/agents/prompts.ts + + 24 + + +
+
+ +
+
+ L6 + exposes + #agent-launcher → #prompt-injection +
+
User prompt concatenated into agent instruction text
+
1 │ /** 2 │ * GuardLink Agents — Prompt builders for annotation and analysis. 3 │ * 4 │ * Extracted from tui/commands.ts for shared use across CLI, TUI, MCP. 5 │ * 6 │ * @exposes #agent-launcher to #prompt-injection [high] cwe:CWE-77 -- "User prompt concatenated into agent instruction text" 7 │ * @audit #agent-launcher -- "Prompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only context" 8 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Reads reference docs from root-relative paths" 9 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "resolve() with root constrains file access" 10 │ * @flows UserPrompt -> #agent-launcher via buildAnnotatePrompt -- "User instruction input" 11 │ * @flows ThreatModel -> #agent-launcher via model -- "Model context injection"
+
+
+
+ L7 + audit + Audit: #agent-launcher +
+
Prompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only context
+
2 │ * GuardLink Agents — Prompt builders for annotation and analysis. 3 │ * 4 │ * Extracted from tui/commands.ts for shared use across CLI, TUI, MCP. 5 │ * 6 │ * @exposes #agent-launcher to #prompt-injection [high] cwe:CWE-77 -- "User prompt concatenated into agent instruction text" 7 │ * @audit #agent-launcher -- "Prompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only context" 8 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Reads reference docs from root-relative paths" 9 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "resolve() with root constrains file access" 10 │ * @flows UserPrompt -> #agent-launcher via buildAnnotatePrompt -- "User instruction input" 11 │ * @flows ThreatModel -> #agent-launcher via model -- "Model context injection" 12 │ * @flows #agent-launcher -> AgentPrompt via return -- "Assembled prompt output"
+
+
+
+ L8 + exposes + #agent-launcher → #path-traversal +
+
Reads reference docs from root-relative paths
+
3 │ * 4 │ * Extracted from tui/commands.ts for shared use across CLI, TUI, MCP. 5 │ * 6 │ * @exposes #agent-launcher to #prompt-injection [high] cwe:CWE-77 -- "User prompt concatenated into agent instruction text" 7 │ * @audit #agent-launcher -- "Prompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only context" 8 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Reads reference docs from root-relative paths" 9 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "resolve() with root constrains file access" 10 │ * @flows UserPrompt -> #agent-launcher via buildAnnotatePrompt -- "User instruction input" 11 │ * @flows ThreatModel -> #agent-launcher via model -- "Model context injection" 12 │ * @flows #agent-launcher -> AgentPrompt via return -- "Assembled prompt output" 13 │ * @handles internal on #agent-launcher -- "Serializes threat model IDs and flows into prompt"
+
+
+
+ L9 + mitigates + #path-validation mitigates #path-traversal +
+
resolve() with root constrains file access
+
4 │ * Extracted from tui/commands.ts for shared use across CLI, TUI, MCP. 5 │ * 6 │ * @exposes #agent-launcher to #prompt-injection [high] cwe:CWE-77 -- "User prompt concatenated into agent instruction text" 7 │ * @audit #agent-launcher -- "Prompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only context" 8 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Reads reference docs from root-relative paths" 9 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "resolve() with root constrains file access" 10 │ * @flows UserPrompt -> #agent-launcher via buildAnnotatePrompt -- "User instruction input" 11 │ * @flows ThreatModel -> #agent-launcher via model -- "Model context injection" 12 │ * @flows #agent-launcher -> AgentPrompt via return -- "Assembled prompt output" 13 │ * @handles internal on #agent-launcher -- "Serializes threat model IDs and flows into prompt" 14 │ */
+
+
+
+ L10 + flow + UserPrompt → #agent-launcher +
+
User instruction input
+
5 │ * 6 │ * @exposes #agent-launcher to #prompt-injection [high] cwe:CWE-77 -- "User prompt concatenated into agent instruction text" 7 │ * @audit #agent-launcher -- "Prompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only context" 8 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Reads reference docs from root-relative paths" 9 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "resolve() with root constrains file access" 10 │ * @flows UserPrompt -> #agent-launcher via buildAnnotatePrompt -- "User instruction input" 11 │ * @flows ThreatModel -> #agent-launcher via model -- "Model context injection" 12 │ * @flows #agent-launcher -> AgentPrompt via return -- "Assembled prompt output" 13 │ * @handles internal on #agent-launcher -- "Serializes threat model IDs and flows into prompt" 14 │ */ 15 │
+
+
+
+ L11 + flow + ThreatModel → #agent-launcher +
+
Model context injection
+
6 │ * @exposes #agent-launcher to #prompt-injection [high] cwe:CWE-77 -- "User prompt concatenated into agent instruction text" 7 │ * @audit #agent-launcher -- "Prompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only context" 8 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Reads reference docs from root-relative paths" 9 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "resolve() with root constrains file access" 10 │ * @flows UserPrompt -> #agent-launcher via buildAnnotatePrompt -- "User instruction input" 11 │ * @flows ThreatModel -> #agent-launcher via model -- "Model context injection" 12 │ * @flows #agent-launcher -> AgentPrompt via return -- "Assembled prompt output" 13 │ * @handles internal on #agent-launcher -- "Serializes threat model IDs and flows into prompt" 14 │ */ 15 │ 16 │ import { existsSync, readFileSync } from 'node:fs';
+
+
+
+ L12 + flow + #agent-launcher → AgentPrompt +
+
Assembled prompt output
+
7 │ * @audit #agent-launcher -- "Prompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only context" 8 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Reads reference docs from root-relative paths" 9 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "resolve() with root constrains file access" 10 │ * @flows UserPrompt -> #agent-launcher via buildAnnotatePrompt -- "User instruction input" 11 │ * @flows ThreatModel -> #agent-launcher via model -- "Model context injection" 12 │ * @flows #agent-launcher -> AgentPrompt via return -- "Assembled prompt output" 13 │ * @handles internal on #agent-launcher -- "Serializes threat model IDs and flows into prompt" 14 │ */ 15 │ 16 │ import { existsSync, readFileSync } from 'node:fs'; 17 │ import { resolve } from 'node:path';
+
+
+
+ L13 + handles + #agent-launcher: internal +
+
Serializes threat model IDs and flows into prompt
+
8 │ * @exposes #agent-launcher to #path-traversal [medium] cwe:CWE-22 -- "Reads reference docs from root-relative paths" 9 │ * @mitigates #agent-launcher against #path-traversal using #path-validation -- "resolve() with root constrains file access" 10 │ * @flows UserPrompt -> #agent-launcher via buildAnnotatePrompt -- "User instruction input" 11 │ * @flows ThreatModel -> #agent-launcher via model -- "Model context injection" 12 │ * @flows #agent-launcher -> AgentPrompt via return -- "Assembled prompt output" 13 │ * @handles internal on #agent-launcher -- "Serializes threat model IDs and flows into prompt" 14 │ */ 15 │ 16 │ import { existsSync, readFileSync } from 'node:fs'; 17 │ import { resolve } from 'node:path'; 18 │ import type { ThreatModel } from '../types/index.js';
+
+
+
+ L148 + shield + Example annotation block for reference, excluded from parsing +
+ +
143 │ 144 │ ### Always Couple Annotations Together 145 │ A file's doc-block should paint the full security picture of that module. Group annotations logically: 146 │ 147 │ \`\`\` 148 │ // @shield:begin -- "Example annotation block for reference, excluded from parsing" 149 │ // 150 │ // GOOD — Complete story at a single code location: 151 │ // @exposes #auth-api to #sqli [P1] cwe:CWE-89 -- "User-supplied email passed to findUser() query builder" 152 │ // @mitigates #auth-api against #sqli using #input-validation -- "Zod schema validates email format before query" 153 │ // @flows User_Input -> #auth-api via POST./login -- "Login form submits credentials"
+
+
+
+ L161 + shield + Shielded region +
+ +
156 │ // @comment -- "Password comparison uses bcrypt.compare with timing-safe equality" 157 │ // 158 │ // BAD — Isolated annotation with no context: 159 │ // @exposes #auth-api to #sqli -- "SQL injection possible" 160 │ // 161 │ // @shield:end 162 │ \`\`\` 163 │ 164 │ ### Description Style — Reference Actual Code 165 │ Descriptions must reference the real code: function names, variable names, libraries, mechanisms. 166 │
+
+
+
+ L168 + shield + Description examples, excluded from parsing +
+ +
163 │ 164 │ ### Description Style — Reference Actual Code 165 │ Descriptions must reference the real code: function names, variable names, libraries, mechanisms. 166 │ 167 │ \`\`\` 168 │ // @shield:begin -- "Description examples, excluded from parsing" 169 │ // 170 │ // GOOD: -- "req.body.token passed to jwt.verify() without audience check" 171 │ // GOOD: -- "bcrypt rounds set to 12 via BCRYPT_COST env var" 172 │ // GOOD: -- "Rate limiter uses express-rate-limit at 100req/15min on /api/*" 173 │ //
+
+
+
+ L178 + shield + Shielded region +
+ +
173 │ // 174 │ // BAD: -- "Input not validated" (too vague — WHICH input? WHERE?) 175 │ // BAD: -- "Uses encryption" (WHAT encryption? On WHAT data?) 176 │ // BAD: -- "Security vulnerability exists" (meaningless — be specific) 177 │ // 178 │ // @shield:end 179 │ \`\`\` 180 │ 181 │ ### @flows — Stitch the Complete Data Path 182 │ @flows is the backbone of the threat model. Trace data movement accurately: 183 │
+
+
+
+ L185 + shield + Flow examples, excluded from parsing +
+ +
180 │ 181 │ ### @flows — Stitch the Complete Data Path 182 │ @flows is the backbone of the threat model. Trace data movement accurately: 183 │ 184 │ \`\`\` 185 │ // @shield:begin -- "Flow examples, excluded from parsing" 186 │ // 187 │ // Trace a request through the full stack: 188 │ // @flows User_Browser -> #api-gateway via HTTPS -- "Client sends auth request" 189 │ // @flows #api-gateway -> #auth-service via internal.gRPC -- "Gateway forwards to auth microservice" 190 │ // @flows #auth-service -> #user-db via pg.query -- "Looks up user record by email"
+
+
+
+ L194 + shield + Shielded region +
+ +
189 │ // @flows #api-gateway -> #auth-service via internal.gRPC -- "Gateway forwards to auth microservice" 190 │ // @flows #auth-service -> #user-db via pg.query -- "Looks up user record by email" 191 │ // @flows #auth-service -> #session-store via redis.set -- "Stores session token with TTL" 192 │ // @flows #auth-service -> User_Browser via Set-Cookie -- "Returns session cookie to client" 193 │ // 194 │ // @shield:end 195 │ \`\`\` 196 │ 197 │ ### @boundary — Mark Every Trust Zone Crossing 198 │ Place @boundary annotations where trust level changes between two components: 199 │
+
+
+
+ L201 + shield + Boundary examples, excluded from parsing +
+ +
196 │ 197 │ ### @boundary — Mark Every Trust Zone Crossing 198 │ Place @boundary annotations where trust level changes between two components: 199 │ 200 │ \`\`\` 201 │ // @shield:begin -- "Boundary examples, excluded from parsing" 202 │ // 203 │ // @boundary between #api-gateway and External_Internet (#public-boundary) -- "TLS termination, rate limiting at edge" 204 │ // @boundary between #backend and #database (#data-boundary) -- "Application to persistence layer, connection pooling via pgBouncer" 205 │ // @boundary between #app and #payment-provider (#vendor-boundary) -- "PCI-DSS scope boundary, tokenized card data only" 206 │ //
+
+
+
+ L207 + shield + Shielded region +
+ +
202 │ // 203 │ // @boundary between #api-gateway and External_Internet (#public-boundary) -- "TLS termination, rate limiting at edge" 204 │ // @boundary between #backend and #database (#data-boundary) -- "Application to persistence layer, connection pooling via pgBouncer" 205 │ // @boundary between #app and #payment-provider (#vendor-boundary) -- "PCI-DSS scope boundary, tokenized card data only" 206 │ // 207 │ // @shield:end 208 │ \`\`\` 209 │ 210 │ ### Where to Place Annotations 211 │ Annotations go in the file's top doc-block comment OR directly above the security-relevant code: 212 │
+
+
+
+ L214 + shield + Placement examples, excluded from parsing +
+ +
209 │ 210 │ ### Where to Place Annotations 211 │ Annotations go in the file's top doc-block comment OR directly above the security-relevant code: 212 │ 213 │ \`\`\` 214 │ // @shield:begin -- "Placement examples, excluded from parsing" 215 │ // 216 │ // FILE-LEVEL (top doc-block) — for module-wide security properties: 217 │ // Place @exposes, @mitigates, @flows, @handles, @boundary that describe the module as a whole 218 │ // 219 │ // INLINE (above specific functions/methods) — for function-specific concerns:
+
+
+
+ L223 + shield + Shielded region +
+ +
218 │ // 219 │ // INLINE (above specific functions/methods) — for function-specific concerns: 220 │ // Place @exposes, @mitigates above the exact function where the risk or control lives 221 │ // Place @comment above tricky security-relevant code to explain intent 222 │ // 223 │ // @shield:end 224 │ \`\`\` 225 │ 226 │ ### Severity — Be Honest, Not Alarmist 227 │ Annotations capture what COULD go wrong, calibrated to realistic risk: 228 │ - **[P0] / [critical]**: Directly exploitable by external attacker, severe impact (RCE, auth bypass, data breach)
+
+
+
+ L250 + shield + @accepts alternative examples, excluded from parsing +
+ +
245 │ 3. Add @comment explaining what controls COULD be added 246 │ 4. Optionally add @assumes to document any assumptions the code makes 247 │ 248 │ Example — what to do when no mitigation exists: 249 │ \`\`\` 250 │ // @shield:begin -- "@accepts alternative examples, excluded from parsing" 251 │ // 252 │ // WRONG (AI rubber-stamping risk): 253 │ // @accepts #prompt-injection on #ai-endpoint -- "Relying on model safety filters" 254 │ // 255 │ // RIGHT (flag for human review):
+
+
+
+ L260 + shield + Shielded region +
+ +
255 │ // RIGHT (flag for human review): 256 │ // @exposes #ai-endpoint to #prompt-injection [P1] cwe:CWE-77 -- "User prompt passed directly to LLM API without sanitization" 257 │ // @audit #ai-endpoint -- "No prompt sanitization — needs human review to decide: add input filter or accept risk" 258 │ // @comment -- "Potential controls: #prompt-filter (input sanitization), #output-validator (response filtering)" 259 │ // 260 │ // @shield:end 261 │ \`\`\` 262 │ 263 │ Leaving exposures unmitigated is HONEST. The dashboard and reports will surface them as open risks for humans to triage. 264 │ 265 │ ### @shield — DO NOT USE Unless Explicitly Asked
+
+
+
+ L277 + shield + Definition syntax examples, excluded from parsing +
+ +
272 │ 273 │ Definitions go in .guardlink/definitions.{ts,js,py,rs}. Source files use only relationship verbs. 274 │ 275 │ ### Definitions (in .guardlink/definitions file) 276 │ \`\`\` 277 │ // @shield:begin -- "Definition syntax examples, excluded from parsing" 278 │ // @asset Server.Auth (#auth) -- "Authentication service handling login and session management" 279 │ // @threat SQL_Injection (#sqli) [P0] cwe:CWE-89 -- "Unsanitized input reaches SQL query builder" 280 │ // @control Prepared_Statements (#prepared-stmts) -- "Parameterized queries via ORM or driver placeholders" 281 │ // @shield:end 282 │ \`\`\`
+
+
+
+ L281 + shield + Shielded region +
+ +
276 │ \`\`\` 277 │ // @shield:begin -- "Definition syntax examples, excluded from parsing" 278 │ // @asset Server.Auth (#auth) -- "Authentication service handling login and session management" 279 │ // @threat SQL_Injection (#sqli) [P0] cwe:CWE-89 -- "Unsanitized input reaches SQL query builder" 280 │ // @control Prepared_Statements (#prepared-stmts) -- "Parameterized queries via ORM or driver placeholders" 281 │ // @shield:end 282 │ \`\`\` 283 │ 284 │ ### Relationships (in source files) 285 │ \`\`\` 286 │ // @shield:begin -- "Relationship syntax examples, excluded from parsing"
+
+
+
+ L286 + shield + Relationship syntax examples, excluded from parsing +
+ +
281 │ // @shield:end 282 │ \`\`\` 283 │ 284 │ ### Relationships (in source files) 285 │ \`\`\` 286 │ // @shield:begin -- "Relationship syntax examples, excluded from parsing" 287 │ // @exposes #auth to #sqli [P0] cwe:CWE-89 owasp:A03:2021 -- "User input concatenated into query" 288 │ // @mitigates #auth against #sqli using #prepared-stmts -- "Uses parameterized queries via sqlx" 289 │ // @audit #auth -- "Timing attack risk — needs human review to decide if bcrypt constant-time comparison is sufficient" 290 │ // @transfers #ddos from #api to #cdn -- "Cloudflare handles L7 DDoS mitigation" 291 │ // @flows req.body.username -> db.query via string-concat -- "User input flows to SQL"
+
+
+
+ L299 + shield + Shielded region +
+ +
294 │ // @validates #prepared-stmts for #auth -- "Integration test sqlInjectionTest.ts confirms parameterized queries block SQLi payloads" 295 │ // @audit #auth -- "Session token rotation logic needs cryptographic review" 296 │ // @assumes #auth -- "Upstream API gateway has already validated TLS and rate-limited requests" 297 │ // @owns security-team for #auth -- "Security team reviews all auth PRs" 298 │ // @comment -- "Password hashing uses bcrypt with cost factor 12, migration from SHA256 completed in v2.1" 299 │ // @shield:end 300 │ \`\`\` 301 │ 302 │ ## CRITICAL SYNTAX RULES (violations cause parse errors) 303 │ 304 │ 1. **@boundary requires TWO assets**: \`@boundary between #A and #B\` or \`@boundary #A | #B\`.
+
+
+
+
+
+ src/analyze/index.ts + + 10 + + +
+
+ +
+
+ L8 + exposes + #llm-client → #path-traversal +
+
buildProjectContext reads files from root-relative paths
+
3 │ * 4 │ * Serializes the threat model, sends it to an LLM with a framework- 5 │ * specific prompt, streams the response, and saves timestamped results 6 │ * to .guardlink/threat-reports/. 7 │ * 8 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "buildProjectContext reads files from root-relative paths" 9 │ * @mitigates #llm-client against #path-traversal using #path-validation -- "join() with root constrains file access" 10 │ * @exposes #llm-client to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync saves threat reports to .guardlink/" 11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis"
+
+
+
+ L9 + mitigates + #path-validation mitigates #path-traversal +
+
join() with root constrains file access
+
4 │ * Serializes the threat model, sends it to an LLM with a framework- 5 │ * specific prompt, streams the response, and saves timestamped results 6 │ * to .guardlink/threat-reports/. 7 │ * 8 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "buildProjectContext reads files from root-relative paths" 9 │ * @mitigates #llm-client against #path-traversal using #path-validation -- "join() with root constrains file access" 10 │ * @exposes #llm-client to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync saves threat reports to .guardlink/" 11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input"
+
+
+
+ L10 + exposes + #llm-client → #arbitrary-write +
+
writeFileSync saves threat reports to .guardlink/
+
5 │ * specific prompt, streams the response, and saves timestamped results 6 │ * to .guardlink/threat-reports/. 7 │ * 8 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "buildProjectContext reads files from root-relative paths" 9 │ * @mitigates #llm-client against #path-traversal using #path-validation -- "join() with root constrains file access" 10 │ * @exposes #llm-client to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync saves threat reports to .guardlink/" 11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input" 15 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Project context read"
+
+
+
+ L11 + mitigates + #path-validation mitigates #arbitrary-write +
+
Output path is fixed to .guardlink/threat-reports/
+
6 │ * to .guardlink/threat-reports/. 7 │ * 8 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "buildProjectContext reads files from root-relative paths" 9 │ * @mitigates #llm-client against #path-traversal using #path-validation -- "join() with root constrains file access" 10 │ * @exposes #llm-client to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync saves threat reports to .guardlink/" 11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input" 15 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Project context read" 16 │ * @flows #llm-client -> ReportFile via writeFileSync -- "Report output"
+
+
+
+ L12 + exposes + #llm-client → #data-exposure +
+
Serializes full threat model and code snippets for LLM
+
7 │ * 8 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "buildProjectContext reads files from root-relative paths" 9 │ * @mitigates #llm-client against #path-traversal using #path-validation -- "join() with root constrains file access" 10 │ * @exposes #llm-client to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync saves threat reports to .guardlink/" 11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input" 15 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Project context read" 16 │ * @flows #llm-client -> ReportFile via writeFileSync -- "Report output" 17 │ * @handles internal on #llm-client -- "Processes project dependencies, env examples, code snippets"
+
+
+
+ L13 + audit + Audit: #llm-client +
+
Threat model data intentionally sent to LLM for analysis
+
8 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "buildProjectContext reads files from root-relative paths" 9 │ * @mitigates #llm-client against #path-traversal using #path-validation -- "join() with root constrains file access" 10 │ * @exposes #llm-client to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync saves threat reports to .guardlink/" 11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input" 15 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Project context read" 16 │ * @flows #llm-client -> ReportFile via writeFileSync -- "Report output" 17 │ * @handles internal on #llm-client -- "Processes project dependencies, env examples, code snippets" 18 │ */
+
+
+
+ L14 + flow + ThreatModel → #llm-client +
+
Model serialization input
+
9 │ * @mitigates #llm-client against #path-traversal using #path-validation -- "join() with root constrains file access" 10 │ * @exposes #llm-client to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync saves threat reports to .guardlink/" 11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input" 15 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Project context read" 16 │ * @flows #llm-client -> ReportFile via writeFileSync -- "Report output" 17 │ * @handles internal on #llm-client -- "Processes project dependencies, env examples, code snippets" 18 │ */ 19 │
+
+
+
+ L15 + flow + ProjectFiles → #llm-client +
+
Project context read
+
10 │ * @exposes #llm-client to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync saves threat reports to .guardlink/" 11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input" 15 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Project context read" 16 │ * @flows #llm-client -> ReportFile via writeFileSync -- "Report output" 17 │ * @handles internal on #llm-client -- "Processes project dependencies, env examples, code snippets" 18 │ */ 19 │ 20 │ import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync } from 'node:fs';
+
+
+
+ L16 + flow + #llm-client → ReportFile +
+
Report output
+
11 │ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Output path is fixed to .guardlink/threat-reports/" 12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input" 15 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Project context read" 16 │ * @flows #llm-client -> ReportFile via writeFileSync -- "Report output" 17 │ * @handles internal on #llm-client -- "Processes project dependencies, env examples, code snippets" 18 │ */ 19 │ 20 │ import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync } from 'node:fs'; 21 │ import { join, relative } from 'node:path';
+
+
+
+ L17 + handles + #llm-client: internal +
+
Processes project dependencies, env examples, code snippets
+
12 │ * @exposes #llm-client to #data-exposure [low] cwe:CWE-200 -- "Serializes full threat model and code snippets for LLM" 13 │ * @audit #llm-client -- "Threat model data intentionally sent to LLM for analysis" 14 │ * @flows ThreatModel -> #llm-client via serializeModel -- "Model serialization input" 15 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Project context read" 16 │ * @flows #llm-client -> ReportFile via writeFileSync -- "Report output" 17 │ * @handles internal on #llm-client -- "Processes project dependencies, env examples, code snippets" 18 │ */ 19 │ 20 │ import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync } from 'node:fs'; 21 │ import { join, relative } from 'node:path'; 22 │ import type { ThreatModel } from '../types/index.js';
+
+
+
+
+
+ src/analyze/llm.ts + + 11 + + +
+
+ +
+
+ L13 + exposes + #llm-client → #ssrf +
+
fetch() calls external LLM API endpoints
+
8 │ * - OpenAI-compatible Chat Completions (DeepSeek, OpenRouter, Ollama) 9 │ * - DeepSeek reasoning mode (deepseek-reasoner) 10 │ * 11 │ * Zero dependencies — uses Node 20+ built-in fetch. 12 │ * 13 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "fetch() calls external LLM API endpoints" 14 │ * @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded; baseUrl override is optional config" 15 │ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "API keys passed in Authorization headers" 16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only"
+
+
+
+ L14 + mitigates + #config-validation mitigates #ssrf +
+
BASE_URLS are hardcoded; baseUrl override is optional config
+
9 │ * - DeepSeek reasoning mode (deepseek-reasoner) 10 │ * 11 │ * Zero dependencies — uses Node 20+ built-in fetch. 12 │ * 13 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "fetch() calls external LLM API endpoints" 14 │ * @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded; baseUrl override is optional config" 15 │ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "API keys passed in Authorization headers" 16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input"
+
+
+
+ L15 + exposes + #llm-client → #api-key-exposure +
+
API keys passed in Authorization headers
+
10 │ * 11 │ * Zero dependencies — uses Node 20+ built-in fetch. 12 │ * 13 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "fetch() calls external LLM API endpoints" 14 │ * @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded; baseUrl override is optional config" 15 │ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "API keys passed in Authorization headers" 16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output"
+
+
+
+ L16 + mitigates + #key-redaction mitigates #api-key-exposure +
+
Keys never logged; passed directly to API
+
11 │ * Zero dependencies — uses Node 20+ built-in fetch. 12 │ * 13 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "fetch() calls external LLM API endpoints" 14 │ * @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded; baseUrl override is optional config" 15 │ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "API keys passed in Authorization headers" 16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output" 21 │ * @flows LLMProvider -> #llm-client via response -- "API response input"
+
+
+
+ L17 + exposes + #llm-client → #prompt-injection +
+
User prompts sent to LLM API
+
12 │ * 13 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "fetch() calls external LLM API endpoints" 14 │ * @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded; baseUrl override is optional config" 15 │ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "API keys passed in Authorization headers" 16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output" 21 │ * @flows LLMProvider -> #llm-client via response -- "API response input" 22 │ * @boundary #llm-client and LLMProvider (#llm-api-boundary) -- "Trust boundary at external API call"
+
+
+
+ L18 + audit + Audit: #llm-client +
+
Prompt injection mitigated by LLM provider safety; local code is read-only
+
13 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "fetch() calls external LLM API endpoints" 14 │ * @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded; baseUrl override is optional config" 15 │ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "API keys passed in Authorization headers" 16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output" 21 │ * @flows LLMProvider -> #llm-client via response -- "API response input" 22 │ * @boundary #llm-client and LLMProvider (#llm-api-boundary) -- "Trust boundary at external API call" 23 │ * @handles secrets on #llm-client -- "Processes API keys for authentication"
+
+
+
+ L19 + flow + LLMConfig → #llm-client +
+
Config and prompt input
+
14 │ * @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded; baseUrl override is optional config" 15 │ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "API keys passed in Authorization headers" 16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output" 21 │ * @flows LLMProvider -> #llm-client via response -- "API response input" 22 │ * @boundary #llm-client and LLMProvider (#llm-api-boundary) -- "Trust boundary at external API call" 23 │ * @handles secrets on #llm-client -- "Processes API keys for authentication" 24 │ */
+
+
+
+ L20 + flow + #llm-client → LLMProvider +
+
API request output
+
15 │ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "API keys passed in Authorization headers" 16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output" 21 │ * @flows LLMProvider -> #llm-client via response -- "API response input" 22 │ * @boundary #llm-client and LLMProvider (#llm-api-boundary) -- "Trust boundary at external API call" 23 │ * @handles secrets on #llm-client -- "Processes API keys for authentication" 24 │ */ 25 │
+
+
+
+ L21 + flow + LLMProvider → #llm-client +
+
API response input
+
16 │ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys never logged; passed directly to API" 17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output" 21 │ * @flows LLMProvider -> #llm-client via response -- "API response input" 22 │ * @boundary #llm-client and LLMProvider (#llm-api-boundary) -- "Trust boundary at external API call" 23 │ * @handles secrets on #llm-client -- "Processes API keys for authentication" 24 │ */ 25 │ 26 │ export type LLMProvider = 'anthropic' | 'openai' | 'google' | 'openrouter' | 'deepseek' | 'ollama';
+
+
+
+ L22 + boundary + #llm-client ↔ LLMProvider +
+
Trust boundary at external API call
+
17 │ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "User prompts sent to LLM API" 18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output" 21 │ * @flows LLMProvider -> #llm-client via response -- "API response input" 22 │ * @boundary #llm-client and LLMProvider (#llm-api-boundary) -- "Trust boundary at external API call" 23 │ * @handles secrets on #llm-client -- "Processes API keys for authentication" 24 │ */ 25 │ 26 │ export type LLMProvider = 'anthropic' | 'openai' | 'google' | 'openrouter' | 'deepseek' | 'ollama'; 27 │
+
+
+
+ L23 + handles + #llm-client: secrets +
+
Processes API keys for authentication
+
18 │ * @audit #llm-client -- "Prompt injection mitigated by LLM provider safety; local code is read-only" 19 │ * @flows LLMConfig -> #llm-client via chatCompletion -- "Config and prompt input" 20 │ * @flows #llm-client -> LLMProvider via fetch -- "API request output" 21 │ * @flows LLMProvider -> #llm-client via response -- "API response input" 22 │ * @boundary #llm-client and LLMProvider (#llm-api-boundary) -- "Trust boundary at external API call" 23 │ * @handles secrets on #llm-client -- "Processes API keys for authentication" 24 │ */ 25 │ 26 │ export type LLMProvider = 'anthropic' | 'openai' | 'google' | 'openrouter' | 'deepseek' | 'ollama'; 27 │ 28 │ // ─── Tool definitions ────────────────────────────────────────────────
+
+
+
+
+
+ src/analyze/prompts.ts + + 2 + + +
+
+ +
+
+ L7 + comment + Prompt templates are static; no user input interpolation in system prompts +
+
Prompt templates are static; no user input interpolation in system prompts
+
2 │ * GuardLink Threat Reports — Framework-specific analysis prompts. 3 │ * 4 │ * Each framework produces a structured security analysis from the 5 │ * serialized threat model. The LLM acts as a senior security architect. 6 │ * 7 │ * @comment -- "Prompt templates are static; no user input interpolation in system prompts" 8 │ * @comment -- "customPrompt is appended to user message, not system prompt — bounded injection risk" 9 │ */ 10 │ 11 │ export type AnalysisFramework = 'stride' | 'dread' | 'pasta' | 'attacker' | 'rapid' | 'general'; 12 │
+
+
+
+ L8 + comment + customPrompt is appended to user message, not system prompt — bounded injection risk +
+
customPrompt is appended to user message, not system prompt — bounded injection risk
+
3 │ * 4 │ * Each framework produces a structured security analysis from the 5 │ * serialized threat model. The LLM acts as a senior security architect. 6 │ * 7 │ * @comment -- "Prompt templates are static; no user input interpolation in system prompts" 8 │ * @comment -- "customPrompt is appended to user message, not system prompt — bounded injection risk" 9 │ */ 10 │ 11 │ export type AnalysisFramework = 'stride' | 'dread' | 'pasta' | 'attacker' | 'rapid' | 'general'; 12 │ 13 │ export const FRAMEWORK_LABELS: Record<AnalysisFramework, string> = {
+
+
+
+
+
+ src/analyze/tools.ts + + 10 + + +
+
+ +
+
+ L9 + exposes + #llm-client → #ssrf +
+
lookupCve fetches from NVD API with user-controlled CVE ID
+
4 │ * Defines tools that the LLM can invoke during threat analysis: 5 │ * - lookup_cve: Search for CVE details (via web fetch) 6 │ * - validate_finding: Cross-reference a finding against the parsed model 7 │ * - search_codebase: Search project files for patterns 8 │ * 9 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "lookupCve fetches from NVD API with user-controlled CVE ID" 10 │ * @mitigates #llm-client against #ssrf using #input-sanitize -- "CVE ID validated with strict regex; URL hardcoded to NVD" 11 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "searchCodebase reads files from project root" 12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter"
+
+
+
+ L10 + mitigates + #input-sanitize mitigates #ssrf +
+
CVE ID validated with strict regex; URL hardcoded to NVD
+
5 │ * - lookup_cve: Search for CVE details (via web fetch) 6 │ * - validate_finding: Cross-reference a finding against the parsed model 7 │ * - search_codebase: Search project files for patterns 8 │ * 9 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "lookupCve fetches from NVD API with user-controlled CVE ID" 10 │ * @mitigates #llm-client against #ssrf using #input-sanitize -- "CVE ID validated with strict regex; URL hardcoded to NVD" 11 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "searchCodebase reads files from project root" 12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input"
+
+
+
+ L11 + exposes + #llm-client → #path-traversal +
+
searchCodebase reads files from project root
+
6 │ * - validate_finding: Cross-reference a finding against the parsed model 7 │ * - search_codebase: Search project files for patterns 8 │ * 9 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "lookupCve fetches from NVD API with user-controlled CVE ID" 10 │ * @mitigates #llm-client against #ssrf using #input-sanitize -- "CVE ID validated with strict regex; URL hardcoded to NVD" 11 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "searchCodebase reads files from project root" 12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input" 16 │ * @flows #llm-client -> NVD via fetch -- "CVE lookup API call"
+
+
+
+ L12 + mitigates + #glob-filtering mitigates #path-traversal +
+
skipDirs excludes sensitive directories; relative() bounds output
+
7 │ * - search_codebase: Search project files for patterns 8 │ * 9 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "lookupCve fetches from NVD API with user-controlled CVE ID" 10 │ * @mitigates #llm-client against #ssrf using #input-sanitize -- "CVE ID validated with strict regex; URL hardcoded to NVD" 11 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "searchCodebase reads files from project root" 12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input" 16 │ * @flows #llm-client -> NVD via fetch -- "CVE lookup API call" 17 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Codebase search reads"
+
+
+
+ L13 + exposes + #llm-client → #dos +
+
searchCodebase reads many files; bounded by maxResults
+
8 │ * 9 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "lookupCve fetches from NVD API with user-controlled CVE ID" 10 │ * @mitigates #llm-client against #ssrf using #input-sanitize -- "CVE ID validated with strict regex; URL hardcoded to NVD" 11 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "searchCodebase reads files from project root" 12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input" 16 │ * @flows #llm-client -> NVD via fetch -- "CVE lookup API call" 17 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Codebase search reads" 18 │ * @boundary #llm-client and NVD (#nvd-api-boundary) -- "Trust boundary at external API"
+
+
+
+ L14 + mitigates + #resource-limits mitigates #dos +
+
maxResults caps output; stat.size < 500KB filter
+
9 │ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "lookupCve fetches from NVD API with user-controlled CVE ID" 10 │ * @mitigates #llm-client against #ssrf using #input-sanitize -- "CVE ID validated with strict regex; URL hardcoded to NVD" 11 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "searchCodebase reads files from project root" 12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input" 16 │ * @flows #llm-client -> NVD via fetch -- "CVE lookup API call" 17 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Codebase search reads" 18 │ * @boundary #llm-client and NVD (#nvd-api-boundary) -- "Trust boundary at external API" 19 │ */
+
+
+
+ L15 + flow + LLMToolCall → #llm-client +
+
Tool invocation input
+
10 │ * @mitigates #llm-client against #ssrf using #input-sanitize -- "CVE ID validated with strict regex; URL hardcoded to NVD" 11 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "searchCodebase reads files from project root" 12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input" 16 │ * @flows #llm-client -> NVD via fetch -- "CVE lookup API call" 17 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Codebase search reads" 18 │ * @boundary #llm-client and NVD (#nvd-api-boundary) -- "Trust boundary at external API" 19 │ */ 20 │
+
+
+
+ L16 + flow + #llm-client → NVD +
+
CVE lookup API call
+
11 │ * @exposes #llm-client to #path-traversal [medium] cwe:CWE-22 -- "searchCodebase reads files from project root" 12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input" 16 │ * @flows #llm-client -> NVD via fetch -- "CVE lookup API call" 17 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Codebase search reads" 18 │ * @boundary #llm-client and NVD (#nvd-api-boundary) -- "Trust boundary at external API" 19 │ */ 20 │ 21 │ import { readFileSync, readdirSync, statSync } from 'node:fs';
+
+
+
+ L17 + flow + ProjectFiles → #llm-client +
+
Codebase search reads
+
12 │ * @mitigates #llm-client against #path-traversal using #glob-filtering -- "skipDirs excludes sensitive directories; relative() bounds output" 13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input" 16 │ * @flows #llm-client -> NVD via fetch -- "CVE lookup API call" 17 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Codebase search reads" 18 │ * @boundary #llm-client and NVD (#nvd-api-boundary) -- "Trust boundary at external API" 19 │ */ 20 │ 21 │ import { readFileSync, readdirSync, statSync } from 'node:fs'; 22 │ import { join, relative } from 'node:path';
+
+
+
+ L18 + boundary + #llm-client ↔ NVD +
+
Trust boundary at external API
+
13 │ * @exposes #llm-client to #dos [low] cwe:CWE-400 -- "searchCodebase reads many files; bounded by maxResults" 14 │ * @mitigates #llm-client against #dos using #resource-limits -- "maxResults caps output; stat.size < 500KB filter" 15 │ * @flows LLMToolCall -> #llm-client via createToolExecutor -- "Tool invocation input" 16 │ * @flows #llm-client -> NVD via fetch -- "CVE lookup API call" 17 │ * @flows ProjectFiles -> #llm-client via readFileSync -- "Codebase search reads" 18 │ * @boundary #llm-client and NVD (#nvd-api-boundary) -- "Trust boundary at external API" 19 │ */ 20 │ 21 │ import { readFileSync, readdirSync, statSync } from 'node:fs'; 22 │ import { join, relative } from 'node:path'; 23 │ import type { ToolDefinition, ToolExecutor } from './llm.js';
+
+
+
+
+
+ src/analyzer/index.ts + + 2 + + +
+
+ +
+
+ L4 + comment + SARIF generation is pure transformation; no I/O in this module +
+
SARIF generation is pure transformation; no I/O in this module
+
1 │ /** 2 │ * GuardLink Analyzer — exports. 3 │ * 4 │ * @comment -- "SARIF generation is pure transformation; no I/O in this module" 5 │ * @comment -- "File writes handled by CLI/MCP callers" 6 │ */ 7 │ 8 │ export { generateSarif, type SarifOptions } from './sarif.js'; 9 │
+
+
+
+ L5 + comment + File writes handled by CLI/MCP callers +
+
File writes handled by CLI/MCP callers
+
1 │ /** 2 │ * GuardLink Analyzer — exports. 3 │ * 4 │ * @comment -- "SARIF generation is pure transformation; no I/O in this module" 5 │ * @comment -- "File writes handled by CLI/MCP callers" 6 │ */ 7 │ 8 │ export { generateSarif, type SarifOptions } from './sarif.js'; 9 │
+
+
+
+
+
+ src/analyzer/sarif.ts + + 5 + + +
+
+ +
+
+ L15 + exposes + #sarif → #data-exposure +
+
Exposes threat model findings to SARIF consumers
+
10 │ * We emit results for: 11 │ * 1. Unmitigated exposures (the primary security findings) 12 │ * 2. Parse errors (annotation syntax problems) 13 │ * 3. Dangling references (broken #id refs) 14 │ * 15 │ * @exposes #sarif to #data-exposure [low] cwe:CWE-200 -- "Exposes threat model findings to SARIF consumers" 16 │ * @audit #sarif -- "SARIF output intentionally reveals security findings for CI/CD integration" 17 │ * @comment -- "Pure function: transforms ThreatModel to SARIF JSON; no I/O" 18 │ * @flows ThreatModel -> #sarif via generateSarif -- "Model input" 19 │ * @flows #sarif -> SarifLog via return -- "SARIF output" 20 │ */
+
+
+
+ L16 + audit + Audit: #sarif +
+
SARIF output intentionally reveals security findings for CI/CD integration
+
11 │ * 1. Unmitigated exposures (the primary security findings) 12 │ * 2. Parse errors (annotation syntax problems) 13 │ * 3. Dangling references (broken #id refs) 14 │ * 15 │ * @exposes #sarif to #data-exposure [low] cwe:CWE-200 -- "Exposes threat model findings to SARIF consumers" 16 │ * @audit #sarif -- "SARIF output intentionally reveals security findings for CI/CD integration" 17 │ * @comment -- "Pure function: transforms ThreatModel to SARIF JSON; no I/O" 18 │ * @flows ThreatModel -> #sarif via generateSarif -- "Model input" 19 │ * @flows #sarif -> SarifLog via return -- "SARIF output" 20 │ */ 21 │
+
+
+
+ L17 + comment + Pure function: transforms ThreatModel to SARIF JSON; no I/O +
+
Pure function: transforms ThreatModel to SARIF JSON; no I/O
+
12 │ * 2. Parse errors (annotation syntax problems) 13 │ * 3. Dangling references (broken #id refs) 14 │ * 15 │ * @exposes #sarif to #data-exposure [low] cwe:CWE-200 -- "Exposes threat model findings to SARIF consumers" 16 │ * @audit #sarif -- "SARIF output intentionally reveals security findings for CI/CD integration" 17 │ * @comment -- "Pure function: transforms ThreatModel to SARIF JSON; no I/O" 18 │ * @flows ThreatModel -> #sarif via generateSarif -- "Model input" 19 │ * @flows #sarif -> SarifLog via return -- "SARIF output" 20 │ */ 21 │ 22 │ import type { ThreatModel, ThreatModelExposure, ParseDiagnostic, Severity } from '../types/index.js';
+
+
+
+ L18 + flow + ThreatModel → #sarif +
+
Model input
+
13 │ * 3. Dangling references (broken #id refs) 14 │ * 15 │ * @exposes #sarif to #data-exposure [low] cwe:CWE-200 -- "Exposes threat model findings to SARIF consumers" 16 │ * @audit #sarif -- "SARIF output intentionally reveals security findings for CI/CD integration" 17 │ * @comment -- "Pure function: transforms ThreatModel to SARIF JSON; no I/O" 18 │ * @flows ThreatModel -> #sarif via generateSarif -- "Model input" 19 │ * @flows #sarif -> SarifLog via return -- "SARIF output" 20 │ */ 21 │ 22 │ import type { ThreatModel, ThreatModelExposure, ParseDiagnostic, Severity } from '../types/index.js'; 23 │
+
+
+
+ L19 + flow + #sarif → SarifLog +
+
SARIF output
+
14 │ * 15 │ * @exposes #sarif to #data-exposure [low] cwe:CWE-200 -- "Exposes threat model findings to SARIF consumers" 16 │ * @audit #sarif -- "SARIF output intentionally reveals security findings for CI/CD integration" 17 │ * @comment -- "Pure function: transforms ThreatModel to SARIF JSON; no I/O" 18 │ * @flows ThreatModel -> #sarif via generateSarif -- "Model input" 19 │ * @flows #sarif -> SarifLog via return -- "SARIF output" 20 │ */ 21 │ 22 │ import type { ThreatModel, ThreatModelExposure, ParseDiagnostic, Severity } from '../types/index.js'; 23 │ 24 │ // ─── SARIF 2.1.0 types (subset) ─────────────────────────────────────
+
+
+
+
+
+ src/cli/index.ts + + 12 + + +
+
+ +
+
+ L25 + exposes + #cli → #path-traversal +
+
User-supplied dir argument resolved via path.resolve
+
20 │ * guardlink tui [dir] Interactive TUI with slash commands + AI chat 21 │ * guardlink gal Display GAL annotation language quick reference 22 │ * guardlink link-project <repos...> Link repos into a shared workspace 23 │ * guardlink merge <files...> Merge repo reports into unified dashboard 24 │ * 25 │ * @exposes #cli to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 26 │ * @mitigates #cli against #path-traversal using #path-validation -- "resolve() canonicalizes paths; cwd-relative by design" 27 │ * @exposes #cli to #arbitrary-write [high] cwe:CWE-73 -- "init/report/sarif/dashboard write files to user-specified paths" 28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output"
+
+
+
+ L26 + mitigates + #path-validation mitigates #path-traversal +
+
resolve() canonicalizes paths; cwd-relative by design
+
21 │ * guardlink gal Display GAL annotation language quick reference 22 │ * guardlink link-project <repos...> Link repos into a shared workspace 23 │ * guardlink merge <files...> Merge repo reports into unified dashboard 24 │ * 25 │ * @exposes #cli to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 26 │ * @mitigates #cli against #path-traversal using #path-validation -- "resolve() canonicalizes paths; cwd-relative by design" 27 │ * @exposes #cli to #arbitrary-write [high] cwe:CWE-73 -- "init/report/sarif/dashboard write files to user-specified paths" 28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes"
+
+
+
+ L27 + exposes + #cli → #arbitrary-write +
+
init/report/sarif/dashboard write files to user-specified paths
+
22 │ * guardlink link-project <repos...> Link repos into a shared workspace 23 │ * guardlink merge <files...> Merge repo reports into unified dashboard 24 │ * 25 │ * @exposes #cli to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 26 │ * @mitigates #cli against #path-traversal using #path-validation -- "resolve() canonicalizes paths; cwd-relative by design" 27 │ * @exposes #cli to #arbitrary-write [high] cwe:CWE-73 -- "init/report/sarif/dashboard write files to user-specified paths" 28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args"
+
+
+
+ L28 + mitigates + #path-validation mitigates #arbitrary-write +
+
Output paths resolved relative to project root
+
23 │ * guardlink merge <files...> Merge repo reports into unified dashboard 24 │ * 25 │ * @exposes #cli to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 26 │ * @mitigates #cli against #path-traversal using #path-validation -- "resolve() canonicalizes paths; cwd-relative by design" 27 │ * @exposes #cli to #arbitrary-write [high] cwe:CWE-73 -- "init/report/sarif/dashboard write files to user-specified paths" 28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path"
+
+
+
+ L29 + exposes + #cli → #api-key-exposure +
+
API keys handled in config set/show commands
+
24 │ * 25 │ * @exposes #cli to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 26 │ * @mitigates #cli against #path-traversal using #path-validation -- "resolve() canonicalizes paths; cwd-relative by design" 27 │ * @exposes #cli to #arbitrary-write [high] cwe:CWE-73 -- "init/report/sarif/dashboard write files to user-specified paths" 28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path" 34 │ * @flows #cli -> FileSystem via writeFile -- "Report/config output path"
+
+
+
+ L30 + mitigates + #key-redaction mitigates #api-key-exposure +
+
maskKey() redacts keys in show output
+
25 │ * @exposes #cli to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 26 │ * @mitigates #cli against #path-traversal using #path-validation -- "resolve() canonicalizes paths; cwd-relative by design" 27 │ * @exposes #cli to #arbitrary-write [high] cwe:CWE-73 -- "init/report/sarif/dashboard write files to user-specified paths" 28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path" 34 │ * @flows #cli -> FileSystem via writeFile -- "Report/config output path" 35 │ * @boundary #cli and UserInput (#cli-input-boundary) -- "Trust boundary at CLI argument parsing"
+
+
+
+ L31 + exposes + #cli → #cmd-injection +
+
Agent launcher spawns child processes
+
26 │ * @mitigates #cli against #path-traversal using #path-validation -- "resolve() canonicalizes paths; cwd-relative by design" 27 │ * @exposes #cli to #arbitrary-write [high] cwe:CWE-73 -- "init/report/sarif/dashboard write files to user-specified paths" 28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path" 34 │ * @flows #cli -> FileSystem via writeFile -- "Report/config output path" 35 │ * @boundary #cli and UserInput (#cli-input-boundary) -- "Trust boundary at CLI argument parsing" 36 │ * @handles secrets on #cli -- "Processes API keys via config commands"
+
+
+
+ L32 + audit + Audit: #cli +
+
Child process spawning delegated to agents/launcher.ts with explicit args
+
27 │ * @exposes #cli to #arbitrary-write [high] cwe:CWE-73 -- "init/report/sarif/dashboard write files to user-specified paths" 28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path" 34 │ * @flows #cli -> FileSystem via writeFile -- "Report/config output path" 35 │ * @boundary #cli and UserInput (#cli-input-boundary) -- "Trust boundary at CLI argument parsing" 36 │ * @handles secrets on #cli -- "Processes API keys via config commands" 37 │ */
+
+
+
+ L33 + flow + UserArgs → #cli +
+
CLI argument input path
+
28 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path" 34 │ * @flows #cli -> FileSystem via writeFile -- "Report/config output path" 35 │ * @boundary #cli and UserInput (#cli-input-boundary) -- "Trust boundary at CLI argument parsing" 36 │ * @handles secrets on #cli -- "Processes API keys via config commands" 37 │ */ 38 │
+
+
+
+ L34 + flow + #cli → FileSystem +
+
Report/config output path
+
29 │ * @exposes #cli to #api-key-exposure [high] cwe:CWE-798 -- "API keys handled in config set/show commands" 30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path" 34 │ * @flows #cli -> FileSystem via writeFile -- "Report/config output path" 35 │ * @boundary #cli and UserInput (#cli-input-boundary) -- "Trust boundary at CLI argument parsing" 36 │ * @handles secrets on #cli -- "Processes API keys via config commands" 37 │ */ 38 │ 39 │ import { Command } from 'commander';
+
+
+
+ L35 + boundary + #cli ↔ UserInput +
+
Trust boundary at CLI argument parsing
+
30 │ * @mitigates #cli against #api-key-exposure using #key-redaction -- "maskKey() redacts keys in show output" 31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path" 34 │ * @flows #cli -> FileSystem via writeFile -- "Report/config output path" 35 │ * @boundary #cli and UserInput (#cli-input-boundary) -- "Trust boundary at CLI argument parsing" 36 │ * @handles secrets on #cli -- "Processes API keys via config commands" 37 │ */ 38 │ 39 │ import { Command } from 'commander'; 40 │ import { resolve, basename } from 'node:path';
+
+
+
+ L36 + handles + #cli: secrets +
+
Processes API keys via config commands
+
31 │ * @exposes #cli to #cmd-injection [critical] cwe:CWE-78 -- "Agent launcher spawns child processes" 32 │ * @audit #cli -- "Child process spawning delegated to agents/launcher.ts with explicit args" 33 │ * @flows UserArgs -> #cli via process.argv -- "CLI argument input path" 34 │ * @flows #cli -> FileSystem via writeFile -- "Report/config output path" 35 │ * @boundary #cli and UserInput (#cli-input-boundary) -- "Trust boundary at CLI argument parsing" 36 │ * @handles secrets on #cli -- "Processes API keys via config commands" 37 │ */ 38 │ 39 │ import { Command } from 'commander'; 40 │ import { resolve, basename } from 'node:path'; 41 │ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
+
+
+
+
+
+ src/dashboard/generate.ts + + 8 + + +
+
+ +
+
+ L8 + exposes + #dashboard → #xss +
+
Generates HTML with user-controlled threat model data
+
3 │ * 4 │ * Sidebar navigation + drawer detail panel + dark/light toggle. 5 │ * 7 pages: Summary, AI Analysis, Threats, Diagrams, Code, Data, Assets. 6 │ * Mermaid.js via CDN for diagrams. Zero build step. 7 │ * 8 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with user-controlled threat model data" 9 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() HTML-encodes all interpolated values" 10 │ * @exposes #dashboard to #path-traversal [medium] cwe:CWE-22 -- "readFileSync reads code files for annotation context" 11 │ * @mitigates #dashboard against #path-traversal using #path-validation -- "resolve() with root constrains file access" 12 │ * @flows ThreatModel -> #dashboard via computeStats -- "Model statistics input" 13 │ * @flows SourceFiles -> #dashboard via readFileSync -- "Code snippet reads"
+
+
+
+ L9 + mitigates + #output-encoding mitigates #xss +
+
esc() HTML-encodes all interpolated values
+
4 │ * Sidebar navigation + drawer detail panel + dark/light toggle. 5 │ * 7 pages: Summary, AI Analysis, Threats, Diagrams, Code, Data, Assets. 6 │ * Mermaid.js via CDN for diagrams. Zero build step. 7 │ * 8 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with user-controlled threat model data" 9 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() HTML-encodes all interpolated values" 10 │ * @exposes #dashboard to #path-traversal [medium] cwe:CWE-22 -- "readFileSync reads code files for annotation context" 11 │ * @mitigates #dashboard against #path-traversal using #path-validation -- "resolve() with root constrains file access" 12 │ * @flows ThreatModel -> #dashboard via computeStats -- "Model statistics input" 13 │ * @flows SourceFiles -> #dashboard via readFileSync -- "Code snippet reads" 14 │ * @flows #dashboard -> HTML via return -- "Generated HTML output"
+
+
+
+ L10 + exposes + #dashboard → #path-traversal +
+
readFileSync reads code files for annotation context
+
5 │ * 7 pages: Summary, AI Analysis, Threats, Diagrams, Code, Data, Assets. 6 │ * Mermaid.js via CDN for diagrams. Zero build step. 7 │ * 8 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with user-controlled threat model data" 9 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() HTML-encodes all interpolated values" 10 │ * @exposes #dashboard to #path-traversal [medium] cwe:CWE-22 -- "readFileSync reads code files for annotation context" 11 │ * @mitigates #dashboard against #path-traversal using #path-validation -- "resolve() with root constrains file access" 12 │ * @flows ThreatModel -> #dashboard via computeStats -- "Model statistics input" 13 │ * @flows SourceFiles -> #dashboard via readFileSync -- "Code snippet reads" 14 │ * @flows #dashboard -> HTML via return -- "Generated HTML output" 15 │ * @handles internal on #dashboard -- "Processes and displays threat model data"
+
+
+
+ L11 + mitigates + #path-validation mitigates #path-traversal +
+
resolve() with root constrains file access
+
6 │ * Mermaid.js via CDN for diagrams. Zero build step. 7 │ * 8 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with user-controlled threat model data" 9 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() HTML-encodes all interpolated values" 10 │ * @exposes #dashboard to #path-traversal [medium] cwe:CWE-22 -- "readFileSync reads code files for annotation context" 11 │ * @mitigates #dashboard against #path-traversal using #path-validation -- "resolve() with root constrains file access" 12 │ * @flows ThreatModel -> #dashboard via computeStats -- "Model statistics input" 13 │ * @flows SourceFiles -> #dashboard via readFileSync -- "Code snippet reads" 14 │ * @flows #dashboard -> HTML via return -- "Generated HTML output" 15 │ * @handles internal on #dashboard -- "Processes and displays threat model data" 16 │ */
+
+
+
+ L12 + flow + ThreatModel → #dashboard +
+
Model statistics input
+
7 │ * 8 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with user-controlled threat model data" 9 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() HTML-encodes all interpolated values" 10 │ * @exposes #dashboard to #path-traversal [medium] cwe:CWE-22 -- "readFileSync reads code files for annotation context" 11 │ * @mitigates #dashboard against #path-traversal using #path-validation -- "resolve() with root constrains file access" 12 │ * @flows ThreatModel -> #dashboard via computeStats -- "Model statistics input" 13 │ * @flows SourceFiles -> #dashboard via readFileSync -- "Code snippet reads" 14 │ * @flows #dashboard -> HTML via return -- "Generated HTML output" 15 │ * @handles internal on #dashboard -- "Processes and displays threat model data" 16 │ */ 17 │
+
+
+
+ L13 + flow + SourceFiles → #dashboard +
+
Code snippet reads
+
8 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with user-controlled threat model data" 9 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() HTML-encodes all interpolated values" 10 │ * @exposes #dashboard to #path-traversal [medium] cwe:CWE-22 -- "readFileSync reads code files for annotation context" 11 │ * @mitigates #dashboard against #path-traversal using #path-validation -- "resolve() with root constrains file access" 12 │ * @flows ThreatModel -> #dashboard via computeStats -- "Model statistics input" 13 │ * @flows SourceFiles -> #dashboard via readFileSync -- "Code snippet reads" 14 │ * @flows #dashboard -> HTML via return -- "Generated HTML output" 15 │ * @handles internal on #dashboard -- "Processes and displays threat model data" 16 │ */ 17 │ 18 │ import type { ThreatModel } from '../types/index.js';
+
+
+
+ L14 + flow + #dashboard → HTML +
+
Generated HTML output
+
9 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() HTML-encodes all interpolated values" 10 │ * @exposes #dashboard to #path-traversal [medium] cwe:CWE-22 -- "readFileSync reads code files for annotation context" 11 │ * @mitigates #dashboard against #path-traversal using #path-validation -- "resolve() with root constrains file access" 12 │ * @flows ThreatModel -> #dashboard via computeStats -- "Model statistics input" 13 │ * @flows SourceFiles -> #dashboard via readFileSync -- "Code snippet reads" 14 │ * @flows #dashboard -> HTML via return -- "Generated HTML output" 15 │ * @handles internal on #dashboard -- "Processes and displays threat model data" 16 │ */ 17 │ 18 │ import type { ThreatModel } from '../types/index.js'; 19 │ import { computeStats, computeSeverity, computeExposures, computeAssetHeatmap } from './data.js';
+
+
+
+ L15 + handles + #dashboard: internal +
+
Processes and displays threat model data
+
10 │ * @exposes #dashboard to #path-traversal [medium] cwe:CWE-22 -- "readFileSync reads code files for annotation context" 11 │ * @mitigates #dashboard against #path-traversal using #path-validation -- "resolve() with root constrains file access" 12 │ * @flows ThreatModel -> #dashboard via computeStats -- "Model statistics input" 13 │ * @flows SourceFiles -> #dashboard via readFileSync -- "Code snippet reads" 14 │ * @flows #dashboard -> HTML via return -- "Generated HTML output" 15 │ * @handles internal on #dashboard -- "Processes and displays threat model data" 16 │ */ 17 │ 18 │ import type { ThreatModel } from '../types/index.js'; 19 │ import { computeStats, computeSeverity, computeExposures, computeAssetHeatmap } from './data.js'; 20 │ import type { DashboardStats, SeverityBreakdown, ExposureRow, AssetHeatmapEntry } from './data.js';
+
+
+
+
+
+ src/dashboard/index.ts + + 4 + + +
+
+ +
+
+ L4 + exposes + #dashboard → #xss +
+
Generates HTML with threat model data
+
1 │ /** 2 │ * GuardLink Dashboard — Self-contained HTML threat model dashboard. 3 │ * 4 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with threat model data" 5 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() function encodes all interpolated values" 6 │ * @flows ThreatModel -> #dashboard via generateDashboardHTML -- "Model to HTML transformation" 7 │ * @comment -- "Self-contained HTML; no external data injection after generation" 8 │ */ 9 │
+
+
+
+ L5 + mitigates + #output-encoding mitigates #xss +
+
esc() function encodes all interpolated values
+
1 │ /** 2 │ * GuardLink Dashboard — Self-contained HTML threat model dashboard. 3 │ * 4 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with threat model data" 5 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() function encodes all interpolated values" 6 │ * @flows ThreatModel -> #dashboard via generateDashboardHTML -- "Model to HTML transformation" 7 │ * @comment -- "Self-contained HTML; no external data injection after generation" 8 │ */ 9 │ 10 │ export { generateDashboardHTML } from './generate.js';
+
+
+
+ L6 + flow + ThreatModel → #dashboard +
+
Model to HTML transformation
+
1 │ /** 2 │ * GuardLink Dashboard — Self-contained HTML threat model dashboard. 3 │ * 4 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with threat model data" 5 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() function encodes all interpolated values" 6 │ * @flows ThreatModel -> #dashboard via generateDashboardHTML -- "Model to HTML transformation" 7 │ * @comment -- "Self-contained HTML; no external data injection after generation" 8 │ */ 9 │ 10 │ export { generateDashboardHTML } from './generate.js'; 11 │ export { computeStats, computeSeverity, computeExposures, computeAssetHeatmap } from './data.js';
+
+
+
+ L7 + comment + Self-contained HTML; no external data injection after generation +
+
Self-contained HTML; no external data injection after generation
+
2 │ * GuardLink Dashboard — Self-contained HTML threat model dashboard. 3 │ * 4 │ * @exposes #dashboard to #xss [high] cwe:CWE-79 -- "Generates HTML with threat model data" 5 │ * @mitigates #dashboard against #xss using #output-encoding -- "esc() function encodes all interpolated values" 6 │ * @flows ThreatModel -> #dashboard via generateDashboardHTML -- "Model to HTML transformation" 7 │ * @comment -- "Self-contained HTML; no external data injection after generation" 8 │ */ 9 │ 10 │ export { generateDashboardHTML } from './generate.js'; 11 │ export { computeStats, computeSeverity, computeExposures, computeAssetHeatmap } from './data.js'; 12 │ export { generateThreatGraph, generateDataFlowDiagram, generateAttackSurface } from './diagrams.js';
+
+
+
+
+
+ src/diff/git.ts + + 10 + + +
+
+ +
+
+ L6 + exposes + #diff → #cmd-injection +
+
execSync runs git commands with ref argument
+
1 │ /** 2 │ * GuardLink Diff — Git integration. 3 │ * Resolves git refs to threat models by checking out files at a given commit 4 │ * and parsing them in a temp directory. 5 │ * 6 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "execSync runs git commands with ref argument" 7 │ * @mitigates #diff against #cmd-injection using #input-sanitize -- "rev-parse validates ref exists before use in other commands" 8 │ * @exposes #diff to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync creates files in temp directory" 9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree"
+
+
+
+ L7 + mitigates + #input-sanitize mitigates #cmd-injection +
+
rev-parse validates ref exists before use in other commands
+
2 │ * GuardLink Diff — Git integration. 3 │ * Resolves git refs to threat models by checking out files at a given commit 4 │ * and parsing them in a temp directory. 5 │ * 6 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "execSync runs git commands with ref argument" 7 │ * @mitigates #diff against #cmd-injection using #input-sanitize -- "rev-parse validates ref exists before use in other commands" 8 │ * @exposes #diff to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync creates files in temp directory" 9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution"
+
+
+
+ L8 + exposes + #diff → #arbitrary-write +
+
writeFileSync creates files in temp directory
+
3 │ * Resolves git refs to threat models by checking out files at a given commit 4 │ * and parsing them in a temp directory. 5 │ * 6 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "execSync runs git commands with ref argument" 7 │ * @mitigates #diff against #cmd-injection using #input-sanitize -- "rev-parse validates ref exists before use in other commands" 8 │ * @exposes #diff to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync creates files in temp directory" 9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution" 13 │ * @flows #diff -> TempDir via writeFileSync -- "Extracted file writes"
+
+
+
+ L9 + mitigates + #path-validation mitigates #arbitrary-write +
+
mkdtempSync creates isolated temp dir; rmSync cleans up
+
4 │ * and parsing them in a temp directory. 5 │ * 6 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "execSync runs git commands with ref argument" 7 │ * @mitigates #diff against #cmd-injection using #input-sanitize -- "rev-parse validates ref exists before use in other commands" 8 │ * @exposes #diff to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync creates files in temp directory" 9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution" 13 │ * @flows #diff -> TempDir via writeFileSync -- "Extracted file writes" 14 │ * @flows #diff -> ThreatModel via parseProject -- "Parsed model output"
+
+
+
+ L10 + exposes + #diff → #path-traversal +
+
git show extracts files based on ls-tree output
+
5 │ * 6 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "execSync runs git commands with ref argument" 7 │ * @mitigates #diff against #cmd-injection using #input-sanitize -- "rev-parse validates ref exists before use in other commands" 8 │ * @exposes #diff to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync creates files in temp directory" 9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution" 13 │ * @flows #diff -> TempDir via writeFileSync -- "Extracted file writes" 14 │ * @flows #diff -> ThreatModel via parseProject -- "Parsed model output" 15 │ * @boundary #diff and GitRepo (#git-boundary) -- "Trust boundary at git command execution"
+
+
+
+ L11 + mitigates + #glob-filtering mitigates #path-traversal +
+
Files constrained to relevantFiles from git ls-tree
+
6 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "execSync runs git commands with ref argument" 7 │ * @mitigates #diff against #cmd-injection using #input-sanitize -- "rev-parse validates ref exists before use in other commands" 8 │ * @exposes #diff to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync creates files in temp directory" 9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution" 13 │ * @flows #diff -> TempDir via writeFileSync -- "Extracted file writes" 14 │ * @flows #diff -> ThreatModel via parseProject -- "Parsed model output" 15 │ * @boundary #diff and GitRepo (#git-boundary) -- "Trust boundary at git command execution" 16 │ */
+
+
+
+ L12 + flow + GitRef → #diff +
+
Git command execution
+
7 │ * @mitigates #diff against #cmd-injection using #input-sanitize -- "rev-parse validates ref exists before use in other commands" 8 │ * @exposes #diff to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync creates files in temp directory" 9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution" 13 │ * @flows #diff -> TempDir via writeFileSync -- "Extracted file writes" 14 │ * @flows #diff -> ThreatModel via parseProject -- "Parsed model output" 15 │ * @boundary #diff and GitRepo (#git-boundary) -- "Trust boundary at git command execution" 16 │ */ 17 │
+
+
+
+ L13 + flow + #diff → TempDir +
+
Extracted file writes
+
8 │ * @exposes #diff to #arbitrary-write [medium] cwe:CWE-73 -- "writeFileSync creates files in temp directory" 9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution" 13 │ * @flows #diff -> TempDir via writeFileSync -- "Extracted file writes" 14 │ * @flows #diff -> ThreatModel via parseProject -- "Parsed model output" 15 │ * @boundary #diff and GitRepo (#git-boundary) -- "Trust boundary at git command execution" 16 │ */ 17 │ 18 │ import { execSync } from 'node:child_process';
+
+
+
+ L14 + flow + #diff → ThreatModel +
+
Parsed model output
+
9 │ * @mitigates #diff against #arbitrary-write using #path-validation -- "mkdtempSync creates isolated temp dir; rmSync cleans up" 10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution" 13 │ * @flows #diff -> TempDir via writeFileSync -- "Extracted file writes" 14 │ * @flows #diff -> ThreatModel via parseProject -- "Parsed model output" 15 │ * @boundary #diff and GitRepo (#git-boundary) -- "Trust boundary at git command execution" 16 │ */ 17 │ 18 │ import { execSync } from 'node:child_process'; 19 │ import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'node:fs';
+
+
+
+ L15 + boundary + #diff ↔ GitRepo +
+
Trust boundary at git command execution
+
10 │ * @exposes #diff to #path-traversal [medium] cwe:CWE-22 -- "git show extracts files based on ls-tree output" 11 │ * @mitigates #diff against #path-traversal using #glob-filtering -- "Files constrained to relevantFiles from git ls-tree" 12 │ * @flows GitRef -> #diff via execSync -- "Git command execution" 13 │ * @flows #diff -> TempDir via writeFileSync -- "Extracted file writes" 14 │ * @flows #diff -> ThreatModel via parseProject -- "Parsed model output" 15 │ * @boundary #diff and GitRepo (#git-boundary) -- "Trust boundary at git command execution" 16 │ */ 17 │ 18 │ import { execSync } from 'node:child_process'; 19 │ import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'node:fs'; 20 │ import { join } from 'node:path';
+
+
+
+
+
+ src/diff/index.ts + + 3 + + +
+
+ +
+
+ L4 + exposes + #diff → #cmd-injection +
+
git.ts uses execSync with ref argument
+
1 │ /** 2 │ * GuardLink Diff — exports. 3 │ * 4 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "git.ts uses execSync with ref argument" 5 │ * @audit #diff -- "Git commands use execSync; ref is validated with rev-parse before use" 6 │ * @flows GitRef -> #diff via parseAtRef -- "Git reference input" 7 │ */ 8 │ 9 │ export { diffModels, type ThreatModelDiff, type DiffSummary, type Change, type ChangeKind } from './engine.js';
+
+
+
+ L5 + audit + Audit: #diff +
+
Git commands use execSync; ref is validated with rev-parse before use
+
1 │ /** 2 │ * GuardLink Diff — exports. 3 │ * 4 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "git.ts uses execSync with ref argument" 5 │ * @audit #diff -- "Git commands use execSync; ref is validated with rev-parse before use" 6 │ * @flows GitRef -> #diff via parseAtRef -- "Git reference input" 7 │ */ 8 │ 9 │ export { diffModels, type ThreatModelDiff, type DiffSummary, type Change, type ChangeKind } from './engine.js'; 10 │ export { formatDiff, formatDiffMarkdown } from './format.js';
+
+
+
+ L6 + flow + GitRef → #diff +
+
Git reference input
+
1 │ /** 2 │ * GuardLink Diff — exports. 3 │ * 4 │ * @exposes #diff to #cmd-injection [high] cwe:CWE-78 -- "git.ts uses execSync with ref argument" 5 │ * @audit #diff -- "Git commands use execSync; ref is validated with rev-parse before use" 6 │ * @flows GitRef -> #diff via parseAtRef -- "Git reference input" 7 │ */ 8 │ 9 │ export { diffModels, type ThreatModelDiff, type DiffSummary, type Change, type ChangeKind } from './engine.js'; 10 │ export { formatDiff, formatDiffMarkdown } from './format.js'; 11 │ export { parseAtRef, getCurrentRef } from './git.js';
+
+
+
+
+
+ src/init/detect.ts + + 4 + + +
+
+ +
+
+ L5 + exposes + #init → #path-traversal +
+
Reads package.json, pyproject.toml, etc. from root
+
1 │ /** 2 │ * GuardLink init — Project detection utilities. 3 │ * Detects language, project name, and existing agent instruction files. 4 │ * 5 │ * @exposes #init to #path-traversal [low] cwe:CWE-22 -- "Reads package.json, pyproject.toml, etc. from root" 6 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with root constrains; reads well-known files only" 7 │ * @flows ProjectRoot -> #init via detectProject -- "Project detection input" 8 │ * @comment -- "Detection is read-only; no file writes" 9 │ */ 10 │
+
+
+
+ L6 + mitigates + #path-validation mitigates #path-traversal +
+
join() with root constrains; reads well-known files only
+
1 │ /** 2 │ * GuardLink init — Project detection utilities. 3 │ * Detects language, project name, and existing agent instruction files. 4 │ * 5 │ * @exposes #init to #path-traversal [low] cwe:CWE-22 -- "Reads package.json, pyproject.toml, etc. from root" 6 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with root constrains; reads well-known files only" 7 │ * @flows ProjectRoot -> #init via detectProject -- "Project detection input" 8 │ * @comment -- "Detection is read-only; no file writes" 9 │ */ 10 │ 11 │ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
+
+
+
+ L7 + flow + ProjectRoot → #init +
+
Project detection input
+
2 │ * GuardLink init — Project detection utilities. 3 │ * Detects language, project name, and existing agent instruction files. 4 │ * 5 │ * @exposes #init to #path-traversal [low] cwe:CWE-22 -- "Reads package.json, pyproject.toml, etc. from root" 6 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with root constrains; reads well-known files only" 7 │ * @flows ProjectRoot -> #init via detectProject -- "Project detection input" 8 │ * @comment -- "Detection is read-only; no file writes" 9 │ */ 10 │ 11 │ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; 12 │ import { join, basename } from 'node:path';
+
+
+
+ L8 + comment + Detection is read-only; no file writes +
+
Detection is read-only; no file writes
+
3 │ * Detects language, project name, and existing agent instruction files. 4 │ * 5 │ * @exposes #init to #path-traversal [low] cwe:CWE-22 -- "Reads package.json, pyproject.toml, etc. from root" 6 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with root constrains; reads well-known files only" 7 │ * @flows ProjectRoot -> #init via detectProject -- "Project detection input" 8 │ * @comment -- "Detection is read-only; no file writes" 9 │ */ 10 │ 11 │ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; 12 │ import { join, basename } from 'node:path'; 13 │
+
+
+
+
+
+ src/init/index.ts + + 10 + + +
+
+ +
+
+ L8 + exposes + #init → #arbitrary-write +
+
Creates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc.
+
3 │ * 4 │ * Detects project language and existing agent files, creates .guardlink/ 5 │ * directory with shared definitions, and injects GuardLink instructions 6 │ * into agent instruction files (CLAUDE.md, .cursorrules, etc.). 7 │ * 8 │ * @exposes #init to #arbitrary-write [high] cwe:CWE-73 -- "Creates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc." 9 │ * @mitigates #init against #arbitrary-write using #path-validation -- "All paths are relative to root; join() constrains" 10 │ * @exposes #init to #path-traversal [medium] cwe:CWE-22 -- "Reads/writes files based on root argument" 11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically"
+
+
+
+ L9 + mitigates + #path-validation mitigates #arbitrary-write +
+
All paths are relative to root; join() constrains
+
4 │ * Detects project language and existing agent files, creates .guardlink/ 5 │ * directory with shared definitions, and injects GuardLink instructions 6 │ * into agent instruction files (CLAUDE.md, .cursorrules, etc.). 7 │ * 8 │ * @exposes #init to #arbitrary-write [high] cwe:CWE-73 -- "Creates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc." 9 │ * @mitigates #init against #arbitrary-write using #path-validation -- "All paths are relative to root; join() constrains" 10 │ * @exposes #init to #path-traversal [medium] cwe:CWE-22 -- "Reads/writes files based on root argument" 11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input"
+
+
+
+ L10 + exposes + #init → #path-traversal +
+
Reads/writes files based on root argument
+
5 │ * directory with shared definitions, and injects GuardLink instructions 6 │ * into agent instruction files (CLAUDE.md, .cursorrules, etc.). 7 │ * 8 │ * @exposes #init to #arbitrary-write [high] cwe:CWE-73 -- "Creates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc." 9 │ * @mitigates #init against #arbitrary-write using #path-validation -- "All paths are relative to root; join() constrains" 10 │ * @exposes #init to #path-traversal [medium] cwe:CWE-22 -- "Reads/writes files based on root argument" 11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input" 15 │ * @flows #init -> AgentFiles via writeFileSync -- "Agent instruction file writes"
+
+
+
+ L11 + mitigates + #path-validation mitigates #path-traversal +
+
join() with explicit root constrains file access
+
6 │ * into agent instruction files (CLAUDE.md, .cursorrules, etc.). 7 │ * 8 │ * @exposes #init to #arbitrary-write [high] cwe:CWE-73 -- "Creates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc." 9 │ * @mitigates #init against #arbitrary-write using #path-validation -- "All paths are relative to root; join() constrains" 10 │ * @exposes #init to #path-traversal [medium] cwe:CWE-22 -- "Reads/writes files based on root argument" 11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input" 15 │ * @flows #init -> AgentFiles via writeFileSync -- "Agent instruction file writes" 16 │ * @flows #init -> ConfigFile via writeFileSync -- "Config file write"
+
+
+
+ L12 + exposes + #init → #data-exposure +
+
Writes API key config to .guardlink/config.json
+
7 │ * 8 │ * @exposes #init to #arbitrary-write [high] cwe:CWE-73 -- "Creates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc." 9 │ * @mitigates #init against #arbitrary-write using #path-validation -- "All paths are relative to root; join() constrains" 10 │ * @exposes #init to #path-traversal [medium] cwe:CWE-22 -- "Reads/writes files based on root argument" 11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input" 15 │ * @flows #init -> AgentFiles via writeFileSync -- "Agent instruction file writes" 16 │ * @flows #init -> ConfigFile via writeFileSync -- "Config file write" 17 │ * @handles internal on #init -- "Generates definitions and agent instruction content"
+
+
+
+ L13 + audit + Audit: #init +
+
Config file may contain API keys; .gitignore entry added automatically
+
8 │ * @exposes #init to #arbitrary-write [high] cwe:CWE-73 -- "Creates/modifies files: .guardlink/, CLAUDE.md, .cursorrules, etc." 9 │ * @mitigates #init against #arbitrary-write using #path-validation -- "All paths are relative to root; join() constrains" 10 │ * @exposes #init to #path-traversal [medium] cwe:CWE-22 -- "Reads/writes files based on root argument" 11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input" 15 │ * @flows #init -> AgentFiles via writeFileSync -- "Agent instruction file writes" 16 │ * @flows #init -> ConfigFile via writeFileSync -- "Config file write" 17 │ * @handles internal on #init -- "Generates definitions and agent instruction content" 18 │ */
+
+
+
+ L14 + flow + ProjectRoot → #init +
+
Project root input
+
9 │ * @mitigates #init against #arbitrary-write using #path-validation -- "All paths are relative to root; join() constrains" 10 │ * @exposes #init to #path-traversal [medium] cwe:CWE-22 -- "Reads/writes files based on root argument" 11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input" 15 │ * @flows #init -> AgentFiles via writeFileSync -- "Agent instruction file writes" 16 │ * @flows #init -> ConfigFile via writeFileSync -- "Config file write" 17 │ * @handles internal on #init -- "Generates definitions and agent instruction content" 18 │ */ 19 │
+
+
+
+ L15 + flow + #init → AgentFiles +
+
Agent instruction file writes
+
10 │ * @exposes #init to #path-traversal [medium] cwe:CWE-22 -- "Reads/writes files based on root argument" 11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input" 15 │ * @flows #init -> AgentFiles via writeFileSync -- "Agent instruction file writes" 16 │ * @flows #init -> ConfigFile via writeFileSync -- "Config file write" 17 │ * @handles internal on #init -- "Generates definitions and agent instruction content" 18 │ */ 19 │ 20 │ import { existsSync, readFileSync, mkdirSync, writeFileSync, appendFileSync } from 'node:fs';
+
+
+
+ L16 + flow + #init → ConfigFile +
+
Config file write
+
11 │ * @mitigates #init against #path-traversal using #path-validation -- "join() with explicit root constrains file access" 12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input" 15 │ * @flows #init -> AgentFiles via writeFileSync -- "Agent instruction file writes" 16 │ * @flows #init -> ConfigFile via writeFileSync -- "Config file write" 17 │ * @handles internal on #init -- "Generates definitions and agent instruction content" 18 │ */ 19 │ 20 │ import { existsSync, readFileSync, mkdirSync, writeFileSync, appendFileSync } from 'node:fs'; 21 │ import { join, dirname } from 'node:path';
+
+
+
+ L17 + handles + #init: internal +
+
Generates definitions and agent instruction content
+
12 │ * @exposes #init to #data-exposure [low] cwe:CWE-200 -- "Writes API key config to .guardlink/config.json" 13 │ * @audit #init -- "Config file may contain API keys; .gitignore entry added automatically" 14 │ * @flows ProjectRoot -> #init via options.root -- "Project root input" 15 │ * @flows #init -> AgentFiles via writeFileSync -- "Agent instruction file writes" 16 │ * @flows #init -> ConfigFile via writeFileSync -- "Config file write" 17 │ * @handles internal on #init -- "Generates definitions and agent instruction content" 18 │ */ 19 │ 20 │ import { existsSync, readFileSync, mkdirSync, writeFileSync, appendFileSync } from 'node:fs'; 21 │ import { join, dirname } from 'node:path'; 22 │ import { detectProject, type ProjectInfo, type AgentFile } from './detect.js';
+
+
+
+
+
+ src/mcp/index.ts + + 4 + + +
+
+ +
+
+ L4 + exposes + #mcp → #cmd-injection +
+
Accepts tool calls from external MCP clients
+
1 │ /** 2 │ * GuardLink MCP Server — exports and stdio entry point. 3 │ * 4 │ * @exposes #mcp to #cmd-injection [high] cwe:CWE-78 -- "Accepts tool calls from external MCP clients" 5 │ * @audit #mcp -- "All tool calls validated by server.ts before execution" 6 │ * @flows MCPClient -> #mcp via stdio -- "MCP protocol transport" 7 │ * @boundary #mcp and MCPClient (#mcp-boundary) -- "Trust boundary at MCP protocol" 8 │ */ 9 │
+
+
+
+ L5 + audit + Audit: #mcp +
+
All tool calls validated by server.ts before execution
+
1 │ /** 2 │ * GuardLink MCP Server — exports and stdio entry point. 3 │ * 4 │ * @exposes #mcp to #cmd-injection [high] cwe:CWE-78 -- "Accepts tool calls from external MCP clients" 5 │ * @audit #mcp -- "All tool calls validated by server.ts before execution" 6 │ * @flows MCPClient -> #mcp via stdio -- "MCP protocol transport" 7 │ * @boundary #mcp and MCPClient (#mcp-boundary) -- "Trust boundary at MCP protocol" 8 │ */ 9 │ 10 │ export { createServer } from './server.js';
+
+
+
+ L6 + flow + MCPClient → #mcp +
+
MCP protocol transport
+
1 │ /** 2 │ * GuardLink MCP Server — exports and stdio entry point. 3 │ * 4 │ * @exposes #mcp to #cmd-injection [high] cwe:CWE-78 -- "Accepts tool calls from external MCP clients" 5 │ * @audit #mcp -- "All tool calls validated by server.ts before execution" 6 │ * @flows MCPClient -> #mcp via stdio -- "MCP protocol transport" 7 │ * @boundary #mcp and MCPClient (#mcp-boundary) -- "Trust boundary at MCP protocol" 8 │ */ 9 │ 10 │ export { createServer } from './server.js'; 11 │ export { lookup, type LookupResult } from './lookup.js';
+
+
+
+ L7 + boundary + #mcp ↔ MCPClient +
+
Trust boundary at MCP protocol
+
2 │ * GuardLink MCP Server — exports and stdio entry point. 3 │ * 4 │ * @exposes #mcp to #cmd-injection [high] cwe:CWE-78 -- "Accepts tool calls from external MCP clients" 5 │ * @audit #mcp -- "All tool calls validated by server.ts before execution" 6 │ * @flows MCPClient -> #mcp via stdio -- "MCP protocol transport" 7 │ * @boundary #mcp and MCPClient (#mcp-boundary) -- "Trust boundary at MCP protocol" 8 │ */ 9 │ 10 │ export { createServer } from './server.js'; 11 │ export { lookup, type LookupResult } from './lookup.js'; 12 │ export { suggestAnnotations, type Suggestion, type SuggestOptions } from './suggest.js';
+
+
+
+
+
+ src/mcp/lookup.ts + + 4 + + +
+
+ +
+
+ L16 + exposes + #mcp → #redos +
+
Regex patterns applied to query strings
+
11 │ * - "flows from #config" → data flows with source = config 12 │ * - "unmitigated" → all unmitigated exposures 13 │ * - "boundary #config" → boundaries involving asset 14 │ * - Free text → fuzzy match across assets, threats, controls 15 │ * 16 │ * @exposes #mcp to #redos [low] cwe:CWE-1333 -- "Regex patterns applied to query strings" 17 │ * @mitigates #mcp against #redos using #regex-anchoring -- "Patterns are simple and bounded" 18 │ * @flows QueryString -> #mcp via lookup -- "Query input path" 19 │ * @comment -- "Pure function; no I/O; operates on in-memory ThreatModel" 20 │ */ 21 │
+
+
+
+ L17 + mitigates + #regex-anchoring mitigates #redos +
+
Patterns are simple and bounded
+
12 │ * - "unmitigated" → all unmitigated exposures 13 │ * - "boundary #config" → boundaries involving asset 14 │ * - Free text → fuzzy match across assets, threats, controls 15 │ * 16 │ * @exposes #mcp to #redos [low] cwe:CWE-1333 -- "Regex patterns applied to query strings" 17 │ * @mitigates #mcp against #redos using #regex-anchoring -- "Patterns are simple and bounded" 18 │ * @flows QueryString -> #mcp via lookup -- "Query input path" 19 │ * @comment -- "Pure function; no I/O; operates on in-memory ThreatModel" 20 │ */ 21 │ 22 │ import type {
+
+
+
+ L18 + flow + QueryString → #mcp +
+
Query input path
+
13 │ * - "boundary #config" → boundaries involving asset 14 │ * - Free text → fuzzy match across assets, threats, controls 15 │ * 16 │ * @exposes #mcp to #redos [low] cwe:CWE-1333 -- "Regex patterns applied to query strings" 17 │ * @mitigates #mcp against #redos using #regex-anchoring -- "Patterns are simple and bounded" 18 │ * @flows QueryString -> #mcp via lookup -- "Query input path" 19 │ * @comment -- "Pure function; no I/O; operates on in-memory ThreatModel" 20 │ */ 21 │ 22 │ import type { 23 │ ThreatModel, ThreatModelAsset, ThreatModelThreat, ThreatModelControl,
+
+
+
+ L19 + comment + Pure function; no I/O; operates on in-memory ThreatModel +
+
Pure function; no I/O; operates on in-memory ThreatModel
+
14 │ * - Free text → fuzzy match across assets, threats, controls 15 │ * 16 │ * @exposes #mcp to #redos [low] cwe:CWE-1333 -- "Regex patterns applied to query strings" 17 │ * @mitigates #mcp against #redos using #regex-anchoring -- "Patterns are simple and bounded" 18 │ * @flows QueryString -> #mcp via lookup -- "Query input path" 19 │ * @comment -- "Pure function; no I/O; operates on in-memory ThreatModel" 20 │ */ 21 │ 22 │ import type { 23 │ ThreatModel, ThreatModelAsset, ThreatModelThreat, ThreatModelControl, 24 │ ThreatModelExposure, ThreatModelMitigation, ThreatModelFlow,
+
+
+
+
+
+ src/mcp/server.ts + + 16 + + +
+
+ +
+
+ L26 + exposes + #mcp → #path-traversal +
+
Tool arguments include 'root' directory path from external client
+
21 │ * guardlink://definitions — Assets, threats, controls 22 │ * guardlink://unmitigated — Unmitigated exposures list 23 │ * 24 │ * Transport: stdio (for Claude Code .mcp.json, Cursor, etc.) 25 │ * 26 │ * @exposes #mcp to #path-traversal [high] cwe:CWE-22 -- "Tool arguments include 'root' directory path from external client" 27 │ * @mitigates #mcp against #path-traversal using #path-validation -- "Zod schema validates root; resolve() canonicalizes" 28 │ * @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "report, dashboard, sarif tools write files" 29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only"
+
+
+
+ L27 + mitigates + #path-validation mitigates #path-traversal +
+
Zod schema validates root; resolve() canonicalizes
+
22 │ * guardlink://unmitigated — Unmitigated exposures list 23 │ * 24 │ * Transport: stdio (for Claude Code .mcp.json, Cursor, etc.) 25 │ * 26 │ * @exposes #mcp to #path-traversal [high] cwe:CWE-22 -- "Tool arguments include 'root' directory path from external client" 27 │ * @mitigates #mcp against #path-traversal using #path-validation -- "Zod schema validates root; resolve() canonicalizes" 28 │ * @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "report, dashboard, sarif tools write files" 29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment"
+
+
+
+ L28 + exposes + #mcp → #arbitrary-write +
+
report, dashboard, sarif tools write files
+
23 │ * 24 │ * Transport: stdio (for Claude Code .mcp.json, Cursor, etc.) 25 │ * 26 │ * @exposes #mcp to #path-traversal [high] cwe:CWE-22 -- "Tool arguments include 'root' directory path from external client" 27 │ * @mitigates #mcp against #path-traversal using #path-validation -- "Zod schema validates root; resolve() canonicalizes" 28 │ * @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "report, dashboard, sarif tools write files" 29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned"
+
+
+
+ L29 + mitigates + #path-validation mitigates #arbitrary-write +
+
Output paths resolved relative to validated root
+
24 │ * Transport: stdio (for Claude Code .mcp.json, Cursor, etc.) 25 │ * 26 │ * @exposes #mcp to #path-traversal [high] cwe:CWE-22 -- "Tool arguments include 'root' directory path from external client" 27 │ * @mitigates #mcp against #path-traversal using #path-validation -- "Zod schema validates root; resolve() canonicalizes" 28 │ * @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "report, dashboard, sarif tools write files" 29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients"
+
+
+
+ L30 + exposes + #mcp → #prompt-injection +
+
annotate and threat_report tools pass user prompts to LLM
+
25 │ * 26 │ * @exposes #mcp to #path-traversal [high] cwe:CWE-22 -- "Tool arguments include 'root' directory path from external client" 27 │ * @mitigates #mcp against #path-traversal using #path-validation -- "Zod schema validates root; resolve() canonicalizes" 28 │ * @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "report, dashboard, sarif tools write files" 29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents"
+
+
+
+ L31 + audit + Audit: #mcp +
+
User prompts passed to LLM; model context is read-only
+
26 │ * @exposes #mcp to #path-traversal [high] cwe:CWE-22 -- "Tool arguments include 'root' directory path from external client" 27 │ * @mitigates #mcp against #path-traversal using #path-validation -- "Zod schema validates root; resolve() canonicalizes" 28 │ * @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "report, dashboard, sarif tools write files" 29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input"
+
+
+
+ L32 + exposes + #mcp → #api-key-exposure +
+
threat_report tool uses API keys from environment
+
27 │ * @mitigates #mcp against #path-traversal using #path-validation -- "Zod schema validates root; resolve() canonicalizes" 28 │ * @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "report, dashboard, sarif tools write files" 29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output"
+
+
+
+ L33 + mitigates + #key-redaction mitigates #api-key-exposure +
+
Keys from env only; never logged or returned
+
28 │ * @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "report, dashboard, sarif tools write files" 29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path"
+
+
+
+ L34 + exposes + #mcp → #data-exposure +
+
Resources expose full threat model to MCP clients
+
29 │ * @mitigates #mcp against #arbitrary-write using #path-validation -- "Output paths resolved relative to validated root" 30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path" 39 │ * @flows #mcp -> MCPClient via resource -- "Threat model data output"
+
+
+
+ L35 + audit + Audit: #mcp +
+
Threat model data intentionally exposed to connected agents
+
30 │ * @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "annotate and threat_report tools pass user prompts to LLM" 31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path" 39 │ * @flows #mcp -> MCPClient via resource -- "Threat model data output" 40 │ * @boundary #mcp and MCPClient (#mcp-tool-boundary) -- "Trust boundary at tool argument parsing"
+
+
+
+ L36 + flow + MCPClient → #mcp +
+
Tool invocation input
+
31 │ * @audit #mcp -- "User prompts passed to LLM; model context is read-only" 32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path" 39 │ * @flows #mcp -> MCPClient via resource -- "Threat model data output" 40 │ * @boundary #mcp and MCPClient (#mcp-tool-boundary) -- "Trust boundary at tool argument parsing" 41 │ * @handles internal on #mcp -- "Processes project annotations and threat model data"
+
+
+
+ L37 + flow + #mcp → FileSystem +
+
Report/dashboard output
+
32 │ * @exposes #mcp to #api-key-exposure [medium] cwe:CWE-798 -- "threat_report tool uses API keys from environment" 33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path" 39 │ * @flows #mcp -> MCPClient via resource -- "Threat model data output" 40 │ * @boundary #mcp and MCPClient (#mcp-tool-boundary) -- "Trust boundary at tool argument parsing" 41 │ * @handles internal on #mcp -- "Processes project annotations and threat model data" 42 │ */
+
+
+
+ L38 + flow + #mcp → #llm-client +
+
LLM API call path
+
33 │ * @mitigates #mcp against #api-key-exposure using #key-redaction -- "Keys from env only; never logged or returned" 34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path" 39 │ * @flows #mcp -> MCPClient via resource -- "Threat model data output" 40 │ * @boundary #mcp and MCPClient (#mcp-tool-boundary) -- "Trust boundary at tool argument parsing" 41 │ * @handles internal on #mcp -- "Processes project annotations and threat model data" 42 │ */ 43 │
+
+
+
+ L39 + flow + #mcp → MCPClient +
+
Threat model data output
+
34 │ * @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Resources expose full threat model to MCP clients" 35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path" 39 │ * @flows #mcp -> MCPClient via resource -- "Threat model data output" 40 │ * @boundary #mcp and MCPClient (#mcp-tool-boundary) -- "Trust boundary at tool argument parsing" 41 │ * @handles internal on #mcp -- "Processes project annotations and threat model data" 42 │ */ 43 │ 44 │ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
+
+
+
+ L40 + boundary + #mcp ↔ MCPClient +
+
Trust boundary at tool argument parsing
+
35 │ * @audit #mcp -- "Threat model data intentionally exposed to connected agents" 36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path" 39 │ * @flows #mcp -> MCPClient via resource -- "Threat model data output" 40 │ * @boundary #mcp and MCPClient (#mcp-tool-boundary) -- "Trust boundary at tool argument parsing" 41 │ * @handles internal on #mcp -- "Processes project annotations and threat model data" 42 │ */ 43 │ 44 │ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; 45 │ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+
+
+
+ L41 + handles + #mcp: internal +
+
Processes project annotations and threat model data
+
36 │ * @flows MCPClient -> #mcp via tool_call -- "Tool invocation input" 37 │ * @flows #mcp -> FileSystem via writeFile -- "Report/dashboard output" 38 │ * @flows #mcp -> #llm-client via generateThreatReport -- "LLM API call path" 39 │ * @flows #mcp -> MCPClient via resource -- "Threat model data output" 40 │ * @boundary #mcp and MCPClient (#mcp-tool-boundary) -- "Trust boundary at tool argument parsing" 41 │ * @handles internal on #mcp -- "Processes project annotations and threat model data" 42 │ */ 43 │ 44 │ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; 45 │ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; 46 │ import { z } from 'zod';
+
+
+
+
+
+ src/mcp/suggest.ts + + 9 + + +
+
+ +
+
+ L12 + exposes + #suggest → #path-traversal +
+
File path from MCP client joined with root
+
7 │ * - HTTP handlers, auth checks, input parsing 8 │ * - Missing annotations on files that handle sensitive data 9 │ * 10 │ * Designed for both file-based and diff-based analysis (§8.2). 11 │ * 12 │ * @exposes #suggest to #path-traversal [high] cwe:CWE-22 -- "File path from MCP client joined with root" 13 │ * @mitigates #suggest against #path-traversal using #path-validation -- "join() with validated root constrains access" 14 │ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" 15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes"
+
+
+
+ L13 + mitigates + #path-validation mitigates #path-traversal +
+
join() with validated root constrains access
+
8 │ * - Missing annotations on files that handle sensitive data 9 │ * 10 │ * Designed for both file-based and diff-based analysis (§8.2). 11 │ * 12 │ * @exposes #suggest to #path-traversal [high] cwe:CWE-22 -- "File path from MCP client joined with root" 13 │ * @mitigates #suggest against #path-traversal using #path-validation -- "join() with validated root constrains access" 14 │ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" 15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" 18 │ * @flows FilePath -> #suggest via readFileSync -- "File read path"
+
+
+
+ L14 + exposes + #suggest → #redos +
+
Complex regex patterns applied to source code
+
9 │ * 10 │ * Designed for both file-based and diff-based analysis (§8.2). 11 │ * 12 │ * @exposes #suggest to #path-traversal [high] cwe:CWE-22 -- "File path from MCP client joined with root" 13 │ * @mitigates #suggest against #path-traversal using #path-validation -- "join() with validated root constrains access" 14 │ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" 15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" 18 │ * @flows FilePath -> #suggest via readFileSync -- "File read path" 19 │ * @flows #suggest -> Suggestions via suggestAnnotations -- "Suggestion output"
+
+
+
+ L15 + mitigates + #regex-anchoring mitigates #redos +
+
Patterns designed with bounded quantifiers
+
10 │ * Designed for both file-based and diff-based analysis (§8.2). 11 │ * 12 │ * @exposes #suggest to #path-traversal [high] cwe:CWE-22 -- "File path from MCP client joined with root" 13 │ * @mitigates #suggest against #path-traversal using #path-validation -- "join() with validated root constrains access" 14 │ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" 15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" 18 │ * @flows FilePath -> #suggest via readFileSync -- "File read path" 19 │ * @flows #suggest -> Suggestions via suggestAnnotations -- "Suggestion output" 20 │ * @comment -- "Skips node_modules and .guardlink directories"
+
+
+
+ L16 + exposes + #suggest → #dos +
+
Large files loaded into memory for pattern scanning
+
11 │ * 12 │ * @exposes #suggest to #path-traversal [high] cwe:CWE-22 -- "File path from MCP client joined with root" 13 │ * @mitigates #suggest against #path-traversal using #path-validation -- "join() with validated root constrains access" 14 │ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" 15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" 18 │ * @flows FilePath -> #suggest via readFileSync -- "File read path" 19 │ * @flows #suggest -> Suggestions via suggestAnnotations -- "Suggestion output" 20 │ * @comment -- "Skips node_modules and .guardlink directories" 21 │ */
+
+
+
+ L17 + audit + Audit: #suggest +
+
File size is bounded by project scope; production use involves reasonable file sizes
+
12 │ * @exposes #suggest to #path-traversal [high] cwe:CWE-22 -- "File path from MCP client joined with root" 13 │ * @mitigates #suggest against #path-traversal using #path-validation -- "join() with validated root constrains access" 14 │ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" 15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" 18 │ * @flows FilePath -> #suggest via readFileSync -- "File read path" 19 │ * @flows #suggest -> Suggestions via suggestAnnotations -- "Suggestion output" 20 │ * @comment -- "Skips node_modules and .guardlink directories" 21 │ */ 22 │
+
+
+
+ L18 + flow + FilePath → #suggest +
+
File read path
+
13 │ * @mitigates #suggest against #path-traversal using #path-validation -- "join() with validated root constrains access" 14 │ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" 15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" 18 │ * @flows FilePath -> #suggest via readFileSync -- "File read path" 19 │ * @flows #suggest -> Suggestions via suggestAnnotations -- "Suggestion output" 20 │ * @comment -- "Skips node_modules and .guardlink directories" 21 │ */ 22 │ 23 │ import { readFileSync, existsSync } from 'node:fs';
+
+
+
+ L19 + flow + #suggest → Suggestions +
+
Suggestion output
+
14 │ * @exposes #suggest to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to source code" 15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" 18 │ * @flows FilePath -> #suggest via readFileSync -- "File read path" 19 │ * @flows #suggest -> Suggestions via suggestAnnotations -- "Suggestion output" 20 │ * @comment -- "Skips node_modules and .guardlink directories" 21 │ */ 22 │ 23 │ import { readFileSync, existsSync } from 'node:fs'; 24 │ import { join, extname } from 'node:path';
+
+
+
+ L20 + comment + Skips node_modules and .guardlink directories +
+
Skips node_modules and .guardlink directories
+
15 │ * @mitigates #suggest against #redos using #regex-anchoring -- "Patterns designed with bounded quantifiers" 16 │ * @exposes #suggest to #dos [low] cwe:CWE-400 -- "Large files loaded into memory for pattern scanning" 17 │ * @audit #suggest -- "File size is bounded by project scope; production use involves reasonable file sizes" 18 │ * @flows FilePath -> #suggest via readFileSync -- "File read path" 19 │ * @flows #suggest -> Suggestions via suggestAnnotations -- "Suggestion output" 20 │ * @comment -- "Skips node_modules and .guardlink directories" 21 │ */ 22 │ 23 │ import { readFileSync, existsSync } from 'node:fs'; 24 │ import { join, extname } from 'node:path'; 25 │ import type { ThreatModel } from '../types/index.js';
+
+
+
+
+
+ src/parser/clear.ts + + 7 + + +
+
+ +
+
+ L7 + exposes + #parser → #arbitrary-write +
+
Writes modified content back to discovered files
+
2 │ * GuardLink — Annotation clearing utility. 3 │ * Scans project source files and removes all GuardLink annotation comment lines. 4 │ * 5 │ * Used by `guardlink clear` and `/clear` to let users start fresh with annotations. 6 │ * 7 │ * @exposes #parser to #arbitrary-write [high] cwe:CWE-73 -- "Writes modified content back to discovered files" 8 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns determine which files are modified" 9 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks sensitive dirs; cwd constrains scope" 10 │ * @audit #parser -- "Destructive operation requires explicit user confirmation via dryRun flag" 11 │ * @flows ProjectRoot -> #parser via fast-glob -- "File discovery path" 12 │ * @flows #parser -> SourceFiles via writeFile -- "Modified file write path"
+
+
+
+ L8 + exposes + #parser → #path-traversal +
+
Glob patterns determine which files are modified
+
3 │ * Scans project source files and removes all GuardLink annotation comment lines. 4 │ * 5 │ * Used by `guardlink clear` and `/clear` to let users start fresh with annotations. 6 │ * 7 │ * @exposes #parser to #arbitrary-write [high] cwe:CWE-73 -- "Writes modified content back to discovered files" 8 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns determine which files are modified" 9 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks sensitive dirs; cwd constrains scope" 10 │ * @audit #parser -- "Destructive operation requires explicit user confirmation via dryRun flag" 11 │ * @flows ProjectRoot -> #parser via fast-glob -- "File discovery path" 12 │ * @flows #parser -> SourceFiles via writeFile -- "Modified file write path" 13 │ * @handles internal on #parser -- "Operates on project source files only"
+
+
+
+ L9 + mitigates + #glob-filtering mitigates #path-traversal +
+
DEFAULT_EXCLUDE blocks sensitive dirs; cwd constrains scope
+
4 │ * 5 │ * Used by `guardlink clear` and `/clear` to let users start fresh with annotations. 6 │ * 7 │ * @exposes #parser to #arbitrary-write [high] cwe:CWE-73 -- "Writes modified content back to discovered files" 8 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns determine which files are modified" 9 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks sensitive dirs; cwd constrains scope" 10 │ * @audit #parser -- "Destructive operation requires explicit user confirmation via dryRun flag" 11 │ * @flows ProjectRoot -> #parser via fast-glob -- "File discovery path" 12 │ * @flows #parser -> SourceFiles via writeFile -- "Modified file write path" 13 │ * @handles internal on #parser -- "Operates on project source files only" 14 │ */
+
+
+
+ L10 + audit + Audit: #parser +
+
Destructive operation requires explicit user confirmation via dryRun flag
+
5 │ * Used by `guardlink clear` and `/clear` to let users start fresh with annotations. 6 │ * 7 │ * @exposes #parser to #arbitrary-write [high] cwe:CWE-73 -- "Writes modified content back to discovered files" 8 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns determine which files are modified" 9 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks sensitive dirs; cwd constrains scope" 10 │ * @audit #parser -- "Destructive operation requires explicit user confirmation via dryRun flag" 11 │ * @flows ProjectRoot -> #parser via fast-glob -- "File discovery path" 12 │ * @flows #parser -> SourceFiles via writeFile -- "Modified file write path" 13 │ * @handles internal on #parser -- "Operates on project source files only" 14 │ */ 15 │
+
+
+
+ L11 + flow + ProjectRoot → #parser +
+
File discovery path
+
6 │ * 7 │ * @exposes #parser to #arbitrary-write [high] cwe:CWE-73 -- "Writes modified content back to discovered files" 8 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns determine which files are modified" 9 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks sensitive dirs; cwd constrains scope" 10 │ * @audit #parser -- "Destructive operation requires explicit user confirmation via dryRun flag" 11 │ * @flows ProjectRoot -> #parser via fast-glob -- "File discovery path" 12 │ * @flows #parser -> SourceFiles via writeFile -- "Modified file write path" 13 │ * @handles internal on #parser -- "Operates on project source files only" 14 │ */ 15 │ 16 │ import fg from 'fast-glob';
+
+
+
+ L12 + flow + #parser → SourceFiles +
+
Modified file write path
+
7 │ * @exposes #parser to #arbitrary-write [high] cwe:CWE-73 -- "Writes modified content back to discovered files" 8 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns determine which files are modified" 9 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks sensitive dirs; cwd constrains scope" 10 │ * @audit #parser -- "Destructive operation requires explicit user confirmation via dryRun flag" 11 │ * @flows ProjectRoot -> #parser via fast-glob -- "File discovery path" 12 │ * @flows #parser -> SourceFiles via writeFile -- "Modified file write path" 13 │ * @handles internal on #parser -- "Operates on project source files only" 14 │ */ 15 │ 16 │ import fg from 'fast-glob'; 17 │ import { readFile, writeFile } from 'node:fs/promises';
+
+
+
+ L13 + handles + #parser: internal +
+
Operates on project source files only
+
8 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns determine which files are modified" 9 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks sensitive dirs; cwd constrains scope" 10 │ * @audit #parser -- "Destructive operation requires explicit user confirmation via dryRun flag" 11 │ * @flows ProjectRoot -> #parser via fast-glob -- "File discovery path" 12 │ * @flows #parser -> SourceFiles via writeFile -- "Modified file write path" 13 │ * @handles internal on #parser -- "Operates on project source files only" 14 │ */ 15 │ 16 │ import fg from 'fast-glob'; 17 │ import { readFile, writeFile } from 'node:fs/promises'; 18 │ import { relative } from 'node:path';
+
+
+
+
+
+ src/parser/parse-file.ts + + 5 + + +
+
+ +
+
+ L5 + exposes + #parser → #path-traversal +
+
File path from caller read via readFile; no validation here
+
1 │ /** 2 │ * GuardLink — File-level parser. 3 │ * Reads source files and extracts all GuardLink annotations. 4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "File path from caller read via readFile; no validation here" 6 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large files loaded entirely into memory" 7 │ * @audit #parser -- "Path validation delegated to callers (CLI/MCP validate root)" 8 │ * @flows FilePath -> #parser via readFile -- "Disk read path" 9 │ * @flows #parser -> Annotations via parseString -- "Parsed annotation output" 10 │ */
+
+
+
+ L6 + exposes + #parser → #dos +
+
Large files loaded entirely into memory
+
1 │ /** 2 │ * GuardLink — File-level parser. 3 │ * Reads source files and extracts all GuardLink annotations. 4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "File path from caller read via readFile; no validation here" 6 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large files loaded entirely into memory" 7 │ * @audit #parser -- "Path validation delegated to callers (CLI/MCP validate root)" 8 │ * @flows FilePath -> #parser via readFile -- "Disk read path" 9 │ * @flows #parser -> Annotations via parseString -- "Parsed annotation output" 10 │ */ 11 │
+
+
+
+ L7 + audit + Audit: #parser +
+
Path validation delegated to callers (CLI/MCP validate root)
+
2 │ * GuardLink — File-level parser. 3 │ * Reads source files and extracts all GuardLink annotations. 4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "File path from caller read via readFile; no validation here" 6 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large files loaded entirely into memory" 7 │ * @audit #parser -- "Path validation delegated to callers (CLI/MCP validate root)" 8 │ * @flows FilePath -> #parser via readFile -- "Disk read path" 9 │ * @flows #parser -> Annotations via parseString -- "Parsed annotation output" 10 │ */ 11 │ 12 │ import { readFile } from 'node:fs/promises';
+
+
+
+ L8 + flow + FilePath → #parser +
+
Disk read path
+
3 │ * Reads source files and extracts all GuardLink annotations. 4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "File path from caller read via readFile; no validation here" 6 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large files loaded entirely into memory" 7 │ * @audit #parser -- "Path validation delegated to callers (CLI/MCP validate root)" 8 │ * @flows FilePath -> #parser via readFile -- "Disk read path" 9 │ * @flows #parser -> Annotations via parseString -- "Parsed annotation output" 10 │ */ 11 │ 12 │ import { readFile } from 'node:fs/promises'; 13 │ import { basename, extname } from 'node:path';
+
+
+
+ L9 + flow + #parser → Annotations +
+
Parsed annotation output
+
4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "File path from caller read via readFile; no validation here" 6 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large files loaded entirely into memory" 7 │ * @audit #parser -- "Path validation delegated to callers (CLI/MCP validate root)" 8 │ * @flows FilePath -> #parser via readFile -- "Disk read path" 9 │ * @flows #parser -> Annotations via parseString -- "Parsed annotation output" 10 │ */ 11 │ 12 │ import { readFile } from 'node:fs/promises'; 13 │ import { basename, extname } from 'node:path'; 14 │ import type { Annotation, ParseDiagnostic, ParseResult } from '../types/index.js';
+
+
+
+
+
+ src/parser/parse-line.ts + + 3 + + +
+
+ +
+
+ L5 + exposes + #parser → #redos +
+
Complex regex patterns applied to annotation text
+
1 │ /** 2 │ * GuardLink — Line-level annotation parser. 3 │ * Parses a single comment line into a typed Annotation. 4 │ * 5 │ * @exposes #parser to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to annotation text" 6 │ * @mitigates #parser against #redos using #regex-anchoring -- "All patterns are anchored (^...$) to prevent backtracking" 7 │ * @comment -- "Regex patterns designed with bounded quantifiers and explicit structure" 8 │ */ 9 │ 10 │ import type {
+
+
+
+ L6 + mitigates + #regex-anchoring mitigates #redos +
+
All patterns are anchored (^...$) to prevent backtracking
+
1 │ /** 2 │ * GuardLink — Line-level annotation parser. 3 │ * Parses a single comment line into a typed Annotation. 4 │ * 5 │ * @exposes #parser to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to annotation text" 6 │ * @mitigates #parser against #redos using #regex-anchoring -- "All patterns are anchored (^...$) to prevent backtracking" 7 │ * @comment -- "Regex patterns designed with bounded quantifiers and explicit structure" 8 │ */ 9 │ 10 │ import type { 11 │ Annotation, AnnotationVerb, Severity, DataClassification,
+
+
+
+ L7 + comment + Regex patterns designed with bounded quantifiers and explicit structure +
+
Regex patterns designed with bounded quantifiers and explicit structure
+
2 │ * GuardLink — Line-level annotation parser. 3 │ * Parses a single comment line into a typed Annotation. 4 │ * 5 │ * @exposes #parser to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns applied to annotation text" 6 │ * @mitigates #parser against #redos using #regex-anchoring -- "All patterns are anchored (^...$) to prevent backtracking" 7 │ * @comment -- "Regex patterns designed with bounded quantifiers and explicit structure" 8 │ */ 9 │ 10 │ import type { 11 │ Annotation, AnnotationVerb, Severity, DataClassification, 12 │ ParseDiagnostic, SourceLocation,
+
+
+
+
+
+ src/parser/parse-project.ts + + 7 + + +
+
+ +
+
+ L5 + exposes + #parser → #path-traversal +
+
Glob patterns could escape root directory
+
1 │ /** 2 │ * GuardLink — Project-level parser. 3 │ * Walks a directory, parses all source files, and assembles a ThreatModel. 4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns could escape root directory" 6 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks node_modules, .git; fast-glob cwd constrains scan" 7 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large projects with many files could exhaust memory" 8 │ * @mitigates #parser against #dos using #resource-limits -- "DEFAULT_EXCLUDE skips build artifacts, tests; limits effective file count" 9 │ * @flows ProjectRoot -> #parser via fast-glob -- "Directory traversal path" 10 │ * @flows #parser -> ThreatModel via assembleModel -- "Aggregated threat model output"
+
+
+
+ L6 + mitigates + #glob-filtering mitigates #path-traversal +
+
DEFAULT_EXCLUDE blocks node_modules, .git; fast-glob cwd constrains scan
+
1 │ /** 2 │ * GuardLink — Project-level parser. 3 │ * Walks a directory, parses all source files, and assembles a ThreatModel. 4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns could escape root directory" 6 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks node_modules, .git; fast-glob cwd constrains scan" 7 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large projects with many files could exhaust memory" 8 │ * @mitigates #parser against #dos using #resource-limits -- "DEFAULT_EXCLUDE skips build artifacts, tests; limits effective file count" 9 │ * @flows ProjectRoot -> #parser via fast-glob -- "Directory traversal path" 10 │ * @flows #parser -> ThreatModel via assembleModel -- "Aggregated threat model output" 11 │ * @boundary #parser and FileSystem (#fs-boundary) -- "Trust boundary between parser and disk I/O"
+
+
+
+ L7 + exposes + #parser → #dos +
+
Large projects with many files could exhaust memory
+
2 │ * GuardLink — Project-level parser. 3 │ * Walks a directory, parses all source files, and assembles a ThreatModel. 4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns could escape root directory" 6 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks node_modules, .git; fast-glob cwd constrains scan" 7 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large projects with many files could exhaust memory" 8 │ * @mitigates #parser against #dos using #resource-limits -- "DEFAULT_EXCLUDE skips build artifacts, tests; limits effective file count" 9 │ * @flows ProjectRoot -> #parser via fast-glob -- "Directory traversal path" 10 │ * @flows #parser -> ThreatModel via assembleModel -- "Aggregated threat model output" 11 │ * @boundary #parser and FileSystem (#fs-boundary) -- "Trust boundary between parser and disk I/O" 12 │ */
+
+
+
+ L8 + mitigates + #resource-limits mitigates #dos +
+
DEFAULT_EXCLUDE skips build artifacts, tests; limits effective file count
+
3 │ * Walks a directory, parses all source files, and assembles a ThreatModel. 4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns could escape root directory" 6 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks node_modules, .git; fast-glob cwd constrains scan" 7 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large projects with many files could exhaust memory" 8 │ * @mitigates #parser against #dos using #resource-limits -- "DEFAULT_EXCLUDE skips build artifacts, tests; limits effective file count" 9 │ * @flows ProjectRoot -> #parser via fast-glob -- "Directory traversal path" 10 │ * @flows #parser -> ThreatModel via assembleModel -- "Aggregated threat model output" 11 │ * @boundary #parser and FileSystem (#fs-boundary) -- "Trust boundary between parser and disk I/O" 12 │ */ 13 │
+
+
+
+ L9 + flow + ProjectRoot → #parser +
+
Directory traversal path
+
4 │ * 5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns could escape root directory" 6 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks node_modules, .git; fast-glob cwd constrains scan" 7 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large projects with many files could exhaust memory" 8 │ * @mitigates #parser against #dos using #resource-limits -- "DEFAULT_EXCLUDE skips build artifacts, tests; limits effective file count" 9 │ * @flows ProjectRoot -> #parser via fast-glob -- "Directory traversal path" 10 │ * @flows #parser -> ThreatModel via assembleModel -- "Aggregated threat model output" 11 │ * @boundary #parser and FileSystem (#fs-boundary) -- "Trust boundary between parser and disk I/O" 12 │ */ 13 │ 14 │ import fg from 'fast-glob';
+
+
+
+ L10 + flow + #parser → ThreatModel +
+
Aggregated threat model output
+
5 │ * @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Glob patterns could escape root directory" 6 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks node_modules, .git; fast-glob cwd constrains scan" 7 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large projects with many files could exhaust memory" 8 │ * @mitigates #parser against #dos using #resource-limits -- "DEFAULT_EXCLUDE skips build artifacts, tests; limits effective file count" 9 │ * @flows ProjectRoot -> #parser via fast-glob -- "Directory traversal path" 10 │ * @flows #parser -> ThreatModel via assembleModel -- "Aggregated threat model output" 11 │ * @boundary #parser and FileSystem (#fs-boundary) -- "Trust boundary between parser and disk I/O" 12 │ */ 13 │ 14 │ import fg from 'fast-glob'; 15 │ import { relative } from 'node:path';
+
+
+
+ L11 + boundary + #parser ↔ FileSystem +
+
Trust boundary between parser and disk I/O
+
6 │ * @mitigates #parser against #path-traversal using #glob-filtering -- "DEFAULT_EXCLUDE blocks node_modules, .git; fast-glob cwd constrains scan" 7 │ * @exposes #parser to #dos [medium] cwe:CWE-400 -- "Large projects with many files could exhaust memory" 8 │ * @mitigates #parser against #dos using #resource-limits -- "DEFAULT_EXCLUDE skips build artifacts, tests; limits effective file count" 9 │ * @flows ProjectRoot -> #parser via fast-glob -- "Directory traversal path" 10 │ * @flows #parser -> ThreatModel via assembleModel -- "Aggregated threat model output" 11 │ * @boundary #parser and FileSystem (#fs-boundary) -- "Trust boundary between parser and disk I/O" 12 │ */ 13 │ 14 │ import fg from 'fast-glob'; 15 │ import { relative } from 'node:path'; 16 │ import type {
+
+
+
+
+
+ src/report/index.ts + + 2 + + +
+
+ +
+
+ L4 + comment + Report generation is pure transformation; no I/O in this module +
+
Report generation is pure transformation; no I/O in this module
+
1 │ /** 2 │ * GuardLink Report — exports. 3 │ * 4 │ * @comment -- "Report generation is pure transformation; no I/O in this module" 5 │ * @comment -- "File writes handled by CLI/MCP callers" 6 │ */ 7 │ 8 │ export { generateMermaid } from './mermaid.js'; 9 │ export { generateReport } from './report.js';
+
+
+
+ L5 + comment + File writes handled by CLI/MCP callers +
+
File writes handled by CLI/MCP callers
+
1 │ /** 2 │ * GuardLink Report — exports. 3 │ * 4 │ * @comment -- "Report generation is pure transformation; no I/O in this module" 5 │ * @comment -- "File writes handled by CLI/MCP callers" 6 │ */ 7 │ 8 │ export { generateMermaid } from './mermaid.js'; 9 │ export { generateReport } from './report.js'; 10 │
+
+
+
+
+
+ src/report/report.ts + + 4 + + +
+
+ +
+
+ L6 + comment + Pure function: transforms ThreatModel to markdown string +
+
Pure function: transforms ThreatModel to markdown string
+
1 │ /** 2 │ * GuardLink Report — Markdown report generator. 3 │ * Produces a human-readable threat model report with 4 │ * embedded Mermaid diagram, finding tables, and coverage stats. 5 │ * 6 │ * @comment -- "Pure function: transforms ThreatModel to markdown string" 7 │ * @comment -- "No file I/O; caller (CLI/MCP) handles write" 8 │ * @flows ThreatModel -> #report via generateReport -- "Model input" 9 │ * @flows #report -> Markdown via return -- "Report output" 10 │ */ 11 │
+
+
+
+ L7 + comment + No file I/O; caller (CLI/MCP) handles write +
+
No file I/O; caller (CLI/MCP) handles write
+
2 │ * GuardLink Report — Markdown report generator. 3 │ * Produces a human-readable threat model report with 4 │ * embedded Mermaid diagram, finding tables, and coverage stats. 5 │ * 6 │ * @comment -- "Pure function: transforms ThreatModel to markdown string" 7 │ * @comment -- "No file I/O; caller (CLI/MCP) handles write" 8 │ * @flows ThreatModel -> #report via generateReport -- "Model input" 9 │ * @flows #report -> Markdown via return -- "Report output" 10 │ */ 11 │ 12 │ import type { ThreatModel, ThreatModelExposure, Severity } from '../types/index.js';
+
+
+
+ L8 + flow + ThreatModel → #report +
+
Model input
+
3 │ * Produces a human-readable threat model report with 4 │ * embedded Mermaid diagram, finding tables, and coverage stats. 5 │ * 6 │ * @comment -- "Pure function: transforms ThreatModel to markdown string" 7 │ * @comment -- "No file I/O; caller (CLI/MCP) handles write" 8 │ * @flows ThreatModel -> #report via generateReport -- "Model input" 9 │ * @flows #report -> Markdown via return -- "Report output" 10 │ */ 11 │ 12 │ import type { ThreatModel, ThreatModelExposure, Severity } from '../types/index.js'; 13 │ import { generateMermaid } from './mermaid.js';
+
+
+
+ L9 + flow + #report → Markdown +
+
Report output
+
4 │ * embedded Mermaid diagram, finding tables, and coverage stats. 5 │ * 6 │ * @comment -- "Pure function: transforms ThreatModel to markdown string" 7 │ * @comment -- "No file I/O; caller (CLI/MCP) handles write" 8 │ * @flows ThreatModel -> #report via generateReport -- "Model input" 9 │ * @flows #report -> Markdown via return -- "Report output" 10 │ */ 11 │ 12 │ import type { ThreatModel, ThreatModelExposure, Severity } from '../types/index.js'; 13 │ import { generateMermaid } from './mermaid.js'; 14 │
+
+
+
+
+
+ src/review/index.ts + + 6 + + +
+
+ +
+
+ L10 + exposes + #cli → #arbitrary-write +
+
Writes @accepts/@audit annotations into source files
+
5 │ * Users walk through the GAL (Governance Acceptance List) and decide: 6 │ * accept — write @accepts + @audit (risk acknowledged, intentional) 7 │ * remediate — write @audit with planned-fix note 8 │ * skip — leave open for now 9 │ * 10 │ * @exposes #cli to #arbitrary-write [medium] cwe:CWE-73 -- "Writes @accepts/@audit annotations into source files" 11 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Only modifies files already in the parsed project" 12 │ * @audit #cli -- "Review decisions require human justification; no empty accepts allowed" 13 │ * @flows ThreatModel -> #cli via getReviewableExposures -- "Exposure list input" 14 │ * @flows #cli -> SourceFiles via writeFile -- "Annotation insertion output" 15 │ * @handles internal on #cli -- "Processes exposure metadata and user justification text"
+
+
+
+ L11 + mitigates + #path-validation mitigates #arbitrary-write +
+
Only modifies files already in the parsed project
+
6 │ * accept — write @accepts + @audit (risk acknowledged, intentional) 7 │ * remediate — write @audit with planned-fix note 8 │ * skip — leave open for now 9 │ * 10 │ * @exposes #cli to #arbitrary-write [medium] cwe:CWE-73 -- "Writes @accepts/@audit annotations into source files" 11 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Only modifies files already in the parsed project" 12 │ * @audit #cli -- "Review decisions require human justification; no empty accepts allowed" 13 │ * @flows ThreatModel -> #cli via getReviewableExposures -- "Exposure list input" 14 │ * @flows #cli -> SourceFiles via writeFile -- "Annotation insertion output" 15 │ * @handles internal on #cli -- "Processes exposure metadata and user justification text" 16 │ */
+
+
+
+ L12 + audit + Audit: #cli +
+
Review decisions require human justification; no empty accepts allowed
+
7 │ * remediate — write @audit with planned-fix note 8 │ * skip — leave open for now 9 │ * 10 │ * @exposes #cli to #arbitrary-write [medium] cwe:CWE-73 -- "Writes @accepts/@audit annotations into source files" 11 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Only modifies files already in the parsed project" 12 │ * @audit #cli -- "Review decisions require human justification; no empty accepts allowed" 13 │ * @flows ThreatModel -> #cli via getReviewableExposures -- "Exposure list input" 14 │ * @flows #cli -> SourceFiles via writeFile -- "Annotation insertion output" 15 │ * @handles internal on #cli -- "Processes exposure metadata and user justification text" 16 │ */ 17 │
+
+
+
+ L13 + flow + ThreatModel → #cli +
+
Exposure list input
+
8 │ * skip — leave open for now 9 │ * 10 │ * @exposes #cli to #arbitrary-write [medium] cwe:CWE-73 -- "Writes @accepts/@audit annotations into source files" 11 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Only modifies files already in the parsed project" 12 │ * @audit #cli -- "Review decisions require human justification; no empty accepts allowed" 13 │ * @flows ThreatModel -> #cli via getReviewableExposures -- "Exposure list input" 14 │ * @flows #cli -> SourceFiles via writeFile -- "Annotation insertion output" 15 │ * @handles internal on #cli -- "Processes exposure metadata and user justification text" 16 │ */ 17 │ 18 │ import { readFile, writeFile } from 'node:fs/promises';
+
+
+
+ L14 + flow + #cli → SourceFiles +
+
Annotation insertion output
+
9 │ * 10 │ * @exposes #cli to #arbitrary-write [medium] cwe:CWE-73 -- "Writes @accepts/@audit annotations into source files" 11 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Only modifies files already in the parsed project" 12 │ * @audit #cli -- "Review decisions require human justification; no empty accepts allowed" 13 │ * @flows ThreatModel -> #cli via getReviewableExposures -- "Exposure list input" 14 │ * @flows #cli -> SourceFiles via writeFile -- "Annotation insertion output" 15 │ * @handles internal on #cli -- "Processes exposure metadata and user justification text" 16 │ */ 17 │ 18 │ import { readFile, writeFile } from 'node:fs/promises'; 19 │ import { resolve } from 'node:path';
+
+
+
+ L15 + handles + #cli: internal +
+
Processes exposure metadata and user justification text
+
10 │ * @exposes #cli to #arbitrary-write [medium] cwe:CWE-73 -- "Writes @accepts/@audit annotations into source files" 11 │ * @mitigates #cli against #arbitrary-write using #path-validation -- "Only modifies files already in the parsed project" 12 │ * @audit #cli -- "Review decisions require human justification; no empty accepts allowed" 13 │ * @flows ThreatModel -> #cli via getReviewableExposures -- "Exposure list input" 14 │ * @flows #cli -> SourceFiles via writeFile -- "Annotation insertion output" 15 │ * @handles internal on #cli -- "Processes exposure metadata and user justification text" 16 │ */ 17 │ 18 │ import { readFile, writeFile } from 'node:fs/promises'; 19 │ import { resolve } from 'node:path'; 20 │ import { stripCommentPrefix } from '../parser/comment-strip.js';
+
+
+
+
+
+ src/tui/commands.ts + + 15 + + +
+
+ +
+
+ L7 + exposes + #tui → #path-traversal +
+
File paths from user args in /view, /sarif -o
+
2 │ * GuardLink TUI — Command implementations. 3 │ * 4 │ * Each command function takes (args, ctx) and prints output directly. 5 │ * Returns void. Throws on fatal errors. 6 │ * 7 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "File paths from user args in /view, /sarif -o" 8 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() with ctx.root constrains file access" 9 │ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files" 10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts"
+
+
+
+ L8 + mitigates + #path-validation mitigates #path-traversal +
+
resolve() with ctx.root constrains file access
+
3 │ * 4 │ * Each command function takes (args, ctx) and prints output directly. 5 │ * Returns void. Throws on fatal errors. 6 │ * 7 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "File paths from user args in /view, /sarif -o" 8 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() with ctx.root constrains file access" 9 │ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files" 10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage"
+
+
+
+ L9 + exposes + #tui → #arbitrary-write +
+
/report, /sarif, /dashboard write files
+
4 │ * Each command function takes (args, ctx) and prints output directly. 5 │ * Returns void. Throws on fatal errors. 6 │ * 7 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "File paths from user args in /view, /sarif -o" 8 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() with ctx.root constrains file access" 9 │ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files" 10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output"
+
+
+
+ L10 + mitigates + #path-validation mitigates #arbitrary-write +
+
Output paths resolved relative to project root
+
5 │ * Returns void. Throws on fatal errors. 6 │ * 7 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "File paths from user args in /view, /sarif -o" 8 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() with ctx.root constrains file access" 9 │ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files" 10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM"
+
+
+
+ L11 + exposes + #tui → #cmd-injection +
+
/annotate and /threat-report spawn child processes
+
6 │ * 7 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "File paths from user args in /view, /sarif -o" 8 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() with ctx.root constrains file access" 9 │ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files" 10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only"
+
+
+
+ L12 + audit + Audit: #tui +
+
Child process spawning delegated to agents/launcher.ts
+
7 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "File paths from user args in /view, /sarif -o" 8 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() with ctx.root constrains file access" 9 │ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files" 10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input"
+
+
+
+ L13 + exposes + #tui → #api-key-exposure +
+
/model handles API key input and storage
+
8 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() with ctx.root constrains file access" 9 │ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files" 10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output"
+
+
+
+ L14 + mitigates + #key-redaction mitigates #api-key-exposure +
+
API keys masked in /model show output
+
9 │ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files" 10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output" 19 │ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path"
+
+
+
+ L15 + exposes + #tui → #prompt-injection +
+
Freeform chat sends user text to LLM
+
10 │ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root" 11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output" 19 │ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path" 20 │ * @flows #tui -> #llm-client via chatCompletion -- "LLM API call path"
+
+
+
+ L16 + audit + Audit: #tui +
+
User freeform text passed to LLM via cmdChat; model context is read-only
+
11 │ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes" 12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output" 19 │ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path" 20 │ * @flows #tui -> #llm-client via chatCompletion -- "LLM API call path" 21 │ * @handles secrets on #tui -- "Processes and stores API keys via /model"
+
+
+
+ L17 + flow + UserArgs → #tui +
+
Command argument input
+
12 │ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts" 13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output" 19 │ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path" 20 │ * @flows #tui -> #llm-client via chatCompletion -- "LLM API call path" 21 │ * @handles secrets on #tui -- "Processes and stores API keys via /model" 22 │ */
+
+
+
+ L18 + flow + #tui → FileSystem +
+
Report/config output
+
13 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage" 14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output" 19 │ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path" 20 │ * @flows #tui -> #llm-client via chatCompletion -- "LLM API call path" 21 │ * @handles secrets on #tui -- "Processes and stores API keys via /model" 22 │ */ 23 │
+
+
+
+ L19 + flow + #tui → #agent-launcher +
+
Agent spawn path
+
14 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output" 15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output" 19 │ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path" 20 │ * @flows #tui -> #llm-client via chatCompletion -- "LLM API call path" 21 │ * @handles secrets on #tui -- "Processes and stores API keys via /model" 22 │ */ 23 │ 24 │ import { resolve, basename, isAbsolute } from 'node:path';
+
+
+
+ L20 + flow + #tui → #llm-client +
+
LLM API call path
+
15 │ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM" 16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output" 19 │ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path" 20 │ * @flows #tui -> #llm-client via chatCompletion -- "LLM API call path" 21 │ * @handles secrets on #tui -- "Processes and stores API keys via /model" 22 │ */ 23 │ 24 │ import { resolve, basename, isAbsolute } from 'node:path'; 25 │ import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
+
+
+
+ L21 + handles + #tui: secrets +
+
Processes and stores API keys via /model
+
16 │ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only" 17 │ * @flows UserArgs -> #tui via args -- "Command argument input" 18 │ * @flows #tui -> FileSystem via writeFile -- "Report/config output" 19 │ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path" 20 │ * @flows #tui -> #llm-client via chatCompletion -- "LLM API call path" 21 │ * @handles secrets on #tui -- "Processes and stores API keys via /model" 22 │ */ 23 │ 24 │ import { resolve, basename, isAbsolute } from 'node:path'; 25 │ import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs'; 26 │ import { parseProject, findDanglingRefs, findUnmitigatedExposures, findAcceptedWithoutAudit, findAcceptedExposures, clearAnnotations } from '../parser/index.js';
+
+
+
+
+
+ src/tui/config.ts + + 5 + + +
+
+ +
+
+ L7 + exposes + #tui → #api-key-exposure +
+
API keys loaded from and saved to config files
+
2 │ * GuardLink TUI — Config persistence for LLM settings. 3 │ * 4 │ * Now delegates to the unified agents/config.ts resolution chain. 5 │ * Keeps backward compatibility with tui-config.json (legacy). 6 │ * 7 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from and saved to config files" 8 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "Delegates to agents/config.ts with masking" 9 │ * @flows ConfigFile -> #tui via loadProjectConfig -- "Config load path" 10 │ * @flows #tui -> ConfigFile via saveProjectConfig -- "Config save path" 11 │ * @handles secrets on #tui -- "API keys stored in .guardlink/config.json" 12 │ */
+
+
+
+ L8 + mitigates + #key-redaction mitigates #api-key-exposure +
+
Delegates to agents/config.ts with masking
+
3 │ * 4 │ * Now delegates to the unified agents/config.ts resolution chain. 5 │ * Keeps backward compatibility with tui-config.json (legacy). 6 │ * 7 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from and saved to config files" 8 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "Delegates to agents/config.ts with masking" 9 │ * @flows ConfigFile -> #tui via loadProjectConfig -- "Config load path" 10 │ * @flows #tui -> ConfigFile via saveProjectConfig -- "Config save path" 11 │ * @handles secrets on #tui -- "API keys stored in .guardlink/config.json" 12 │ */ 13 │
+
+
+
+ L9 + flow + ConfigFile → #tui +
+
Config load path
+
4 │ * Now delegates to the unified agents/config.ts resolution chain. 5 │ * Keeps backward compatibility with tui-config.json (legacy). 6 │ * 7 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from and saved to config files" 8 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "Delegates to agents/config.ts with masking" 9 │ * @flows ConfigFile -> #tui via loadProjectConfig -- "Config load path" 10 │ * @flows #tui -> ConfigFile via saveProjectConfig -- "Config save path" 11 │ * @handles secrets on #tui -- "API keys stored in .guardlink/config.json" 12 │ */ 13 │ 14 │ import type { LLMConfig, LLMProvider } from '../analyze/llm.js';
+
+
+
+ L10 + flow + #tui → ConfigFile +
+
Config save path
+
5 │ * Keeps backward compatibility with tui-config.json (legacy). 6 │ * 7 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from and saved to config files" 8 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "Delegates to agents/config.ts with masking" 9 │ * @flows ConfigFile -> #tui via loadProjectConfig -- "Config load path" 10 │ * @flows #tui -> ConfigFile via saveProjectConfig -- "Config save path" 11 │ * @handles secrets on #tui -- "API keys stored in .guardlink/config.json" 12 │ */ 13 │ 14 │ import type { LLMConfig, LLMProvider } from '../analyze/llm.js'; 15 │ import { resolveConfig, saveProjectConfig, loadProjectConfig } from '../agents/config.js';
+
+
+
+ L11 + handles + #tui: secrets +
+
API keys stored in .guardlink/config.json
+
6 │ * 7 │ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "API keys loaded from and saved to config files" 8 │ * @mitigates #tui against #api-key-exposure using #key-redaction -- "Delegates to agents/config.ts with masking" 9 │ * @flows ConfigFile -> #tui via loadProjectConfig -- "Config load path" 10 │ * @flows #tui -> ConfigFile via saveProjectConfig -- "Config save path" 11 │ * @handles secrets on #tui -- "API keys stored in .guardlink/config.json" 12 │ */ 13 │ 14 │ import type { LLMConfig, LLMProvider } from '../analyze/llm.js'; 15 │ import { resolveConfig, saveProjectConfig, loadProjectConfig } from '../agents/config.js'; 16 │
+
+
+
+
+
+ src/tui/index.ts + + 8 + + +
+
+ +
+
+ L9 + exposes + #tui → #path-traversal +
+
User-supplied dir argument resolved via path.resolve
+
4 │ * GuardLink TUI — Interactive terminal interface. 5 │ * 6 │ * Claude Code-style inline REPL: stays in your terminal, 7 │ * slash commands + freeform AI chat, Ctrl+C to exit. 8 │ * 9 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 10 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() canonicalizes paths; starts from cwd" 11 │ * @exposes #tui to #api-key-exposure [medium] cwe:CWE-798 -- "API keys displayed in banner via resolveLLMConfig" 12 │ * @audit #tui -- "API keys masked via maskKey() in banner display" 13 │ * @flows UserInput -> #tui via readline -- "Interactive command input" 14 │ * @flows #tui -> Commands via dispatch -- "Command routing"
+
+
+
+ L10 + mitigates + #path-validation mitigates #path-traversal +
+
resolve() canonicalizes paths; starts from cwd
+
5 │ * 6 │ * Claude Code-style inline REPL: stays in your terminal, 7 │ * slash commands + freeform AI chat, Ctrl+C to exit. 8 │ * 9 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 10 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() canonicalizes paths; starts from cwd" 11 │ * @exposes #tui to #api-key-exposure [medium] cwe:CWE-798 -- "API keys displayed in banner via resolveLLMConfig" 12 │ * @audit #tui -- "API keys masked via maskKey() in banner display" 13 │ * @flows UserInput -> #tui via readline -- "Interactive command input" 14 │ * @flows #tui -> Commands via dispatch -- "Command routing" 15 │ * @boundary #tui and UserInput (#tui-input-boundary) -- "Trust boundary at interactive input"
+
+
+
+ L11 + exposes + #tui → #api-key-exposure +
+
API keys displayed in banner via resolveLLMConfig
+
6 │ * Claude Code-style inline REPL: stays in your terminal, 7 │ * slash commands + freeform AI chat, Ctrl+C to exit. 8 │ * 9 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 10 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() canonicalizes paths; starts from cwd" 11 │ * @exposes #tui to #api-key-exposure [medium] cwe:CWE-798 -- "API keys displayed in banner via resolveLLMConfig" 12 │ * @audit #tui -- "API keys masked via maskKey() in banner display" 13 │ * @flows UserInput -> #tui via readline -- "Interactive command input" 14 │ * @flows #tui -> Commands via dispatch -- "Command routing" 15 │ * @boundary #tui and UserInput (#tui-input-boundary) -- "Trust boundary at interactive input" 16 │ * @handles secrets on #tui -- "Displays LLM config including masked API keys"
+
+
+
+ L12 + audit + Audit: #tui +
+
API keys masked via maskKey() in banner display
+
7 │ * slash commands + freeform AI chat, Ctrl+C to exit. 8 │ * 9 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 10 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() canonicalizes paths; starts from cwd" 11 │ * @exposes #tui to #api-key-exposure [medium] cwe:CWE-798 -- "API keys displayed in banner via resolveLLMConfig" 12 │ * @audit #tui -- "API keys masked via maskKey() in banner display" 13 │ * @flows UserInput -> #tui via readline -- "Interactive command input" 14 │ * @flows #tui -> Commands via dispatch -- "Command routing" 15 │ * @boundary #tui and UserInput (#tui-input-boundary) -- "Trust boundary at interactive input" 16 │ * @handles secrets on #tui -- "Displays LLM config including masked API keys" 17 │ */
+
+
+
+ L13 + flow + UserInput → #tui +
+
Interactive command input
+
8 │ * 9 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 10 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() canonicalizes paths; starts from cwd" 11 │ * @exposes #tui to #api-key-exposure [medium] cwe:CWE-798 -- "API keys displayed in banner via resolveLLMConfig" 12 │ * @audit #tui -- "API keys masked via maskKey() in banner display" 13 │ * @flows UserInput -> #tui via readline -- "Interactive command input" 14 │ * @flows #tui -> Commands via dispatch -- "Command routing" 15 │ * @boundary #tui and UserInput (#tui-input-boundary) -- "Trust boundary at interactive input" 16 │ * @handles secrets on #tui -- "Displays LLM config including masked API keys" 17 │ */ 18 │
+
+
+
+ L14 + flow + #tui → Commands +
+
Command routing
+
9 │ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "User-supplied dir argument resolved via path.resolve" 10 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() canonicalizes paths; starts from cwd" 11 │ * @exposes #tui to #api-key-exposure [medium] cwe:CWE-798 -- "API keys displayed in banner via resolveLLMConfig" 12 │ * @audit #tui -- "API keys masked via maskKey() in banner display" 13 │ * @flows UserInput -> #tui via readline -- "Interactive command input" 14 │ * @flows #tui -> Commands via dispatch -- "Command routing" 15 │ * @boundary #tui and UserInput (#tui-input-boundary) -- "Trust boundary at interactive input" 16 │ * @handles secrets on #tui -- "Displays LLM config including masked API keys" 17 │ */ 18 │ 19 │ import { createInterface, type Interface } from 'node:readline';
+
+
+
+ L15 + boundary + #tui ↔ UserInput +
+
Trust boundary at interactive input
+
10 │ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() canonicalizes paths; starts from cwd" 11 │ * @exposes #tui to #api-key-exposure [medium] cwe:CWE-798 -- "API keys displayed in banner via resolveLLMConfig" 12 │ * @audit #tui -- "API keys masked via maskKey() in banner display" 13 │ * @flows UserInput -> #tui via readline -- "Interactive command input" 14 │ * @flows #tui -> Commands via dispatch -- "Command routing" 15 │ * @boundary #tui and UserInput (#tui-input-boundary) -- "Trust boundary at interactive input" 16 │ * @handles secrets on #tui -- "Displays LLM config including masked API keys" 17 │ */ 18 │ 19 │ import { createInterface, type Interface } from 'node:readline'; 20 │ import { resolve, basename } from 'node:path';
+
+
+
+ L16 + handles + #tui: secrets +
+
Displays LLM config including masked API keys
+
11 │ * @exposes #tui to #api-key-exposure [medium] cwe:CWE-798 -- "API keys displayed in banner via resolveLLMConfig" 12 │ * @audit #tui -- "API keys masked via maskKey() in banner display" 13 │ * @flows UserInput -> #tui via readline -- "Interactive command input" 14 │ * @flows #tui -> Commands via dispatch -- "Command routing" 15 │ * @boundary #tui and UserInput (#tui-input-boundary) -- "Trust boundary at interactive input" 16 │ * @handles secrets on #tui -- "Displays LLM config including masked API keys" 17 │ */ 18 │ 19 │ import { createInterface, type Interface } from 'node:readline'; 20 │ import { resolve, basename } from 'node:path'; 21 │ import { existsSync, readFileSync } from 'node:fs';
+
+
+
+
+
+ src/tui/input.ts + + 5 + + +
+
+ +
+
+ L15 + exposes + #tui → #dos +
+
Rapid keystrokes could consume CPU in raw mode
+
10 │ * /files Browse files 11 │ * /assets Asset tree 12 │ * 13 │ * Uses raw stdin mode for full keystroke control. 14 │ * 15 │ * @exposes #tui to #dos [low] cwe:CWE-400 -- "Rapid keystrokes could consume CPU in raw mode" 16 │ * @mitigates #tui against #dos using #resource-limits -- "Keystroke buffer bounded by terminal width" 17 │ * @flows RawStdin -> #tui via process.stdin -- "Raw keystroke input" 18 │ * @flows #tui -> Terminal via process.stdout -- "ANSI escape sequence output" 19 │ * @comment -- "Raw mode enables full keystroke control for command palette" 20 │ */
+
+
+
+ L16 + mitigates + #resource-limits mitigates #dos +
+
Keystroke buffer bounded by terminal width
+
11 │ * /assets Asset tree 12 │ * 13 │ * Uses raw stdin mode for full keystroke control. 14 │ * 15 │ * @exposes #tui to #dos [low] cwe:CWE-400 -- "Rapid keystrokes could consume CPU in raw mode" 16 │ * @mitigates #tui against #dos using #resource-limits -- "Keystroke buffer bounded by terminal width" 17 │ * @flows RawStdin -> #tui via process.stdin -- "Raw keystroke input" 18 │ * @flows #tui -> Terminal via process.stdout -- "ANSI escape sequence output" 19 │ * @comment -- "Raw mode enables full keystroke control for command palette" 20 │ */ 21 │
+
+
+
+ L17 + flow + RawStdin → #tui +
+
Raw keystroke input
+
12 │ * 13 │ * Uses raw stdin mode for full keystroke control. 14 │ * 15 │ * @exposes #tui to #dos [low] cwe:CWE-400 -- "Rapid keystrokes could consume CPU in raw mode" 16 │ * @mitigates #tui against #dos using #resource-limits -- "Keystroke buffer bounded by terminal width" 17 │ * @flows RawStdin -> #tui via process.stdin -- "Raw keystroke input" 18 │ * @flows #tui -> Terminal via process.stdout -- "ANSI escape sequence output" 19 │ * @comment -- "Raw mode enables full keystroke control for command palette" 20 │ */ 21 │ 22 │ import chalk from 'chalk';
+
+
+
+ L18 + flow + #tui → Terminal +
+
ANSI escape sequence output
+
13 │ * Uses raw stdin mode for full keystroke control. 14 │ * 15 │ * @exposes #tui to #dos [low] cwe:CWE-400 -- "Rapid keystrokes could consume CPU in raw mode" 16 │ * @mitigates #tui against #dos using #resource-limits -- "Keystroke buffer bounded by terminal width" 17 │ * @flows RawStdin -> #tui via process.stdin -- "Raw keystroke input" 18 │ * @flows #tui -> Terminal via process.stdout -- "ANSI escape sequence output" 19 │ * @comment -- "Raw mode enables full keystroke control for command palette" 20 │ */ 21 │ 22 │ import chalk from 'chalk'; 23 │
+
+
+
+ L19 + comment + Raw mode enables full keystroke control for command palette +
+
Raw mode enables full keystroke control for command palette
+
14 │ * 15 │ * @exposes #tui to #dos [low] cwe:CWE-400 -- "Rapid keystrokes could consume CPU in raw mode" 16 │ * @mitigates #tui against #dos using #resource-limits -- "Keystroke buffer bounded by terminal width" 17 │ * @flows RawStdin -> #tui via process.stdin -- "Raw keystroke input" 18 │ * @flows #tui -> Terminal via process.stdout -- "ANSI escape sequence output" 19 │ * @comment -- "Raw mode enables full keystroke control for command palette" 20 │ */ 21 │ 22 │ import chalk from 'chalk'; 23 │ 24 │ const BRAVOS = '#2dd4a7';
+
+
+
+
+
+ src/workspace/index.ts + + 1 + + +
+
+ +
+
+ L4 + comment + Workspace module: config loading, merge engine, link-project setup +
+
Workspace module: config loading, merge engine, link-project setup
+
1 │ /** 2 │ * GuardLink Workspace — Multi-repo linking and merge. 3 │ * 4 │ * @comment -- "Workspace module: config loading, merge engine, link-project setup" 5 │ */ 6 │ 7 │ export type { 8 │ WorkspaceConfig, WorkspaceRepo, 9 │ TagOwnership, UnresolvedRef, MergeWarning, MergeWarningCode,
+
+
+
+
+
+ src/workspace/link.ts + + 3 + + +
+
+ +
+
+ L7 + asset + Workspace.Link +
+
Multi-repo workspace linking setup
+
2 │ * GuardLink Workspace — link-project command logic. 3 │ * 4 │ * Scaffolds workspace.yaml in each repo and updates agent instruction 5 │ * files with workspace context so agents write cross-repo-aware annotations. 6 │ * 7 │ * @asset Workspace.Link (#workspace-link) -- "Multi-repo workspace linking setup" 8 │ * @flows UserArgs -> #workspace-link via linkProject -- "CLI args to workspace scaffolding" 9 │ * @flows #workspace-link -> AgentFiles via updateAgentWorkspaceContext -- "Inject workspace context" 10 │ */ 11 │ 12 │ import { existsSync, readFileSync, mkdirSync, readdirSync, statSync, unlinkSync } from 'node:fs';
+
+
+
+ L8 + flow + UserArgs → #workspace-link +
+
CLI args to workspace scaffolding
+
3 │ * 4 │ * Scaffolds workspace.yaml in each repo and updates agent instruction 5 │ * files with workspace context so agents write cross-repo-aware annotations. 6 │ * 7 │ * @asset Workspace.Link (#workspace-link) -- "Multi-repo workspace linking setup" 8 │ * @flows UserArgs -> #workspace-link via linkProject -- "CLI args to workspace scaffolding" 9 │ * @flows #workspace-link -> AgentFiles via updateAgentWorkspaceContext -- "Inject workspace context" 10 │ */ 11 │ 12 │ import { existsSync, readFileSync, mkdirSync, readdirSync, statSync, unlinkSync } from 'node:fs'; 13 │ import { writeFileSync } from 'node:fs';
+
+
+
+ L9 + flow + #workspace-link → AgentFiles +
+
Inject workspace context
+
4 │ * Scaffolds workspace.yaml in each repo and updates agent instruction 5 │ * files with workspace context so agents write cross-repo-aware annotations. 6 │ * 7 │ * @asset Workspace.Link (#workspace-link) -- "Multi-repo workspace linking setup" 8 │ * @flows UserArgs -> #workspace-link via linkProject -- "CLI args to workspace scaffolding" 9 │ * @flows #workspace-link -> AgentFiles via updateAgentWorkspaceContext -- "Inject workspace context" 10 │ */ 11 │ 12 │ import { existsSync, readFileSync, mkdirSync, readdirSync, statSync, unlinkSync } from 'node:fs'; 13 │ import { writeFileSync } from 'node:fs'; 14 │ import { resolve, basename, dirname, join } from 'node:path';
+
+
+
+
+
+ src/workspace/merge.ts + + 5 + + +
+
+ +
+
+ L7 + asset + Workspace.Merge +
+
Cross-repo threat model unification
+
2 │ * GuardLink Workspace — Merge engine for multi-repo reports. 3 │ * 4 │ * Takes N per-repo report JSONs and produces a unified MergedReport 5 │ * with cross-repo tag resolution, warning detection, and aggregated stats. 6 │ * 7 │ * @asset Workspace.Merge (#merge-engine) -- "Cross-repo threat model unification" 8 │ * @threat Tag_Collision (#tag-collision) [medium] -- "Duplicate tag definitions across repos" 9 │ * @mitigates #merge-engine against #tag-collision using #prefix-ownership -- "Tag prefix determines owning repo" 10 │ * @flows ReportJSON -> #merge-engine via mergeReports -- "Per-repo reports feed into merge" 11 │ * @flows #merge-engine -> MergedReport via mergeReports -- "Unified output" 12 │ */
+
+
+
+ L8 + threat + Tag_Collision +
+
Duplicate tag definitions across repos
+
3 │ * 4 │ * Takes N per-repo report JSONs and produces a unified MergedReport 5 │ * with cross-repo tag resolution, warning detection, and aggregated stats. 6 │ * 7 │ * @asset Workspace.Merge (#merge-engine) -- "Cross-repo threat model unification" 8 │ * @threat Tag_Collision (#tag-collision) [medium] -- "Duplicate tag definitions across repos" 9 │ * @mitigates #merge-engine against #tag-collision using #prefix-ownership -- "Tag prefix determines owning repo" 10 │ * @flows ReportJSON -> #merge-engine via mergeReports -- "Per-repo reports feed into merge" 11 │ * @flows #merge-engine -> MergedReport via mergeReports -- "Unified output" 12 │ */ 13 │
+
+
+
+ L9 + mitigates + #prefix-ownership mitigates #tag-collision +
+
Tag prefix determines owning repo
+
4 │ * Takes N per-repo report JSONs and produces a unified MergedReport 5 │ * with cross-repo tag resolution, warning detection, and aggregated stats. 6 │ * 7 │ * @asset Workspace.Merge (#merge-engine) -- "Cross-repo threat model unification" 8 │ * @threat Tag_Collision (#tag-collision) [medium] -- "Duplicate tag definitions across repos" 9 │ * @mitigates #merge-engine against #tag-collision using #prefix-ownership -- "Tag prefix determines owning repo" 10 │ * @flows ReportJSON -> #merge-engine via mergeReports -- "Per-repo reports feed into merge" 11 │ * @flows #merge-engine -> MergedReport via mergeReports -- "Unified output" 12 │ */ 13 │ 14 │ import { readFile } from 'node:fs/promises';
+
+
+
+ L10 + flow + ReportJSON → #merge-engine +
+
Per-repo reports feed into merge
+
5 │ * with cross-repo tag resolution, warning detection, and aggregated stats. 6 │ * 7 │ * @asset Workspace.Merge (#merge-engine) -- "Cross-repo threat model unification" 8 │ * @threat Tag_Collision (#tag-collision) [medium] -- "Duplicate tag definitions across repos" 9 │ * @mitigates #merge-engine against #tag-collision using #prefix-ownership -- "Tag prefix determines owning repo" 10 │ * @flows ReportJSON -> #merge-engine via mergeReports -- "Per-repo reports feed into merge" 11 │ * @flows #merge-engine -> MergedReport via mergeReports -- "Unified output" 12 │ */ 13 │ 14 │ import { readFile } from 'node:fs/promises'; 15 │ import { basename } from 'node:path';
+
+
+
+ L11 + flow + #merge-engine → MergedReport +
+
Unified output
+
6 │ * 7 │ * @asset Workspace.Merge (#merge-engine) -- "Cross-repo threat model unification" 8 │ * @threat Tag_Collision (#tag-collision) [medium] -- "Duplicate tag definitions across repos" 9 │ * @mitigates #merge-engine against #tag-collision using #prefix-ownership -- "Tag prefix determines owning repo" 10 │ * @flows ReportJSON -> #merge-engine via mergeReports -- "Per-repo reports feed into merge" 11 │ * @flows #merge-engine -> MergedReport via mergeReports -- "Unified output" 12 │ */ 13 │ 14 │ import { readFile } from 'node:fs/promises'; 15 │ import { basename } from 'node:path'; 16 │ import type {
+
+
+
+
+
+ src/workspace/metadata.ts + + 3 + + +
+
+ +
+
+ L7 + asset + Workspace.Metadata +
+
Report provenance data
+
2 │ * GuardLink Workspace — Report metadata population. 3 │ * 4 │ * Enriches a ThreatModel with provenance metadata (git SHA, branch, 5 │ * workspace info) for the report JSON contract. 6 │ * 7 │ * @asset Workspace.Metadata (#report-metadata) -- "Report provenance data" 8 │ * @flows GitRepo -> #report-metadata via execSync -- "Git info extraction" 9 │ * @flows #report-metadata -> ThreatModel via populateMetadata -- "Metadata injection" 10 │ */ 11 │ 12 │ import { execSync } from 'node:child_process';
+
+
+
+ L8 + flow + GitRepo → #report-metadata +
+
Git info extraction
+
3 │ * 4 │ * Enriches a ThreatModel with provenance metadata (git SHA, branch, 5 │ * workspace info) for the report JSON contract. 6 │ * 7 │ * @asset Workspace.Metadata (#report-metadata) -- "Report provenance data" 8 │ * @flows GitRepo -> #report-metadata via execSync -- "Git info extraction" 9 │ * @flows #report-metadata -> ThreatModel via populateMetadata -- "Metadata injection" 10 │ */ 11 │ 12 │ import { execSync } from 'node:child_process'; 13 │ import { readFileSync, existsSync } from 'node:fs';
+
+
+
+ L9 + flow + #report-metadata → ThreatModel +
+
Metadata injection
+
4 │ * Enriches a ThreatModel with provenance metadata (git SHA, branch, 5 │ * workspace info) for the report JSON contract. 6 │ * 7 │ * @asset Workspace.Metadata (#report-metadata) -- "Report provenance data" 8 │ * @flows GitRepo -> #report-metadata via execSync -- "Git info extraction" 9 │ * @flows #report-metadata -> ThreatModel via populateMetadata -- "Metadata injection" 10 │ */ 11 │ 12 │ import { execSync } from 'node:child_process'; 13 │ import { readFileSync, existsSync } from 'node:fs'; 14 │ import { join } from 'node:path';
+
+
+
+
+
+ src/workspace/types.ts + + 3 + + +
+
+ +
+
+ L7 + asset + Workspace.Config +
+
Multi-repo workspace definition
+
2 │ * GuardLink Workspace — Types for multi-repo linking. 3 │ * 4 │ * workspace.yaml lives in each repo's .guardlink/ directory. 5 │ * It declares membership in a workspace and lists sibling repos. 6 │ * 7 │ * @asset Workspace.Config (#workspace-config) -- "Multi-repo workspace definition" 8 │ * @threat Config_Tampering (#config-tamper) [medium] cwe:CWE-15 -- "Malicious workspace.yaml could misdirect agent annotations" 9 │ * @mitigates #workspace-config against #config-tamper using #yaml-validation -- "Schema validation on load" 10 │ */ 11 │ 12 │ import type { ThreatModel, Severity, ExternalRef } from '../types/index.js';
+
+
+
+ L8 + threat + Config_Tampering +
+
Malicious workspace.yaml could misdirect agent annotations
+
3 │ * 4 │ * workspace.yaml lives in each repo's .guardlink/ directory. 5 │ * It declares membership in a workspace and lists sibling repos. 6 │ * 7 │ * @asset Workspace.Config (#workspace-config) -- "Multi-repo workspace definition" 8 │ * @threat Config_Tampering (#config-tamper) [medium] cwe:CWE-15 -- "Malicious workspace.yaml could misdirect agent annotations" 9 │ * @mitigates #workspace-config against #config-tamper using #yaml-validation -- "Schema validation on load" 10 │ */ 11 │ 12 │ import type { ThreatModel, Severity, ExternalRef } from '../types/index.js'; 13 │
+
+
+
+ L9 + mitigates + #yaml-validation mitigates #config-tamper +
+
Schema validation on load
+
4 │ * workspace.yaml lives in each repo's .guardlink/ directory. 5 │ * It declares membership in a workspace and lists sibling repos. 6 │ * 7 │ * @asset Workspace.Config (#workspace-config) -- "Multi-repo workspace definition" 8 │ * @threat Config_Tampering (#config-tamper) [medium] cwe:CWE-15 -- "Malicious workspace.yaml could misdirect agent annotations" 9 │ * @mitigates #workspace-config against #config-tamper using #yaml-validation -- "Schema validation on load" 10 │ */ 11 │ 12 │ import type { ThreatModel, Severity, ExternalRef } from '../types/index.js'; 13 │ 14 │ // ─── Workspace Configuration (workspace.yaml) ───────────────────────
+
+
+
+ + +
File Coverage
+
+ 38 of 60 files + have GuardLink annotations +
+
+ + +
⚠ Unannotated Files (22)
+

+ Source files with no GuardLink annotations. Not all files need annotations — only those touching security boundaries. +

+
+
.github/ISSUE_TEMPLATE/bug_report.yml
.github/ISSUE_TEMPLATE/config.yml
.github/ISSUE_TEMPLATE/feature_request.yml
.github/workflows/ci.yml
.github/workflows/release.yml
examples/ci/per-repo-report.yml
examples/ci/workspace-merge.yml
examples/github-action.yml
src/dashboard/data.ts
src/dashboard/diagrams.ts
src/diff/engine.ts
src/diff/format.ts
src/index.ts
src/init/picker.ts
src/init/templates.ts
src/parser/comment-strip.ts
src/parser/index.ts
src/parser/normalize.ts
src/parser/validate.ts
src/report/mermaid.ts
src/tui/format.ts
src/types/index.ts
+
+
+ +
+
🔒 Data & Boundaries
+ + +
Trust Boundaries
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Side ASide BDescriptionLocation
#agent-launcherAgentProcessTrust boundary at process spawnsrc/agents/launcher.ts:20
#llm-clientLLMProviderTrust boundary at external API callsrc/analyze/llm.ts:22
#llm-clientNVDTrust boundary at external APIsrc/analyze/tools.ts:18
#cliUserInputTrust boundary at CLI argument parsingsrc/cli/index.ts:35
#diffGitRepoTrust boundary at git command executionsrc/diff/git.ts:15
#mcpMCPClientTrust boundary at MCP protocolsrc/mcp/index.ts:7
#mcpMCPClientTrust boundary at tool argument parsingsrc/mcp/server.ts:40
#parserFileSystemTrust boundary between parser and disk I/Osrc/parser/parse-project.ts:11
#tuiUserInputTrust boundary at interactive inputsrc/tui/index.ts:15
+ + +
Data Classifications
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassificationAssetDescriptionLocation
secrets#agent-launcherProcesses and stores LLM API keyssrc/agents/config.ts:22
internal#agent-launcherSerializes threat model IDs and flows into promptsrc/agents/prompts.ts:13
internal#llm-clientProcesses project dependencies, env examples, code snippetssrc/analyze/index.ts:17
secrets#llm-clientProcesses API keys for authenticationsrc/analyze/llm.ts:23
secrets#cliProcesses API keys via config commandssrc/cli/index.ts:36
internal#dashboardProcesses and displays threat model datasrc/dashboard/generate.ts:15
internal#initGenerates definitions and agent instruction contentsrc/init/index.ts:17
internal#mcpProcesses project annotations and threat model datasrc/mcp/server.ts:41
internal#parserOperates on project source files onlysrc/parser/clear.ts:13
internal#cliProcesses exposure metadata and user justification textsrc/review/index.ts:15
secrets#tuiProcesses and stores API keys via /modelsrc/tui/commands.ts:21
secrets#tuiAPI keys stored in .guardlink/config.jsonsrc/tui/config.ts:11
secrets#tuiDisplays LLM config including masked API keyssrc/tui/index.ts:16
+ + + + + + +
Audit Items (19)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AssetDescriptionLocation
#agent-launcherPrompt content is opaque to agent binary; injection risk depends on agent implementationsrc/agents/launcher.ts:14
#agent-launcherTimeout intentionally omitted for interactive sessions; inline mode has implicit controlsrc/agents/launcher.ts:16
#agent-launcherPrompt injection mitigated by agent's own safety measures; GuardLink prompt is read-only contextsrc/agents/prompts.ts:7
#llm-clientThreat model data intentionally sent to LLM for analysissrc/analyze/index.ts:13
#llm-clientPrompt injection mitigated by LLM provider safety; local code is read-onlysrc/analyze/llm.ts:18
#sarifSARIF output intentionally reveals security findings for CI/CD integrationsrc/analyzer/sarif.ts:16
#cliChild process spawning delegated to agents/launcher.ts with explicit argssrc/cli/index.ts:32
#diffGit commands use execSync; ref is validated with rev-parse before usesrc/diff/index.ts:5
#initConfig file may contain API keys; .gitignore entry added automaticallysrc/init/index.ts:13
#mcpAll tool calls validated by server.ts before executionsrc/mcp/index.ts:5
#mcpUser prompts passed to LLM; model context is read-onlysrc/mcp/server.ts:31
#mcpThreat model data intentionally exposed to connected agentssrc/mcp/server.ts:35
#suggestFile size is bounded by project scope; production use involves reasonable file sizessrc/mcp/suggest.ts:17
#parserDestructive operation requires explicit user confirmation via dryRun flagsrc/parser/clear.ts:10
#parserPath validation delegated to callers (CLI/MCP validate root)src/parser/parse-file.ts:7
#cliReview decisions require human justification; no empty accepts allowedsrc/review/index.ts:12
#tuiChild process spawning delegated to agents/launcher.tssrc/tui/commands.ts:12
#tuiUser freeform text passed to LLM via cmdChat; model context is read-onlysrc/tui/commands.ts:16
#tuiAPI keys masked via maskKey() in banner displaysrc/tui/index.ts:12
+ + + + +
Shielded Regions (16)
+

Code regions where annotations are intentionally suppressed via @shield.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReasonLocation
Example annotation block for reference, excluded from parsingsrc/agents/prompts.ts:148
No reason providedsrc/agents/prompts.ts:161
Description examples, excluded from parsingsrc/agents/prompts.ts:168
No reason providedsrc/agents/prompts.ts:178
Flow examples, excluded from parsingsrc/agents/prompts.ts:185
No reason providedsrc/agents/prompts.ts:194
Boundary examples, excluded from parsingsrc/agents/prompts.ts:201
No reason providedsrc/agents/prompts.ts:207
Placement examples, excluded from parsingsrc/agents/prompts.ts:214
No reason providedsrc/agents/prompts.ts:223
@accepts alternative examples, excluded from parsingsrc/agents/prompts.ts:250
No reason providedsrc/agents/prompts.ts:260
Definition syntax examples, excluded from parsingsrc/agents/prompts.ts:277
No reason providedsrc/agents/prompts.ts:281
Relationship syntax examples, excluded from parsingsrc/agents/prompts.ts:286
No reason providedsrc/agents/prompts.ts:299
+ + +
Developer Comments (18)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CommentLocation
Agent binaries are hardcoded; no user-controlled binary namessrc/agents/index.ts:7
parseAgentFlag extracts flags from args; no injection risksrc/agents/index.ts:8
Prompt templates are static; no user input interpolation in system promptssrc/analyze/prompts.ts:7
customPrompt is appended to user message, not system prompt — bounded injection risksrc/analyze/prompts.ts:8
SARIF generation is pure transformation; no I/O in this modulesrc/analyzer/index.ts:4
File writes handled by CLI/MCP callerssrc/analyzer/index.ts:5
Pure function: transforms ThreatModel to SARIF JSON; no I/Osrc/analyzer/sarif.ts:17
Self-contained HTML; no external data injection after generationsrc/dashboard/index.ts:7
Detection is read-only; no file writessrc/init/detect.ts:8
Pure function; no I/O; operates on in-memory ThreatModelsrc/mcp/lookup.ts:19
Skips node_modules and .guardlink directoriessrc/mcp/suggest.ts:20
Regex patterns designed with bounded quantifiers and explicit structuresrc/parser/parse-line.ts:7
Report generation is pure transformation; no I/O in this modulesrc/report/index.ts:4
File writes handled by CLI/MCP callerssrc/report/index.ts:5
Pure function: transforms ThreatModel to markdown stringsrc/report/report.ts:6
No file I/O; caller (CLI/MCP) handles writesrc/report/report.ts:7
Raw mode enables full keystroke control for command palettesrc/tui/input.ts:19
Workspace module: config loading, merge engine, link-project setupsrc/workspace/index.ts:4
+ + +
+ +
+
🗺 Asset Risk Heatmap
+

Assets sorted by risk level. Unmitigated exposures increase risk. Click an asset for details.

+ +
+ +
+
#mcp
+
+ ⚠ 7 + 🛡 4 + ↔ 6 +
+
internal
+
+
+
#parser
+
+ ⚠ 7 + 🛡 4 + ↔ 6 +
+
internal
+
+
+
#tui
+
+ ⚠ 9 + 🛡 6 + ↔ 10 +
+
secretssecretssecrets
+
+
+
#agent-launcher
+
+ ⚠ 8 + 🛡 6 + ↔ 10 +
+
secretsinternal
+
+
+
#llm-client
+
+ ⚠ 9 + 🛡 7 + ↔ 11 +
+
internalsecrets
+
+
+
#sarif
+
+ ⚠ 1 + 🛡 0 + ↔ 2 +
+ +
+
+
#cli
+
+ ⚠ 5 + 🛡 4 + ↔ 4 +
+
secretsinternal
+
+
+
#diff
+
+ ⚠ 4 + 🛡 3 + ↔ 4 +
+ +
+
+
#init
+
+ ⚠ 4 + 🛡 3 + ↔ 4 +
+
internal
+
+
+
#suggest
+
+ ⚠ 3 + 🛡 2 + ↔ 2 +
+ +
+
+
#dashboard
+
+ ⚠ 3 + 🛡 3 + ↔ 4 +
+
internal
+
+
+
GuardLink.Parser
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.CLI
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.TUI
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.MCP
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.LLM_Client
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.Dashboard
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.Init
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.Agent_Launcher
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.Diff
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.Report
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.SARIF
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
GuardLink.Suggest
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
Workspace.Link
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
Workspace.Merge
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
Workspace.Metadata
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
Workspace.Config
+
+ ⚠ 0 + 🛡 0 + ↔ 0 +
+ +
+
+
#merge-engine
+
+ ⚠ 0 + 🛡 1 + ↔ 2 +
+ +
+
+
#workspace-config
+
+ ⚠ 0 + 🛡 1 + ↔ 0 +
+ +
+
+
EnvVars
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
ConfigFile
+
+ ⚠ 0 + 🛡 0 + ↔ 5 +
+ +
+
+
UserPrompt
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
AgentProcess
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
ThreatModel
+
+ ⚠ 0 + 🛡 0 + ↔ 10 +
+ +
+
+
AgentPrompt
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
ProjectFiles
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
ReportFile
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
LLMConfig
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
LLMProvider
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
LLMToolCall
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
NVD
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
SarifLog
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
UserArgs
+
+ ⚠ 0 + 🛡 0 + ↔ 3 +
+ +
+
+
FileSystem
+
+ ⚠ 0 + 🛡 0 + ↔ 3 +
+ +
+
+
SourceFiles
+
+ ⚠ 0 + 🛡 0 + ↔ 3 +
+ +
+
+
HTML
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
GitRef
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
TempDir
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
ProjectRoot
+
+ ⚠ 0 + 🛡 0 + ↔ 4 +
+ +
+
+
AgentFiles
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
MCPClient
+
+ ⚠ 0 + 🛡 0 + ↔ 3 +
+ +
+
+
QueryString
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
FilePath
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
Suggestions
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
Annotations
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
#report
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
Markdown
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
UserInput
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
Commands
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
RawStdin
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
Terminal
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
#workspace-link
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
ReportJSON
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
MergedReport
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
GitRepo
+
+ ⚠ 0 + 🛡 0 + ↔ 1 +
+ +
+
+
#report-metadata
+
+ ⚠ 0 + 🛡 0 + ↔ 2 +
+ +
+
+
+ +
+
+ + +
+
+
+

Details

+ +
+
+
+ + + + + \ No newline at end of file