{"repo_url":"https://github.com/Azure/Security-Copilot","overall_status":"completed","scanned_at":"2026-10-14T23:52:14.666Z","scan_summary":{"total_components":3,"worst_case_severity":"HIGH","repo_trust_score":{"score":60,"tier":"low","capability_band":"high","score_confidence":"low","score_interval":{"low":36,"high":84},"factors":["ATR-C0007 HIGH","ATR-C0010 MEDIUM","ATR-C0011 HIGH","ATR-C0012 MEDIUM"]}},"components":[{"artifact_version":"2.0","component":{"component_type":"api-server","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing","component_path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing","metadata":{"transports":["http"]}},"scan_provenance":{"scanned_at":"2026-10-14T23:52:14.666Z","resolved_ref":"79ee8ea8a3ce7f7ebd906fe61d7be03af668614a","resolved_ver":null},"repo_context":{"repo_url":"https://github.com/Azure/Security-Copilot","languages":["YAML","JSON","PowerShell","Python","Markdown"],"transports_detected":[],"deployment_artifacts":["Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing/functionapp_azuredeploy.json","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/functionapp_azuredeploy.json","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing/FunctionApp.zip","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionApp.zip","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip",".github/workflows/codeql.yml",".github/dependabot.yml"],"provenance":{"publisher":"Azure","publisher_verified":true,"signed_build":false,"dependency_cve_count":23,"maintenance_active":false,"declared_policy":false}},"component_findings":[{"rule_id":"ATR-M0001","rule_version":"1.2.0","rule_name":"Tool Definition Integrity & Versioning (ETDI-style)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository; attached only to satisfy per-component reporting. Repo-wide grep for MCP registration patterns found no matches.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents rug-pull tool poisoning.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0002","rule_version":"1.1.0","rule_name":"Unrestricted Tool Permissions (Overprivileged Tools)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Limits blast radius and privilege escalation.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0003","rule_version":"1.3.1","rule_name":"CORS / Origin / Host Validation (DNS Rebinding Defense)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server (stdio/SSE/streamable-HTTP) component exists in this repository.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents DNS rebinding/browser hijack of local or remote MCP.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0004","rule_version":"1.2.0","rule_name":"Binding to 0.0.0.0 Without Auth/TLS","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository; Azure Function Apps use the managed Functions host, not a self-managed listener.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"LAN/Internet exposure enables remote exploitation.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0005","rule_version":"1.4.0","rule_name":"OAuth 2.1 + PKCE Correctness (MCP Authorization)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Misconfig enables token theft and confused-deputy attacks.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0006","rule_version":"1.2.0","rule_name":"Tool Name Collision / Spoofing","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No MCP server/tool registry exists in this repository.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents malicious tool shadowing.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0007","rule_version":"1.2.0","rule_name":"Prompt/Metadata Injection in Tool Descriptions","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No MCP server/tool-definition registry exists in this repository.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents covert model manipulation.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0008","rule_version":"1.2.0","rule_name":"CORS Misuse: Wildcard with Credentials","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents credentialed cross-origin abuse.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0009","rule_version":"1.3.0","rule_name":"Transport Security: TLS Everywhere (Remote)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"This component is an Azure Function App, not an MCP server, and it exposes no remote MCP transport (SSE or streamable-HTTP) for ATR-M0009's TLS-everywhere requirement to apply to. The managed HTTPS endpoint Azure provides is unrelated to the MCP-specific remote-transport TLS obligation this rule targets, so NOT_APPLICABLE reflects the rule's applicability precondition rather than an assessment of TLS configuration quality.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"MitM can steal tokens and tamper responses.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0010","rule_version":"1.4.0","rule_name":"No Authentication or Authorization Checks (General)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents unauthorized tool use and data access.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"rule_id":"ATR-M0011","rule_version":"1.2.0","rule_name":"OAuth Proxy Per-Client Consent (Confused Deputy Defense)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"No MCP server / OAuth proxy component exists in this repository.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Shared upstream client + dynamic MCP-client registration + no per-client consent enables attacker-registered MCP clients to receive bridge codes carrying victim upstream tokens — the documented MCP Confused Deputy attack.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"}],"repo_findings_inherited":[{"rule_id":"ATR-C0001","rule_version":"1.2.0","rule_name":"Unrestricted Network Fetch / SSRF","finding":"UNKNOWN","severity":"HIGH","realized_severity":null,"confidence":"low","rationale":"Manual review (via python zipfile extraction, not committed as extracted source) of FunctionApp.zip's parse_email/__init__.py shows an expand_url() helper that calls requests.Session().head(url, allow_redirects=True) on email-derived URLs gated only by a hardcoded shortener-domain allowlist (no private-IP/loopback/metadata denylist), which looks like a plausible SSRF primitive. However, this code exists ONLY inside a committed binary zip deployment artifact (FunctionApp.zip) and is not present as an extracted/plain-text file anywhere in the repository tree, so it cannot be cited with a repo-relative path + line-number snippet that is independently verifiable by opening that path in the repo (the actual repo file at that path is binary zip bytes, not the Python source). Per the evidence contract, required_evidence classes could not be established against a verifiable repo-relative source file. Abstaining rather than asserting VULNERABLE against unverifiable evidence.","vulnerability_details":null,"fix_guidance":"Extract and commit function source as plain text (not only as a zip blob) for reviewability; add IP-class validation (resolve host, reject RFC1918/loopback/link-local/169.254.169.254) before any outbound HEAD/GET request derived from email content.","why_this_matters":"Enables internal pivoting and data exfiltration.","context_note":null,"within_declared_contract":true,"transport_gated":null,"mitigation_present":true,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0002","rule_version":"1.3.2","rule_name":"Static Secrets","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"medium","rationale":"Gitleaks scan (0 findings) plus manual grep for API_KEY/SECRET/TOKEN/PASSWORD literal assignments across YAML/JSON/PS1/Python files found no committed secret VALUES -- only schema/property names (e.g. 'apiAccessToken', 'token:' as an OpenAPI schema field name in Netskope/CrowdSec plugin specs) and placeholder example URLs (https://example.com). The PromptBooks PowerShell scripts require the operator to pass a bearer token as a command-line parameter (-token) copied manually from browser devtools each run; no token is hardcoded or persisted in the repo. No .env files with real values, no AKIA/ghp_/sk- patterns found.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Plaintext secrets are easily exfiltrated.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Plugins/Published Plugins/CrowdSecTI/crowdsecTI_smoke.yaml","start_line":62,"end_line":68,"snippet":"      security:\n        - api_key: []\n  \ncomponents:\n  securitySchemes:\n    api_key:\n      type: \"apiKey\"\n      name: \"x-api-key\"\n      in: \"header\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0003","rule_version":"1.3.0","rule_name":"Runtime Command Injection via Process Execution","finding":"UNKNOWN","severity":"CRITICAL","realized_severity":null,"confidence":"medium","rationale":"Manual archive extraction found only a single subprocess call in application code: a fixed-argv invocation of 'antiword' with a locally generated temp-file path as its only argument, with no shell=True and no attacker-controlled command text reaching the sink; no eval()/Function()/dynamic-code-execution pattern was found elsewhere. However, this code exists only inside a committed binary ZIP deployment artifact and is not present as an extracted, plain-text file at a stable repository path, so the required source citation cannot be independently re-opened and re-verified at that path. Given this unresolved source-attestation gap, the verdict is UNKNOWN rather than SECURE.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Unsanitized command construction in shipped runtime code can give a remote attacker arbitrary code execution with the application's privileges.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::extractors/word_extractor.py","start_line":100,"end_line":110,"snippet":"with tempfile.NamedTemporaryFile(delete=False) as temp_file:\n    temp_file.write(word_data)\n    temp_file_path = temp_file.name\ntry:\n    result = subprocess.run(\n        [\"antiword\", temp_file_path],\n        capture_output=True,\n        text=True,\n        check=True\n    )"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0004","rule_version":"1.2.0","rule_name":"DoS Protections: Timeouts, Concurrency, Streaming Limits","finding":"UNKNOWN","severity":"MEDIUM","realized_severity":null,"confidence":"low","rationale":"Manual extraction of FunctionAppV2.zip shows function_app.py accepting a caller-supplied 'max_depth' query parameter with no upper-bound clamp, passed into parsers/email_parser.py's recursive parse_email(), and no visible request-body-size limit in host.json. This looks like a plausible unbounded-recursion/resource-exhaustion vector, but the code exists only inside a committed binary zip deployment artifact, not as an extracted plain-text file at a reviewable repo path -- so a reviewer opening the cited path sees zip bytes, not the Python source quoted in evidence. Abstaining to UNKNOWN rather than asserting VULNERABLE against unverifiable evidence.","vulnerability_details":null,"fix_guidance":"Commit function source as extracted plain text for reviewability; clamp max_depth to a fixed ceiling; add a request body size limit and a processing time budget around attachment parsing.","why_this_matters":"Resource exhaustion can crash or stall MCP.","context_note":null,"within_declared_contract":true,"transport_gated":false,"mitigation_present":false,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0005","rule_version":"1.2.0","rule_name":"Logging Hygiene (No Secrets/PII/Tokens) & Audit Trail","finding":"UNKNOWN","severity":"MEDIUM","realized_severity":null,"confidence":"low","rationale":"The Function App code (committed only as binary FunctionApp.zip / FunctionAppV2.zip, not extracted plain text) uses Python logging extensively with DEBUG-level statements that could log request bodies/content in some paths (e.g. parse_email/__init__.py logs 'Raw request body (as bytes)' truncated to 100 chars, and various functions log full decoded content at DEBUG level). host.json sets default logLevel to 'Debug' for both Function Apps, which in production would surface verbose content (including potentially PII from parsed phishing emails) into Application Insights logs. However, because this code exists only inside committed zip binaries and not as reviewable plain-text repo files, a definitive source-to-sink citation at a stable repo path/line cannot be established per the evidence contract. The PowerShell Promptbook scripts avoid logging the bearer token itself (Write-Host calls never echo $token or $headers). Abstaining on the Function App logging question specifically due to the binary-artifact citation issue; the PowerShell scripts alone would be SECURE but are evaluated together with the Function Apps for this repo-level rule.","vulnerability_details":null,"fix_guidance":"Extract and commit function source as plain text; set host.json default logLevel to Information/Warning for production; ensure DEBUG-level logs that include email body/attachment content are gated off outside of explicit troubleshooting.","why_this_matters":"Prevents sensitive data leakage; enables forensics.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":["parse_email_functionapp","parse_email (FunctionApp v1)"],"component_name":null},{"rule_id":"ATR-C0006","rule_version":"1.2.0","rule_name":"Container/Runtime Hardening","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No Dockerfile, docker-compose, Helm chart, or Kubernetes manifest exists anywhere in this repository (confirmed via repo-wide find for Dockerfile*/docker-compose*/*.tf and directory listing). Deployment artifacts present are Azure ARM/Logic App JSON templates and Azure Function App zip packages, which run on Azure's managed PaaS compute (Functions/Logic Apps/App Service) rather than a repo-controlled container image, so there is no container hardening surface (USER, capabilities, seccomp, hostNetwork) for this rule to evaluate.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Reduces blast radius of exploits.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0007","rule_version":"1.2.0","rule_name":"Dependency Risk & Supply Chain","finding":"VULNERABLE","severity":"HIGH","realized_severity":"HIGH","confidence":"medium","rationale":"The FunctionAppV2 requirements.txt uses open-ended version ranges ('azure-functions' with no version at all; 'tnefparse>=1.4.0', 'extract-msg>=0.30.0', etc.) with no lockfile pinning exact resolved versions, and GitHub Actions workflow dependencies float on mutable tags (actions/checkout@v4, github/codeql-action/init@v3, github/codeql-action/analyze@v3) rather than pinned SHAs -- flagged by Semgrep (yaml.github-actions.security.github-actions-mutable-action-tag, 3 findings in .github/workflows/codeql.yml) as a supply-chain risk.","vulnerability_details":"No requirements.lock / poetry.lock exists for any Python component; all pins in FunctionAppV2's requirements.txt are >= floors, not ==; CI workflow uses mutable @v3/@v4 tags instead of pinned 40-character commit SHAs that execute on every push/PR/scheduled run to main.","fix_guidance":"Generate and commit a pip-compile/poetry lockfile pinning exact transitive versions; pin GitHub Actions to full commit SHAs per Semgrep's guidance; enable Dependabot cooldown.","why_this_matters":"Prevents typosquat and malicious update compromise.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0007 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals HIGH.","within_declared_contract":false,"transport_gated":false,"mitigation_present":false,"evidence":[{"path":".github/workflows/codeql.yml","start_line":54,"end_line":60,"snippet":"    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v4\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3"},{"path":".github/workflows/codeql.yml","start_line":16,"end_line":16,"snippet":"on:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n  schedule:\n    - cron: '38 6 * * 5'\n\njobs:\n  analyze:"},{"path":".github/dependabot.yml","start_line":5,"end_line":10,"snippet":"version: 2\nupdates:\n  - package-ecosystem: \"\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0008","rule_version":"1.2.0","rule_name":"Missing or Inadequate Input Validation","finding":"UNKNOWN","severity":"HIGH","realized_severity":null,"confidence":"low","rationale":"Archive review confirms that the extract_regex_functionapp endpoint (functions/regex_extractor/extractor.py) accepts a caller-supplied pattern and subject from the request JSON and calls Python's re.search(pattern, subject) with no length or complexity limit, a plausible ReDoS primitive given Python re's susceptibility to catastrophic backtracking. However, the only repository-visible invocation of this function, from the deployed Logic App, supplies a fixed regex pattern and a trigger-derived subject, and direct endpoint access requires a Function-level key; whether an external attacker can control the pattern or obtain a valid function key is not established anywhere in the repository. This unresolved trigger-capability gap, not any unreviewability of the ZIP contents, is why the verdict remains UNKNOWN.","vulnerability_details":null,"fix_guidance":"Validate and bound regex pattern complexity and length before calling re.search (or enforce a matching timeout), and determine whether the extractor endpoint can be reached by external callers without a valid function key or whether the Logic App only ever supplies fixed, non-attacker-controlled patterns.","why_this_matters":"Frontline control to prevent multiple classes of vulns.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":["extract_regex_functionapp"],"component_name":null},{"rule_id":"ATR-C0009","rule_version":"1.2.0","rule_name":"Insecure Deserialization","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"medium","rationale":"No pickle.loads, yaml.load() (unsafe), marshal.load, or other unsafe deserializer was found in any Python code across both Function App zip archives (grepped across all extracted .py files excluding vendored site-packages). All JSON handling uses the standard json.loads/json.dumps (safe), and YAML files in the repo (plugin manifests) are static configuration consumed by Security Copilot's own backend, not deserialized by application code in this repo.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Can lead to arbitrary code execution.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::functions/json_cleaner/cleaner.py","start_line":1,"end_line":5,"snippet":"import json\nimport logging\nimport re\nimport azure.functions as func"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0010","rule_version":"1.2.0","rule_name":"Lack of Output Encoding/Sanitization","finding":"VULNERABLE","severity":"MEDIUM","realized_severity":"MEDIUM","confidence":"medium","rationale":"The generate_html_report_functionapp endpoint builds its HTML report using a Jinja2 Template constructed from a raw triple-quoted string, so autoescape defaults to off, and the template interpolates values from the submitted analysis JSON via unescaped {{ value }} expressions. The companion Logic App's mailbox-triggered workflow invokes this function with parsed, attacker-influenced email-analysis content and forwards its rendered output as an outbound HTML report, so content embedded in a reported phishing email (e.g. '<script>' markup) can reach the unescaped template interpolation and be reflected as live markup in the generated report.","vulnerability_details":"req_body = req.get_json() is the full attacker-controlled POST body passed unmodified into create_html(req_body); Template() defaults to autoescape=False and the template's {{ value }} expressions do not apply |e, so any value containing e.g. '<script>' is reflected as live markup in the HTTP response body served with mimetype text/html.","fix_guidance":"Use jinja2.Environment(autoescape=True) or select_autoescape() instead of the bare Template() class, and apply the |e escape filter to every interpolated value sourced from the analysis JSON before rendering.","why_this_matters":"Prevents UI-level injection and operator compromise.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0010 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals MEDIUM.","within_declared_contract":false,"transport_gated":false,"mitigation_present":false,"evidence":[{"path":"Plugins/Published Plugins/Netskope-Copilot-Plugin/CoPilotOpenAPISpec.yaml","start_line":12260,"end_line":160,"snippet":"    Response:\n      type: object\n      properties:\n        status:\n          type: string\n          enum:\n            - success\n            - error\n        data:\n          oneOf:\n            - $ref: '#/components/schemas/Forensics'"},{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::functions/html_report/generator.py","start_line":1,"end_line":17,"snippet":"import logging\nfrom jinja2 import Template\nfrom urllib.parse import unquote\nimport azure.functions as func\n\nlogger = logging.getLogger(__name__)\n\nCATEGORY_STYLES = {\n    \"PHISHING\": \"background-color: #d9534f; ...\",\n    ...\n}\n\ndef create_html(json_data):\n    html_template = '''\n    <html>"},{"path":"Plugins/Published Plugins/Netskope-Copilot-Plugin/CoPilotOpenAPISpec.yaml","start_line":12260,"end_line":165,"snippet":"    Response:\n      type: object\n      properties:\n        status:\n            return func.HttpResponse(... status_code=400)\n          enum:\n            - success\n        return func.HttpResponse(html_report, status_code=200, mimetype=\"text/html\", ...)"}],"affected_tools":["generate_html_report_functionapp"],"component_name":null},{"rule_id":"ATR-C0011","rule_version":"1.4.0","rule_name":"Path Traversal & Symlink Bypass (Filesystem Tools)","finding":"VULNERABLE","severity":"HIGH","realized_severity":"HIGH","confidence":"medium","rationale":"The downloaded promptbook's 'name' field originates from the Security Copilot API response and is passed through a chain of string replacements that strip quote, parenthesis, and bracket characters but leave '..' sequences and path separators intact. The sanitized name is concatenated onto the fixed './Downloads/' prefix and written via Out-File, which resolves '../' segments in the resulting path, so a crafted promptbook name containing traversal sequences can cause the script to write a file outside the intended Downloads directory.","vulnerability_details":null,"fix_guidance":"Strip or reject '..' sequences and path separators from the promptbook name (or resolve the final output path and verify it remains within the Downloads directory) before passing it to Out-File.","why_this_matters":"Traversal exposes arbitrary host files; can lead to code execution.","context_note":"[none|relief:none] No context relief applies; realized severity equals HIGH.","within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":30,"end_line":38,"snippet":"$response = Invoke-WebRequest -Uri $url -Method GET -Headers $headers\n$jsonContent = $response.content\n$fromJson = $jsonContent | ConvertFrom-Json \n\nWrite-Host \"Number of promptbooks Downloaded: $($fromJson.value.Count)\" #$jsonContent\n\n# Iterate for each promptbook in JSON\n$folder = './Downloads/'\nforeach ($pb in $fromJson.value) {"},{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":41,"end_line":49,"snippet":"        $fileName = $pb.name + \".json\"\n        # Remove all special chars from filename\n        $fileName= $fileName.replace(\"'\",\"\")\n        $fileName= $fileName.replace(\"(\",\"\")\n        $fileName= $fileName.replace(\")\",\"\")\n        $fileName= $fileName.replace(\"[\",\"-\")\n        $fileName= $fileName.replace(\"]\",\"-\")\n        $fileName= $fileName.replace(' ','_') \n        $fileName = $folder + $fileName "},{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":65,"end_line":70,"snippet":"\n        $json = $pb | ConvertTo-Json\n        #Write-Host $json\n        \"$json\" | out-file -filepath $fileName #-encoding utf8NoBOM\n\n        Write-Host \"Written file $($fileName)\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0012","rule_version":"1.2.0","rule_name":"Denial of Wallet / Cost Controls","finding":"VULNERABLE","severity":"MEDIUM","realized_severity":"MEDIUM","confidence":"low","rationale":"The FunctionAppV2 ARM template explicitly provisions the Y1/Dynamic consumption hosting plan, and the companion Logic App polls a shared mailbox, triggering a metered run -- including attachment parsing and Function invocations -- for each arriving email. No repository-defined per-sender quota, rate limit, or budget gate exists on this mailbox-triggered path, so an attacker able to send email to the monitored mailbox can drive consumption-based billing at volume.","vulnerability_details":null,"fix_guidance":"Add a per-sender or per-time-window rate limit and a budget alert in front of the mailbox-triggered workflow, and consider a hosting plan with a fixed cost ceiling to bound consumption-driven billing exposure.","why_this_matters":"Prevents cost-based disruption.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0012 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals MEDIUM.","within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/logicapp_azuredeploy.json","start_line":180,"end_line":203,"snippet":"                    \"triggers\": {\n                        \"When_a_new_email_arrives_in_a_shared_mailbox_(V2)\": {\n                            \"recurrence\": {\n                                \"interval\": 3,\n                                \"frequency\": \"Minute\"\n                            },\n                            \"evaluatedRecurrence\": {\n                                \"interval\": 3,\n                                \"frequency\": \"Minute\"\n                            },\n                            \"splitOn\": \"@triggerBody()?['value']\",\n                            \"type\": \"ApiConnection\",\n                            \"inputs\": {\n                                \"host\": {\n                                    \"connection\": {\n                                        \"name\": \"@parameters('$connections')['office365-1']['connectionId']\"\n                                    }\n                                },\n                                \"method\": \"get\",\n                                \"path\": \"/v2/SharedMailbox/Mail/OnNewEmail\",\n                                \"queries\": {\n                                    \"mailboxAddress\": \"[parameters('SharedMailboxAddress')]\",\n                                    \"importance\": \"Any\",\n                                    \"hasAttachments\": false,"},{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/functionapp_azuredeploy.json","start_line":33,"end_line":48,"snippet":"            \"type\": \"Microsoft.Web/serverfarms\",\n            \"apiVersion\": \"2018-02-01\",\n            \"name\": \"[variables('FunctionAppName')]\",\n            \"location\": \"[resourceGroup().location]\",\n            \"sku\": {\n                \"name\": \"Y1\",\n                \"tier\": \"Dynamic\"\n            },\n            \"kind\": \"functionapp,linux\",\n            \"properties\": {\n                \"name\": \"[variables('FunctionAppName')]\",\n                \"workerSize\": \"0\",\n                \"workerSizeId\": \"0\",\n                \"numberOfWorkers\": \"1\",\n                \"reserved\": true\n            }"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0013","rule_version":"1.1.0","rule_name":"Tool Output Sanitization & Injection Containment","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"This rule targets MCP tool-output handling that gets concatenated into an LLM's context window (envelope/untrustedReturn annotation, control-character stripping before injection into a model prompt). No MCP server or LLM-tool-calling host exists in this repository; the Function Apps here return data to a Logic App orchestration / Azure consumer, not into an LLM context window managed by this codebase. The HTML-report-generation XSS issue (ATR-C0010) is a related but distinct rendering-sanitization concern already captured under its own rule.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Tool outputs are a primary prompt-injection vector. Third-party content (web pages, files, API responses) may contain text crafted to override instructions or impersonate system/tool messages. Without a host-enforced envelope, sanitization, and an explicit untrusted-return signal, the model can be coerced into executing attacker-controlled directives, leaking secrets, or chaining further tool calls on behalf of the adversary.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0014","rule_version":"1.2.0","rule_name":"CI/CD Workflow Script Injection","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"The only workflow in this repo, .github/workflows/codeql.yml, has a single 'run:' block (lines 78-83) that is a static, hardcoded multi-line echo/message with NO interpolation of any github.event.*, github.head_ref, inputs.*, or needs.* expression -- it only prints fixed instructional text about manual build steps. Triggers are push/pull_request (both scoped to the 'main' branch) and a weekly schedule; none of pull_request_target, issue_comment, workflow_run, or repository_dispatch are used. The only '${{ }}' expressions in the file (matrix.language, matrix.build-mode) are workflow-internal matrix values defined in the same file, not attacker-controlled external input, and none of them reach a shell run block -- they are consumed only as 'with:' action inputs (languages:, build-mode:, category:) to the github/codeql-action, not re-parsed by a shell.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"CI/CD script injection can execute attacker-controlled commands with workflow tokens, repository secrets, trusted-runner access, artifact or cache authority, and release or deployment privileges.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":".github/workflows/codeql.yml","start_line":74,"end_line":83,"snippet":"    - if: matrix.build-mode == 'manual'\n      run: |\n        echo 'If you are using a \"manual\" build mode for one or more of the' \\\n          'languages you are analyzing, replace this with the commands to build' \\\n          'your code, for example:'\n        echo '  make bootstrap'\n        echo '  make release'\n        exit 1"},{"path":".github/workflows/codeql.yml","start_line":16,"end_line":16,"snippet":"on:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n  schedule:\n    - cron: '38 6 * * 5'"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-R0001","rule_version":"1.3.0","rule_name":"Weaponization: Malicious-Purpose Artifact (Offensive Capability by Design)","finding":"SECURE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"This repository is entirely composed of defensive/detective security-operations content: Microsoft Security Copilot plugin manifests for threat intelligence lookups (CrowdSec, GreyNoise, HaveIBeenPwned), KQL hunting-query plugins for detecting ransomware activity signs, phishing/AiTM detection, anomaly detection, and incident investigation; Logic App automation for triage/reporting; and promptbook samples for SOC analyst workflows. Manual review of the 'Ransomware Signs' plugin (hunts for taskkill.exe/cipher.exe/wevtutil indicators to DETECT ransomware activity, not perform it), the QR-code AiTM phishing DETECTION plugin, and the GEO-IP workshop's 'script_decode.txt' (a benign training exercise asking students to decode and analyze a hex-encoded PowerShell snippet as a SOC exercise, explicitly framed as 'suspicious script analysis' for a defender audience, not an operational payload) found no artifact whose declared purpose is to generate or perform offensive capability. No ransomware-builder, credential-harvester, C2/loader, or mass-abuse tooling exists; all offensive-adjacent content is framed and used for detection/defense/training.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"An artifact whose purpose is to weaponize the agent -- to produce malware, steal credentials, evade defenses, or run attacks at scale -- is dangerous regardless of how securely it is built; posture controls (auth, input validation, least privilege) cannot make a weapon safe, which is why a confirmed weaponization finding caps the trust verdict to `blocked` rather than being averaged against a good posture score. Catching malicious PURPOSE is a distinct safety control, and it must be conservative because offensive capability is dual-use: legitimate pentest, CTF, defensive, and research work must abstain (UNKNOWN), never block -- unless the artifact itself hides from the people who install, run or audit it.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Plugins/Community Based Plugins/Microsoft Defender XDR Custom Plugin Scenarios/Ransomware Signs/Readme.md","start_line":1,"end_line":11,"snippet":"### Signs of ransomware activity Custom Plugin\n\nWelcome to the Signs of ransomware activity custom plugin! Here, you'll discover a Skills that looking up signs of ransomware activity in Defender Advanced Hunting that create queries that locate individual artifacts associated with ransomware activity..."},{"path":"Technical Workshops/Custom Plugin Workshop/Task04_GEO_IP_script/readme.md","start_line":48,"end_line":61,"snippet":"####  Use case\nYou are Soc Analyst in woodgrove Domain, During an endpoint Incident investigation, you found suspicious script that run on your DMZ server, your job is to analyze this script, and share your final to your team member.\nYour task is:\n1. Input this information about the script from the script_decode.txt and ask Copilot to decode it\n2. Extract only the IPs from this script.\n3. Employ the MDTI reputation score to assess these Ip."}],"affected_tools":null,"component_name":null}],"component_tools":[{"tool_name":"parse_email (FunctionApp v1)","tool_description":"HTTP endpoint (parse_email/__init__.py) that parses a raw email, extracts URLs/IPs/domains, decodes SafeLinks/Proofpoint URLs, and expands shortened URLs via outbound HTTP HEAD requests.","types":["read-only","network-broad","untrusted-output"],"status":"IMPLEMENTED","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"tool_name":"parse_pdf","tool_description":"HTTP endpoint that decodes a base64-encoded PDF and extracts/cleans its text via pdfminer.","types":["read-only","untrusted-output"],"status":"IMPLEMENTED","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"},{"tool_name":"parse_virustotal_json","tool_description":"HTTP endpoint that parses a VirusTotal API JSON response and extracts malicious/suspicious engine results.","types":["read-only","untrusted-output"],"status":"IMPLEMENTED","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing"}],"summary":{"high_level_risks":["This repo is NOT an MCP server / agentic-AI codebase: it is Microsoft's public Security Copilot community content repository (plugin manifests, Logic App ARM templates, Azure Function Apps, promptbook samples, workshop material). All ATR-M (mcp-server) rules are NOT_APPLICABLE -- no MCP server, stdio/SSE/streamable-HTTP transport, or tool registry exists anywhere in the codebase.","Two Azure Function Apps (bundled as binary zip deployment artifacts under 'Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing(V2)') parse untrusted, attacker-influenced phishing-report email content and contain a plausible SSRF primitive: expand_url()/UrlProcessor.expand_url() follows HTTP redirects on URLs extracted from email bodies, gated only by a non-authoritative domain-substring match against known URL-shortener providers (no RFC1918/loopback/metadata-IP denylist). Because this source exists only inside committed binary .zip artifacts rather than plain-text repo files, several related findings (SSRF, DoS via unbounded max_depth, logging hygiene, denial-of-wallet) were adjudicated as UNKNOWN rather than VULNERABLE per the evidence-citation contract, but the underlying code pattern is worth a human follow-up review.","generate_html_report_functionapp (FunctionAppV2) renders attacker-controlled JSON directly into an HTML report using a bare Jinja2 Template() with autoescape OFF and no per-value escaping -- a stored/reflected XSS vector for anyone viewing the generated phishing-analysis report.","Supply-chain hygiene gaps: FunctionAppV2's requirements.txt uses open-ended '>=' version floors with no lockfile; GitHub Actions workflow (.github/workflows/codeql.yml) pins third-party actions to mutable tags (@v3/@v4) instead of commit SHAs (flagged by Semgrep); Dependabot config has no cooldown period and an empty package-ecosystem value.","No MCP server, agent framework, or LLM tool-use component of any kind was found in this repository -- it is a plugin/documentation/IaC repo for Microsoft's first-party Security Copilot product, not an agentic AI system under the MCP threat model this ruleset primarily targets.","No evidence of weaponized/offensive-purpose content: all security-adjacent plugins (ransomware-signs detection, AiTM phishing detection, threat-intel lookups) are defensive/detective in framing and function; no malware-builder, credential-harvester, or C2 tooling exists."],"top_remediations":["Extract and commit the Azure Function App source code as plain text (not only inside binary .zip blobs) so it can be properly code-reviewed and so future SAST/security scans can analyze it directly.","Add IP-class validation (reject RFC1918/loopback/link-local/169.254.169.254) before following any URL extracted from untrusted email content in expand_url()/UrlProcessor.expand_url(), and re-validate on every redirect hop.","Switch generate_html_report_functionapp's Jinja2 Template() to an Environment with autoescape=True (or select_autoescape()) to prevent HTML/script injection into generated phishing-analysis reports.","Pin GitHub Actions to full commit SHAs instead of mutable version tags; add a Dependabot cooldown period; generate and commit a Python lockfile for the Function App's dependencies.","Clamp the caller-controllable 'max_depth' parameter in parse_email_functionapp to a fixed, small ceiling to prevent unbounded-recursion resource exhaustion."]},"rollup":{"component_findings_count":{"vulnerable":0,"secure":0,"not_applicable":11},"repo_findings_inherited_count":{"vulnerable":4,"secure":4,"not_applicable":2},"component_tools_count":{"read_only":3,"network_broad":1,"untrusted_output":3},"worst_case_severity":"HIGH"},"trust_scores":{"repo_level":{"score":60,"tier":"low","capability_band":"high","score_confidence":"low","score_interval":{"low":36,"high":84},"factors":["ATR-C0007 HIGH","ATR-C0010 MEDIUM","ATR-C0011 HIGH","ATR-C0012 MEDIUM"]},"component_level":{"score":100,"tier":"high","capability_band":"moderate","score_confidence":"high","score_interval":{"low":96,"high":100},"factors":[]}}},{"artifact_version":"2.0","component":{"component_type":"api-server","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2","component_path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2","metadata":{"transports":["http"]}},"scan_provenance":{"scanned_at":"2026-10-14T23:52:14.666Z","resolved_ref":"79ee8ea8a3ce7f7ebd906fe61d7be03af668614a","resolved_ver":null},"repo_context":{"repo_url":"https://github.com/Azure/Security-Copilot","languages":["YAML","JSON","PowerShell","Python","Markdown"],"transports_detected":[],"deployment_artifacts":["Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing/functionapp_azuredeploy.json","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/functionapp_azuredeploy.json","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing/FunctionApp.zip","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionApp.zip","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip",".github/workflows/codeql.yml",".github/dependabot.yml"],"provenance":{"publisher":"Azure","publisher_verified":true,"signed_build":false,"dependency_cve_count":23,"maintenance_active":false,"declared_policy":false}},"component_findings":[{"rule_id":"ATR-M0001","rule_version":"1.2.0","rule_name":"Tool Definition Integrity & Versioning (ETDI-style)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"Repo-wide search (grep for FastMCP, server.tool, @mcp.tool, registerTool, add_tool, McpServer, stdio/SSE/streamable-HTTP transport patterns) found zero MCP server implementations anywhere in the repository. This repo is a collection of Microsoft Security Copilot plugin manifests (OpenAPI/YAML), Logic App ARM templates, Azure Function Apps, and documentation/workshop material -- not an MCP server codebase. No mcp-server component exists to evaluate this rule against; attached here only to satisfy the reporting schema's component-scoping requirement.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents rug-pull tool poisoning.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0002","rule_version":"1.1.0","rule_name":"Unrestricted Tool Permissions (Overprivileged Tools)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository (verified via repo-wide grep for MCP registration patterns); this rule's mcp-server applicability has no target.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Limits blast radius and privilege escalation.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0003","rule_version":"1.3.1","rule_name":"CORS / Origin / Host Validation (DNS Rebinding Defense)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server (stdio/SSE/streamable-HTTP) component exists in this repository. The repo contains Security Copilot plugin manifests and Logic App/Function App deployment templates, none of which are an MCP server listener.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents DNS rebinding/browser hijack of local or remote MCP.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0004","rule_version":"1.2.0","rule_name":"Binding to 0.0.0.0 Without Auth/TLS","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository; there is no server bind/listen code to evaluate (Azure Function Apps use the managed Azure Functions host, not a self-managed listener).","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"LAN/Internet exposure enables remote exploitation.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0005","rule_version":"1.4.0","rule_name":"OAuth 2.1 + PKCE Correctness (MCP Authorization)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository to evaluate MCP-specific OAuth 2.1/PKCE requirements against.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Misconfig enables token theft and confused-deputy attacks.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0006","rule_version":"1.2.0","rule_name":"Tool Name Collision / Spoofing","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No MCP server/tool registry exists in this repository; the 'tools' present (Security Copilot plugins) are OpenAPI-based skills consumed by a closed first-party orchestrator, not MCP tools subject to cross-server name collision.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents malicious tool shadowing.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0007","rule_version":"1.2.0","rule_name":"Prompt/Metadata Injection in Tool Descriptions","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No MCP server/tool-definition registry exists in this repository. Plugin YAML descriptions were spot-checked for hidden directives/control characters/RLO-LRO and none were found; this is a distinct surface from MCP tool manifests and the rule's MCP-tool-definition threat model does not map onto Security Copilot plugin manifests.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents covert model manipulation.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0008","rule_version":"1.2.0","rule_name":"CORS Misuse: Wildcard with Credentials","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository; no CORS configuration code exists to evaluate under the MCP remote-transport threat model.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents credentialed cross-origin abuse.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0009","rule_version":"1.3.0","rule_name":"Transport Security: TLS Everywhere (Remote)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"This component is an Azure Function App enforcing HTTPS-only access and TLS 1.2, but it is not an MCP server and exposes no remote MCP transport for ATR-M0009's TLS-everywhere requirement to apply to. The rule's applicability precondition -- a remote MCP transport -- is absent, so NOT_APPLICABLE reflects scope rather than an assessment of the Function App's TLS configuration.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"MitM can steal tokens and tamper responses.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0010","rule_version":"1.4.0","rule_name":"No Authentication or Authorization Checks (General)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"No MCP server component exists in this repository to evaluate MCP tool/resource authn/authz gating against.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents unauthorized tool use and data access.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"rule_id":"ATR-M0011","rule_version":"1.2.0","rule_name":"OAuth Proxy Per-Client Consent (Confused Deputy Defense)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"No MCP server / OAuth proxy component exists in this repository; the rule's applicability precondition (an OAuth proxy forwarding to a distinct upstream IdP on behalf of dynamically-registered MCP clients) is not met.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Shared upstream client + dynamic MCP-client registration + no per-client consent enables attacker-registered MCP clients to receive bridge codes carrying victim upstream tokens — the documented MCP Confused Deputy attack.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"}],"repo_findings_inherited":[{"rule_id":"ATR-C0001","rule_version":"1.2.0","rule_name":"Unrestricted Network Fetch / SSRF","finding":"UNKNOWN","severity":"HIGH","realized_severity":null,"confidence":"low","rationale":"Manual review (via python zipfile extraction, not committed as extracted source) of FunctionApp.zip's parse_email/__init__.py shows an expand_url() helper that calls requests.Session().head(url, allow_redirects=True) on email-derived URLs gated only by a hardcoded shortener-domain allowlist (no private-IP/loopback/metadata denylist), which looks like a plausible SSRF primitive. However, this code exists ONLY inside a committed binary zip deployment artifact (FunctionApp.zip) and is not present as an extracted/plain-text file anywhere in the repository tree, so it cannot be cited with a repo-relative path + line-number snippet that is independently verifiable by opening that path in the repo (the actual repo file at that path is binary zip bytes, not the Python source). Per the evidence contract, required_evidence classes could not be established against a verifiable repo-relative source file. Abstaining rather than asserting VULNERABLE against unverifiable evidence.","vulnerability_details":null,"fix_guidance":"Extract and commit function source as plain text (not only as a zip blob) for reviewability; add IP-class validation (resolve host, reject RFC1918/loopback/link-local/169.254.169.254) before any outbound HEAD/GET request derived from email content.","why_this_matters":"Enables internal pivoting and data exfiltration.","context_note":null,"within_declared_contract":true,"transport_gated":null,"mitigation_present":true,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0002","rule_version":"1.3.2","rule_name":"Static Secrets","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"medium","rationale":"Gitleaks scan (0 findings) plus manual grep for API_KEY/SECRET/TOKEN/PASSWORD literal assignments across YAML/JSON/PS1/Python files found no committed secret VALUES -- only schema/property names (e.g. 'apiAccessToken', 'token:' as an OpenAPI schema field name in Netskope/CrowdSec plugin specs) and placeholder example URLs (https://example.com). The PromptBooks PowerShell scripts require the operator to pass a bearer token as a command-line parameter (-token) copied manually from browser devtools each run; no token is hardcoded or persisted in the repo. No .env files with real values, no AKIA/ghp_/sk- patterns found.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Plaintext secrets are easily exfiltrated.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Plugins/Published Plugins/CrowdSecTI/crowdsecTI_smoke.yaml","start_line":62,"end_line":68,"snippet":"      security:\n        - api_key: []\n  \ncomponents:\n  securitySchemes:\n    api_key:\n      type: \"apiKey\"\n      name: \"x-api-key\"\n      in: \"header\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0003","rule_version":"1.3.0","rule_name":"Runtime Command Injection via Process Execution","finding":"UNKNOWN","severity":"CRITICAL","realized_severity":null,"confidence":"medium","rationale":"Manual archive extraction found only a single subprocess call in application code: a fixed-argv invocation of 'antiword' with a locally generated temp-file path as its only argument, with no shell=True and no attacker-controlled command text reaching the sink; no eval()/Function()/dynamic-code-execution pattern was found elsewhere. However, this code exists only inside a committed binary ZIP deployment artifact and is not present as an extracted, plain-text file at a stable repository path, so the required source citation cannot be independently re-opened and re-verified at that path. Given this unresolved source-attestation gap, the verdict is UNKNOWN rather than SECURE.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Unsanitized command construction in shipped runtime code can give a remote attacker arbitrary code execution with the application's privileges.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::extractors/word_extractor.py","start_line":100,"end_line":110,"snippet":"with tempfile.NamedTemporaryFile(delete=False) as temp_file:\n    temp_file.write(word_data)\n    temp_file_path = temp_file.name\ntry:\n    result = subprocess.run(\n        [\"antiword\", temp_file_path],\n        capture_output=True,\n        text=True,\n        check=True\n    )"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0004","rule_version":"1.2.0","rule_name":"DoS Protections: Timeouts, Concurrency, Streaming Limits","finding":"UNKNOWN","severity":"MEDIUM","realized_severity":null,"confidence":"low","rationale":"Manual extraction of FunctionAppV2.zip shows function_app.py accepting a caller-supplied 'max_depth' query parameter with no upper-bound clamp, passed into parsers/email_parser.py's recursive parse_email(), and no visible request-body-size limit in host.json. This looks like a plausible unbounded-recursion/resource-exhaustion vector, but the code exists only inside a committed binary zip deployment artifact, not as an extracted plain-text file at a reviewable repo path -- so a reviewer opening the cited path sees zip bytes, not the Python source quoted in evidence. Abstaining to UNKNOWN rather than asserting VULNERABLE against unverifiable evidence.","vulnerability_details":null,"fix_guidance":"Commit function source as extracted plain text for reviewability; clamp max_depth to a fixed ceiling; add a request body size limit and a processing time budget around attachment parsing.","why_this_matters":"Resource exhaustion can crash or stall MCP.","context_note":null,"within_declared_contract":true,"transport_gated":false,"mitigation_present":false,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0005","rule_version":"1.2.0","rule_name":"Logging Hygiene (No Secrets/PII/Tokens) & Audit Trail","finding":"UNKNOWN","severity":"MEDIUM","realized_severity":null,"confidence":"low","rationale":"The Function App code (committed only as binary FunctionApp.zip / FunctionAppV2.zip, not extracted plain text) uses Python logging extensively with DEBUG-level statements that could log request bodies/content in some paths (e.g. parse_email/__init__.py logs 'Raw request body (as bytes)' truncated to 100 chars, and various functions log full decoded content at DEBUG level). host.json sets default logLevel to 'Debug' for both Function Apps, which in production would surface verbose content (including potentially PII from parsed phishing emails) into Application Insights logs. However, because this code exists only inside committed zip binaries and not as reviewable plain-text repo files, a definitive source-to-sink citation at a stable repo path/line cannot be established per the evidence contract. The PowerShell Promptbook scripts avoid logging the bearer token itself (Write-Host calls never echo $token or $headers). Abstaining on the Function App logging question specifically due to the binary-artifact citation issue; the PowerShell scripts alone would be SECURE but are evaluated together with the Function Apps for this repo-level rule.","vulnerability_details":null,"fix_guidance":"Extract and commit function source as plain text; set host.json default logLevel to Information/Warning for production; ensure DEBUG-level logs that include email body/attachment content are gated off outside of explicit troubleshooting.","why_this_matters":"Prevents sensitive data leakage; enables forensics.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":["parse_email_functionapp","parse_email (FunctionApp v1)"],"component_name":null},{"rule_id":"ATR-C0006","rule_version":"1.2.0","rule_name":"Container/Runtime Hardening","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No Dockerfile, docker-compose, Helm chart, or Kubernetes manifest exists anywhere in this repository (confirmed via repo-wide find for Dockerfile*/docker-compose*/*.tf and directory listing). Deployment artifacts present are Azure ARM/Logic App JSON templates and Azure Function App zip packages, which run on Azure's managed PaaS compute (Functions/Logic Apps/App Service) rather than a repo-controlled container image, so there is no container hardening surface (USER, capabilities, seccomp, hostNetwork) for this rule to evaluate.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Reduces blast radius of exploits.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0007","rule_version":"1.2.0","rule_name":"Dependency Risk & Supply Chain","finding":"VULNERABLE","severity":"HIGH","realized_severity":"HIGH","confidence":"medium","rationale":"The FunctionAppV2 requirements.txt uses open-ended version ranges ('azure-functions' with no version at all; 'tnefparse>=1.4.0', 'extract-msg>=0.30.0', etc.) with no lockfile pinning exact resolved versions, and GitHub Actions workflow dependencies float on mutable tags (actions/checkout@v4, github/codeql-action/init@v3, github/codeql-action/analyze@v3) rather than pinned SHAs -- flagged by Semgrep (yaml.github-actions.security.github-actions-mutable-action-tag, 3 findings in .github/workflows/codeql.yml) as a supply-chain risk.","vulnerability_details":"No requirements.lock / poetry.lock exists for any Python component; all pins in FunctionAppV2's requirements.txt are >= floors, not ==; CI workflow uses mutable @v3/@v4 tags instead of pinned 40-character commit SHAs that execute on every push/PR/scheduled run to main.","fix_guidance":"Generate and commit a pip-compile/poetry lockfile pinning exact transitive versions; pin GitHub Actions to full commit SHAs per Semgrep's guidance; enable Dependabot cooldown.","why_this_matters":"Prevents typosquat and malicious update compromise.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0007 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals HIGH.","within_declared_contract":false,"transport_gated":false,"mitigation_present":false,"evidence":[{"path":".github/workflows/codeql.yml","start_line":54,"end_line":60,"snippet":"    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v4\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3"},{"path":".github/workflows/codeql.yml","start_line":16,"end_line":16,"snippet":"on:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n  schedule:\n    - cron: '38 6 * * 5'\n\njobs:\n  analyze:"},{"path":".github/dependabot.yml","start_line":5,"end_line":10,"snippet":"version: 2\nupdates:\n  - package-ecosystem: \"\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0008","rule_version":"1.2.0","rule_name":"Missing or Inadequate Input Validation","finding":"UNKNOWN","severity":"HIGH","realized_severity":null,"confidence":"low","rationale":"Archive review confirms that the extract_regex_functionapp endpoint (functions/regex_extractor/extractor.py) accepts a caller-supplied pattern and subject from the request JSON and calls Python's re.search(pattern, subject) with no length or complexity limit, a plausible ReDoS primitive given Python re's susceptibility to catastrophic backtracking. However, the only repository-visible invocation of this function, from the deployed Logic App, supplies a fixed regex pattern and a trigger-derived subject, and direct endpoint access requires a Function-level key; whether an external attacker can control the pattern or obtain a valid function key is not established anywhere in the repository. This unresolved trigger-capability gap, not any unreviewability of the ZIP contents, is why the verdict remains UNKNOWN.","vulnerability_details":null,"fix_guidance":"Validate and bound regex pattern complexity and length before calling re.search (or enforce a matching timeout), and determine whether the extractor endpoint can be reached by external callers without a valid function key or whether the Logic App only ever supplies fixed, non-attacker-controlled patterns.","why_this_matters":"Frontline control to prevent multiple classes of vulns.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":["extract_regex_functionapp"],"component_name":null},{"rule_id":"ATR-C0009","rule_version":"1.2.0","rule_name":"Insecure Deserialization","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"medium","rationale":"No pickle.loads, yaml.load() (unsafe), marshal.load, or other unsafe deserializer was found in any Python code across both Function App zip archives (grepped across all extracted .py files excluding vendored site-packages). All JSON handling uses the standard json.loads/json.dumps (safe), and YAML files in the repo (plugin manifests) are static configuration consumed by Security Copilot's own backend, not deserialized by application code in this repo.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Can lead to arbitrary code execution.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::functions/json_cleaner/cleaner.py","start_line":1,"end_line":5,"snippet":"import json\nimport logging\nimport re\nimport azure.functions as func"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0010","rule_version":"1.2.0","rule_name":"Lack of Output Encoding/Sanitization","finding":"VULNERABLE","severity":"MEDIUM","realized_severity":"MEDIUM","confidence":"medium","rationale":"The generate_html_report_functionapp endpoint builds its HTML report using a Jinja2 Template constructed from a raw triple-quoted string, so autoescape defaults to off, and the template interpolates values from the submitted analysis JSON via unescaped {{ value }} expressions. The companion Logic App's mailbox-triggered workflow invokes this function with parsed, attacker-influenced email-analysis content and forwards its rendered output as an outbound HTML report, so content embedded in a reported phishing email (e.g. '<script>' markup) can reach the unescaped template interpolation and be reflected as live markup in the generated report.","vulnerability_details":"req_body = req.get_json() is the full attacker-controlled POST body passed unmodified into create_html(req_body); Template() defaults to autoescape=False and the template's {{ value }} expressions do not apply |e, so any value containing e.g. '<script>' is reflected as live markup in the HTTP response body served with mimetype text/html.","fix_guidance":"Use jinja2.Environment(autoescape=True) or select_autoescape() instead of the bare Template() class, and apply the |e escape filter to every interpolated value sourced from the analysis JSON before rendering.","why_this_matters":"Prevents UI-level injection and operator compromise.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0010 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals MEDIUM.","within_declared_contract":false,"transport_gated":false,"mitigation_present":false,"evidence":[{"path":"Plugins/Published Plugins/Netskope-Copilot-Plugin/CoPilotOpenAPISpec.yaml","start_line":12260,"end_line":160,"snippet":"    Response:\n      type: object\n      properties:\n        status:\n          type: string\n          enum:\n            - success\n            - error\n        data:\n          oneOf:\n            - $ref: '#/components/schemas/Forensics'"},{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::functions/html_report/generator.py","start_line":1,"end_line":17,"snippet":"import logging\nfrom jinja2 import Template\nfrom urllib.parse import unquote\nimport azure.functions as func\n\nlogger = logging.getLogger(__name__)\n\nCATEGORY_STYLES = {\n    \"PHISHING\": \"background-color: #d9534f; ...\",\n    ...\n}\n\ndef create_html(json_data):\n    html_template = '''\n    <html>"},{"path":"Plugins/Published Plugins/Netskope-Copilot-Plugin/CoPilotOpenAPISpec.yaml","start_line":12260,"end_line":165,"snippet":"    Response:\n      type: object\n      properties:\n        status:\n            return func.HttpResponse(... status_code=400)\n          enum:\n            - success\n        return func.HttpResponse(html_report, status_code=200, mimetype=\"text/html\", ...)"}],"affected_tools":["generate_html_report_functionapp"],"component_name":null},{"rule_id":"ATR-C0011","rule_version":"1.4.0","rule_name":"Path Traversal & Symlink Bypass (Filesystem Tools)","finding":"VULNERABLE","severity":"HIGH","realized_severity":"HIGH","confidence":"medium","rationale":"The downloaded promptbook's 'name' field originates from the Security Copilot API response and is passed through a chain of string replacements that strip quote, parenthesis, and bracket characters but leave '..' sequences and path separators intact. The sanitized name is concatenated onto the fixed './Downloads/' prefix and written via Out-File, which resolves '../' segments in the resulting path, so a crafted promptbook name containing traversal sequences can cause the script to write a file outside the intended Downloads directory.","vulnerability_details":null,"fix_guidance":"Strip or reject '..' sequences and path separators from the promptbook name (or resolve the final output path and verify it remains within the Downloads directory) before passing it to Out-File.","why_this_matters":"Traversal exposes arbitrary host files; can lead to code execution.","context_note":"[none|relief:none] No context relief applies; realized severity equals HIGH.","within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":30,"end_line":38,"snippet":"$response = Invoke-WebRequest -Uri $url -Method GET -Headers $headers\n$jsonContent = $response.content\n$fromJson = $jsonContent | ConvertFrom-Json \n\nWrite-Host \"Number of promptbooks Downloaded: $($fromJson.value.Count)\" #$jsonContent\n\n# Iterate for each promptbook in JSON\n$folder = './Downloads/'\nforeach ($pb in $fromJson.value) {"},{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":41,"end_line":49,"snippet":"        $fileName = $pb.name + \".json\"\n        # Remove all special chars from filename\n        $fileName= $fileName.replace(\"'\",\"\")\n        $fileName= $fileName.replace(\"(\",\"\")\n        $fileName= $fileName.replace(\")\",\"\")\n        $fileName= $fileName.replace(\"[\",\"-\")\n        $fileName= $fileName.replace(\"]\",\"-\")\n        $fileName= $fileName.replace(' ','_') \n        $fileName = $folder + $fileName "},{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":65,"end_line":70,"snippet":"\n        $json = $pb | ConvertTo-Json\n        #Write-Host $json\n        \"$json\" | out-file -filepath $fileName #-encoding utf8NoBOM\n\n        Write-Host \"Written file $($fileName)\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0012","rule_version":"1.2.0","rule_name":"Denial of Wallet / Cost Controls","finding":"VULNERABLE","severity":"MEDIUM","realized_severity":"MEDIUM","confidence":"low","rationale":"The FunctionAppV2 ARM template explicitly provisions the Y1/Dynamic consumption hosting plan, and the companion Logic App polls a shared mailbox, triggering a metered run -- including attachment parsing and Function invocations -- for each arriving email. No repository-defined per-sender quota, rate limit, or budget gate exists on this mailbox-triggered path, so an attacker able to send email to the monitored mailbox can drive consumption-based billing at volume.","vulnerability_details":null,"fix_guidance":"Add a per-sender or per-time-window rate limit and a budget alert in front of the mailbox-triggered workflow, and consider a hosting plan with a fixed cost ceiling to bound consumption-driven billing exposure.","why_this_matters":"Prevents cost-based disruption.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0012 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals MEDIUM.","within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/logicapp_azuredeploy.json","start_line":180,"end_line":203,"snippet":"                    \"triggers\": {\n                        \"When_a_new_email_arrives_in_a_shared_mailbox_(V2)\": {\n                            \"recurrence\": {\n                                \"interval\": 3,\n                                \"frequency\": \"Minute\"\n                            },\n                            \"evaluatedRecurrence\": {\n                                \"interval\": 3,\n                                \"frequency\": \"Minute\"\n                            },\n                            \"splitOn\": \"@triggerBody()?['value']\",\n                            \"type\": \"ApiConnection\",\n                            \"inputs\": {\n                                \"host\": {\n                                    \"connection\": {\n                                        \"name\": \"@parameters('$connections')['office365-1']['connectionId']\"\n                                    }\n                                },\n                                \"method\": \"get\",\n                                \"path\": \"/v2/SharedMailbox/Mail/OnNewEmail\",\n                                \"queries\": {\n                                    \"mailboxAddress\": \"[parameters('SharedMailboxAddress')]\",\n                                    \"importance\": \"Any\",\n                                    \"hasAttachments\": false,"},{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/functionapp_azuredeploy.json","start_line":33,"end_line":48,"snippet":"            \"type\": \"Microsoft.Web/serverfarms\",\n            \"apiVersion\": \"2018-02-01\",\n            \"name\": \"[variables('FunctionAppName')]\",\n            \"location\": \"[resourceGroup().location]\",\n            \"sku\": {\n                \"name\": \"Y1\",\n                \"tier\": \"Dynamic\"\n            },\n            \"kind\": \"functionapp,linux\",\n            \"properties\": {\n                \"name\": \"[variables('FunctionAppName')]\",\n                \"workerSize\": \"0\",\n                \"workerSizeId\": \"0\",\n                \"numberOfWorkers\": \"1\",\n                \"reserved\": true\n            }"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0013","rule_version":"1.1.0","rule_name":"Tool Output Sanitization & Injection Containment","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"This rule targets MCP tool-output handling that gets concatenated into an LLM's context window (envelope/untrustedReturn annotation, control-character stripping before injection into a model prompt). No MCP server or LLM-tool-calling host exists in this repository; the Function Apps here return data to a Logic App orchestration / Azure consumer, not into an LLM context window managed by this codebase. The HTML-report-generation XSS issue (ATR-C0010) is a related but distinct rendering-sanitization concern already captured under its own rule.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Tool outputs are a primary prompt-injection vector. Third-party content (web pages, files, API responses) may contain text crafted to override instructions or impersonate system/tool messages. Without a host-enforced envelope, sanitization, and an explicit untrusted-return signal, the model can be coerced into executing attacker-controlled directives, leaking secrets, or chaining further tool calls on behalf of the adversary.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0014","rule_version":"1.2.0","rule_name":"CI/CD Workflow Script Injection","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"The only workflow in this repo, .github/workflows/codeql.yml, has a single 'run:' block (lines 78-83) that is a static, hardcoded multi-line echo/message with NO interpolation of any github.event.*, github.head_ref, inputs.*, or needs.* expression -- it only prints fixed instructional text about manual build steps. Triggers are push/pull_request (both scoped to the 'main' branch) and a weekly schedule; none of pull_request_target, issue_comment, workflow_run, or repository_dispatch are used. The only '${{ }}' expressions in the file (matrix.language, matrix.build-mode) are workflow-internal matrix values defined in the same file, not attacker-controlled external input, and none of them reach a shell run block -- they are consumed only as 'with:' action inputs (languages:, build-mode:, category:) to the github/codeql-action, not re-parsed by a shell.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"CI/CD script injection can execute attacker-controlled commands with workflow tokens, repository secrets, trusted-runner access, artifact or cache authority, and release or deployment privileges.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":".github/workflows/codeql.yml","start_line":74,"end_line":83,"snippet":"    - if: matrix.build-mode == 'manual'\n      run: |\n        echo 'If you are using a \"manual\" build mode for one or more of the' \\\n          'languages you are analyzing, replace this with the commands to build' \\\n          'your code, for example:'\n        echo '  make bootstrap'\n        echo '  make release'\n        exit 1"},{"path":".github/workflows/codeql.yml","start_line":16,"end_line":16,"snippet":"on:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n  schedule:\n    - cron: '38 6 * * 5'"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-R0001","rule_version":"1.3.0","rule_name":"Weaponization: Malicious-Purpose Artifact (Offensive Capability by Design)","finding":"SECURE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"This repository is entirely composed of defensive/detective security-operations content: Microsoft Security Copilot plugin manifests for threat intelligence lookups (CrowdSec, GreyNoise, HaveIBeenPwned), KQL hunting-query plugins for detecting ransomware activity signs, phishing/AiTM detection, anomaly detection, and incident investigation; Logic App automation for triage/reporting; and promptbook samples for SOC analyst workflows. Manual review of the 'Ransomware Signs' plugin (hunts for taskkill.exe/cipher.exe/wevtutil indicators to DETECT ransomware activity, not perform it), the QR-code AiTM phishing DETECTION plugin, and the GEO-IP workshop's 'script_decode.txt' (a benign training exercise asking students to decode and analyze a hex-encoded PowerShell snippet as a SOC exercise, explicitly framed as 'suspicious script analysis' for a defender audience, not an operational payload) found no artifact whose declared purpose is to generate or perform offensive capability. No ransomware-builder, credential-harvester, C2/loader, or mass-abuse tooling exists; all offensive-adjacent content is framed and used for detection/defense/training.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"An artifact whose purpose is to weaponize the agent -- to produce malware, steal credentials, evade defenses, or run attacks at scale -- is dangerous regardless of how securely it is built; posture controls (auth, input validation, least privilege) cannot make a weapon safe, which is why a confirmed weaponization finding caps the trust verdict to `blocked` rather than being averaged against a good posture score. Catching malicious PURPOSE is a distinct safety control, and it must be conservative because offensive capability is dual-use: legitimate pentest, CTF, defensive, and research work must abstain (UNKNOWN), never block -- unless the artifact itself hides from the people who install, run or audit it.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Plugins/Community Based Plugins/Microsoft Defender XDR Custom Plugin Scenarios/Ransomware Signs/Readme.md","start_line":1,"end_line":11,"snippet":"### Signs of ransomware activity Custom Plugin\n\nWelcome to the Signs of ransomware activity custom plugin! Here, you'll discover a Skills that looking up signs of ransomware activity in Defender Advanced Hunting that create queries that locate individual artifacts associated with ransomware activity..."},{"path":"Technical Workshops/Custom Plugin Workshop/Task04_GEO_IP_script/readme.md","start_line":48,"end_line":61,"snippet":"####  Use case\nYou are Soc Analyst in woodgrove Domain, During an endpoint Incident investigation, you found suspicious script that run on your DMZ server, your job is to analyze this script, and share your final to your team member.\nYour task is:\n1. Input this information about the script from the script_decode.txt and ask Copilot to decode it\n2. Extract only the IPs from this script.\n3. Employ the MDTI reputation score to assess these Ip."}],"affected_tools":null,"component_name":null}],"component_tools":[{"tool_name":"clean_json_functionapp","tool_description":"HTTP endpoint that cleans/normalizes LLM-produced JSON text (strips markdown fences, replaces null with 'None').","types":["read-only"],"status":"IMPLEMENTED","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"tool_name":"extract_regex_functionapp","tool_description":"HTTP endpoint that runs a caller-supplied regex pattern against a caller-supplied subject string and returns the match.","types":["read-only"],"status":"IMPLEMENTED","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"tool_name":"generate_html_report_functionapp","tool_description":"HTTP endpoint that renders a Jinja2 HTML report from a submitted JSON phishing-analysis object.","types":["read-only"],"status":"IMPLEMENTED","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"},{"tool_name":"parse_email_functionapp","tool_description":"HTTP endpoint that parses raw email content (or base64-encoded email) to extract headers, body, attachments, URLs, IPs, and domains; expands shortened URLs via outbound HTTP requests.","types":["read-only","network-broad","untrusted-output"],"status":"IMPLEMENTED","component_name":"api-server/Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2"}],"summary":{"high_level_risks":["This repo is NOT an MCP server / agentic-AI codebase: it is Microsoft's public Security Copilot community content repository (plugin manifests, Logic App ARM templates, Azure Function Apps, promptbook samples, workshop material). All ATR-M (mcp-server) rules are NOT_APPLICABLE -- no MCP server, stdio/SSE/streamable-HTTP transport, or tool registry exists anywhere in the codebase.","Two Azure Function Apps (bundled as binary zip deployment artifacts under 'Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing(V2)') parse untrusted, attacker-influenced phishing-report email content and contain a plausible SSRF primitive: expand_url()/UrlProcessor.expand_url() follows HTTP redirects on URLs extracted from email bodies, gated only by a non-authoritative domain-substring match against known URL-shortener providers (no RFC1918/loopback/metadata-IP denylist). Because this source exists only inside committed binary .zip artifacts rather than plain-text repo files, several related findings (SSRF, DoS via unbounded max_depth, logging hygiene, denial-of-wallet) were adjudicated as UNKNOWN rather than VULNERABLE per the evidence-citation contract, but the underlying code pattern is worth a human follow-up review.","generate_html_report_functionapp (FunctionAppV2) renders attacker-controlled JSON directly into an HTML report using a bare Jinja2 Template() with autoescape OFF and no per-value escaping -- a stored/reflected XSS vector for anyone viewing the generated phishing-analysis report.","Supply-chain hygiene gaps: FunctionAppV2's requirements.txt uses open-ended '>=' version floors with no lockfile; GitHub Actions workflow (.github/workflows/codeql.yml) pins third-party actions to mutable tags (@v3/@v4) instead of commit SHAs (flagged by Semgrep); Dependabot config has no cooldown period and an empty package-ecosystem value.","No MCP server, agent framework, or LLM tool-use component of any kind was found in this repository -- it is a plugin/documentation/IaC repo for Microsoft's first-party Security Copilot product, not an agentic AI system under the MCP threat model this ruleset primarily targets.","No evidence of weaponized/offensive-purpose content: all security-adjacent plugins (ransomware-signs detection, AiTM phishing detection, threat-intel lookups) are defensive/detective in framing and function; no malware-builder, credential-harvester, or C2 tooling exists."],"top_remediations":["Extract and commit the Azure Function App source code as plain text (not only inside binary .zip blobs) so it can be properly code-reviewed and so future SAST/security scans can analyze it directly.","Add IP-class validation (reject RFC1918/loopback/link-local/169.254.169.254) before following any URL extracted from untrusted email content in expand_url()/UrlProcessor.expand_url(), and re-validate on every redirect hop.","Switch generate_html_report_functionapp's Jinja2 Template() to an Environment with autoescape=True (or select_autoescape()) to prevent HTML/script injection into generated phishing-analysis reports.","Pin GitHub Actions to full commit SHAs instead of mutable version tags; add a Dependabot cooldown period; generate and commit a Python lockfile for the Function App's dependencies.","Clamp the caller-controllable 'max_depth' parameter in parse_email_functionapp to a fixed, small ceiling to prevent unbounded-recursion resource exhaustion."]},"rollup":{"component_findings_count":{"vulnerable":0,"secure":0,"not_applicable":11},"repo_findings_inherited_count":{"vulnerable":4,"secure":4,"not_applicable":2},"component_tools_count":{"read_only":4,"network_broad":1,"untrusted_output":1},"worst_case_severity":"HIGH"},"trust_scores":{"repo_level":{"score":60,"tier":"low","capability_band":"high","score_confidence":"low","score_interval":{"low":36,"high":84},"factors":["ATR-C0007 HIGH","ATR-C0010 MEDIUM","ATR-C0011 HIGH","ATR-C0012 MEDIUM"]},"component_level":{"score":89,"tier":"high","capability_band":"moderate","score_confidence":"low","score_interval":{"low":71,"high":100},"factors":[]}}},{"artifact_version":"2.0","component":{"component_type":"cli","component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks","component_path":"Promptbook samples/Powershell to Manage Promptbooks","metadata":{"transports":["n/a - local CLI script, operator-run"]}},"scan_provenance":{"scanned_at":"2026-10-14T23:52:14.666Z","resolved_ref":"79ee8ea8a3ce7f7ebd906fe61d7be03af668614a","resolved_ver":null},"repo_context":{"repo_url":"https://github.com/Azure/Security-Copilot","languages":["YAML","JSON","PowerShell","Python","Markdown"],"transports_detected":[],"deployment_artifacts":["Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing/functionapp_azuredeploy.json","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/functionapp_azuredeploy.json","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing/FunctionApp.zip","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionApp.zip","Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip",".github/workflows/codeql.yml",".github/dependabot.yml"],"provenance":{"publisher":"Azure","publisher_verified":true,"signed_build":false,"dependency_cve_count":23,"maintenance_active":false,"declared_policy":false}},"component_findings":[{"rule_id":"ATR-M0001","rule_version":"1.2.0","rule_name":"Tool Definition Integrity & Versioning (ETDI-style)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"This component is a pair of local, operator-run PowerShell CLI scripts, not an MCP server; there is no tool manifest/registry to version or sign.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents rug-pull tool poisoning.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0002","rule_version":"1.1.0","rule_name":"Unrestricted Tool Permissions (Overprivileged Tools)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No MCP tool registry/capability model exists; this is a local script invoked directly by an operator with their own credentials.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Limits blast radius and privilege escalation.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0003","rule_version":"1.3.1","rule_name":"CORS / Origin / Host Validation (DNS Rebinding Defense)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No listener/remote transport exists; this is an outbound-only CLI script.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents DNS rebinding/browser hijack of local or remote MCP.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0004","rule_version":"1.2.0","rule_name":"Binding to 0.0.0.0 Without Auth/TLS","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No listener exists in this component; it only makes outbound HTTPS calls.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"LAN/Internet exposure enables remote exploitation.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0005","rule_version":"1.4.0","rule_name":"OAuth 2.1 + PKCE Correctness (MCP Authorization)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"This is not an MCP server; it is a CLI script that uses an operator-supplied bearer token copied manually from the browser, outside of any OAuth/PKCE flow implemented by this code.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Misconfig enables token theft and confused-deputy attacks.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0006","rule_version":"1.2.0","rule_name":"Tool Name Collision / Spoofing","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No MCP tool registry exists for this local CLI script pair.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents malicious tool shadowing.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0007","rule_version":"1.2.0","rule_name":"Prompt/Metadata Injection in Tool Descriptions","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No MCP tool definitions/descriptions exist for this component.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents covert model manipulation.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0008","rule_version":"1.2.0","rule_name":"CORS Misuse: Wildcard with Credentials","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"No listener/CORS configuration exists in this outbound-only CLI script.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents credentialed cross-origin abuse.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0009","rule_version":"1.3.0","rule_name":"Transport Security: TLS Everywhere (Remote)","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"This component is an operator-run PowerShell CLI script that makes outbound HTTPS requests to a fixed Security Copilot API URL. It exposes no remote MCP server transport (SSE or streamable-HTTP) for ATR-M0009's TLS-everywhere requirement to gate against. The rule's applicability precondition -- a remote MCP transport -- is not met, so NOT_APPLICABLE is the correct verdict rather than an evaluation of the script's outbound TLS usage.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"MitM can steal tokens and tamper responses.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":19,"end_line":19,"snippet":"$url = \"https://api.securitycopilot.microsoft.com/geo/eastus/promptbooks\""}],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0010","rule_version":"1.4.0","rule_name":"No Authentication or Authorization Checks (General)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"This is not a server exposing tools/resources to remote callers; it is a local script that itself authenticates outbound to the Security Copilot API using an operator-supplied bearer token. There is no listener for this rule to gate.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Prevents unauthorized tool use and data access.","context_note":null,"within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"rule_id":"ATR-M0011","rule_version":"1.2.0","rule_name":"OAuth Proxy Per-Client Consent (Confused Deputy Defense)","finding":"NOT_APPLICABLE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"This component is not an OAuth proxy; it does not forward to an upstream IdP on behalf of dynamically-registered MCP clients.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Shared upstream client + dynamic MCP-client registration + no per-client consent enables attacker-registered MCP clients to receive bridge codes carrying victim upstream tokens — the documented MCP Confused Deputy attack.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"}],"repo_findings_inherited":[{"rule_id":"ATR-C0001","rule_version":"1.2.0","rule_name":"Unrestricted Network Fetch / SSRF","finding":"UNKNOWN","severity":"HIGH","realized_severity":null,"confidence":"low","rationale":"Manual review (via python zipfile extraction, not committed as extracted source) of FunctionApp.zip's parse_email/__init__.py shows an expand_url() helper that calls requests.Session().head(url, allow_redirects=True) on email-derived URLs gated only by a hardcoded shortener-domain allowlist (no private-IP/loopback/metadata denylist), which looks like a plausible SSRF primitive. However, this code exists ONLY inside a committed binary zip deployment artifact (FunctionApp.zip) and is not present as an extracted/plain-text file anywhere in the repository tree, so it cannot be cited with a repo-relative path + line-number snippet that is independently verifiable by opening that path in the repo (the actual repo file at that path is binary zip bytes, not the Python source). Per the evidence contract, required_evidence classes could not be established against a verifiable repo-relative source file. Abstaining rather than asserting VULNERABLE against unverifiable evidence.","vulnerability_details":null,"fix_guidance":"Extract and commit function source as plain text (not only as a zip blob) for reviewability; add IP-class validation (resolve host, reject RFC1918/loopback/link-local/169.254.169.254) before any outbound HEAD/GET request derived from email content.","why_this_matters":"Enables internal pivoting and data exfiltration.","context_note":null,"within_declared_contract":true,"transport_gated":null,"mitigation_present":true,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0002","rule_version":"1.3.2","rule_name":"Static Secrets","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"medium","rationale":"Gitleaks scan (0 findings) plus manual grep for API_KEY/SECRET/TOKEN/PASSWORD literal assignments across YAML/JSON/PS1/Python files found no committed secret VALUES -- only schema/property names (e.g. 'apiAccessToken', 'token:' as an OpenAPI schema field name in Netskope/CrowdSec plugin specs) and placeholder example URLs (https://example.com). The PromptBooks PowerShell scripts require the operator to pass a bearer token as a command-line parameter (-token) copied manually from browser devtools each run; no token is hardcoded or persisted in the repo. No .env files with real values, no AKIA/ghp_/sk- patterns found.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Plaintext secrets are easily exfiltrated.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Plugins/Published Plugins/CrowdSecTI/crowdsecTI_smoke.yaml","start_line":62,"end_line":68,"snippet":"      security:\n        - api_key: []\n  \ncomponents:\n  securitySchemes:\n    api_key:\n      type: \"apiKey\"\n      name: \"x-api-key\"\n      in: \"header\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0003","rule_version":"1.3.0","rule_name":"Runtime Command Injection via Process Execution","finding":"UNKNOWN","severity":"CRITICAL","realized_severity":null,"confidence":"medium","rationale":"Manual archive extraction found only a single subprocess call in application code: a fixed-argv invocation of 'antiword' with a locally generated temp-file path as its only argument, with no shell=True and no attacker-controlled command text reaching the sink; no eval()/Function()/dynamic-code-execution pattern was found elsewhere. However, this code exists only inside a committed binary ZIP deployment artifact and is not present as an extracted, plain-text file at a stable repository path, so the required source citation cannot be independently re-opened and re-verified at that path. Given this unresolved source-attestation gap, the verdict is UNKNOWN rather than SECURE.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Unsanitized command construction in shipped runtime code can give a remote attacker arbitrary code execution with the application's privileges.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::extractors/word_extractor.py","start_line":100,"end_line":110,"snippet":"with tempfile.NamedTemporaryFile(delete=False) as temp_file:\n    temp_file.write(word_data)\n    temp_file_path = temp_file.name\ntry:\n    result = subprocess.run(\n        [\"antiword\", temp_file_path],\n        capture_output=True,\n        text=True,\n        check=True\n    )"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0004","rule_version":"1.2.0","rule_name":"DoS Protections: Timeouts, Concurrency, Streaming Limits","finding":"UNKNOWN","severity":"MEDIUM","realized_severity":null,"confidence":"low","rationale":"Manual extraction of FunctionAppV2.zip shows function_app.py accepting a caller-supplied 'max_depth' query parameter with no upper-bound clamp, passed into parsers/email_parser.py's recursive parse_email(), and no visible request-body-size limit in host.json. This looks like a plausible unbounded-recursion/resource-exhaustion vector, but the code exists only inside a committed binary zip deployment artifact, not as an extracted plain-text file at a reviewable repo path -- so a reviewer opening the cited path sees zip bytes, not the Python source quoted in evidence. Abstaining to UNKNOWN rather than asserting VULNERABLE against unverifiable evidence.","vulnerability_details":null,"fix_guidance":"Commit function source as extracted plain text for reviewability; clamp max_depth to a fixed ceiling; add a request body size limit and a processing time budget around attachment parsing.","why_this_matters":"Resource exhaustion can crash or stall MCP.","context_note":null,"within_declared_contract":true,"transport_gated":false,"mitigation_present":false,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0005","rule_version":"1.2.0","rule_name":"Logging Hygiene (No Secrets/PII/Tokens) & Audit Trail","finding":"UNKNOWN","severity":"MEDIUM","realized_severity":null,"confidence":"low","rationale":"The Function App code (committed only as binary FunctionApp.zip / FunctionAppV2.zip, not extracted plain text) uses Python logging extensively with DEBUG-level statements that could log request bodies/content in some paths (e.g. parse_email/__init__.py logs 'Raw request body (as bytes)' truncated to 100 chars, and various functions log full decoded content at DEBUG level). host.json sets default logLevel to 'Debug' for both Function Apps, which in production would surface verbose content (including potentially PII from parsed phishing emails) into Application Insights logs. However, because this code exists only inside committed zip binaries and not as reviewable plain-text repo files, a definitive source-to-sink citation at a stable repo path/line cannot be established per the evidence contract. The PowerShell Promptbook scripts avoid logging the bearer token itself (Write-Host calls never echo $token or $headers). Abstaining on the Function App logging question specifically due to the binary-artifact citation issue; the PowerShell scripts alone would be SECURE but are evaluated together with the Function Apps for this repo-level rule.","vulnerability_details":null,"fix_guidance":"Extract and commit function source as plain text; set host.json default logLevel to Information/Warning for production; ensure DEBUG-level logs that include email body/attachment content are gated off outside of explicit troubleshooting.","why_this_matters":"Prevents sensitive data leakage; enables forensics.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":["parse_email_functionapp","parse_email (FunctionApp v1)"],"component_name":null},{"rule_id":"ATR-C0006","rule_version":"1.2.0","rule_name":"Container/Runtime Hardening","finding":"NOT_APPLICABLE","severity":"MEDIUM","realized_severity":null,"confidence":"high","rationale":"No Dockerfile, docker-compose, Helm chart, or Kubernetes manifest exists anywhere in this repository (confirmed via repo-wide find for Dockerfile*/docker-compose*/*.tf and directory listing). Deployment artifacts present are Azure ARM/Logic App JSON templates and Azure Function App zip packages, which run on Azure's managed PaaS compute (Functions/Logic Apps/App Service) rather than a repo-controlled container image, so there is no container hardening surface (USER, capabilities, seccomp, hostNetwork) for this rule to evaluate.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Reduces blast radius of exploits.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0007","rule_version":"1.2.0","rule_name":"Dependency Risk & Supply Chain","finding":"VULNERABLE","severity":"HIGH","realized_severity":"HIGH","confidence":"medium","rationale":"The FunctionAppV2 requirements.txt uses open-ended version ranges ('azure-functions' with no version at all; 'tnefparse>=1.4.0', 'extract-msg>=0.30.0', etc.) with no lockfile pinning exact resolved versions, and GitHub Actions workflow dependencies float on mutable tags (actions/checkout@v4, github/codeql-action/init@v3, github/codeql-action/analyze@v3) rather than pinned SHAs -- flagged by Semgrep (yaml.github-actions.security.github-actions-mutable-action-tag, 3 findings in .github/workflows/codeql.yml) as a supply-chain risk.","vulnerability_details":"No requirements.lock / poetry.lock exists for any Python component; all pins in FunctionAppV2's requirements.txt are >= floors, not ==; CI workflow uses mutable @v3/@v4 tags instead of pinned 40-character commit SHAs that execute on every push/PR/scheduled run to main.","fix_guidance":"Generate and commit a pip-compile/poetry lockfile pinning exact transitive versions; pin GitHub Actions to full commit SHAs per Semgrep's guidance; enable Dependabot cooldown.","why_this_matters":"Prevents typosquat and malicious update compromise.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0007 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals HIGH.","within_declared_contract":false,"transport_gated":false,"mitigation_present":false,"evidence":[{"path":".github/workflows/codeql.yml","start_line":54,"end_line":60,"snippet":"    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v4\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3"},{"path":".github/workflows/codeql.yml","start_line":16,"end_line":16,"snippet":"on:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n  schedule:\n    - cron: '38 6 * * 5'\n\njobs:\n  analyze:"},{"path":".github/dependabot.yml","start_line":5,"end_line":10,"snippet":"version: 2\nupdates:\n  - package-ecosystem: \"\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0008","rule_version":"1.2.0","rule_name":"Missing or Inadequate Input Validation","finding":"UNKNOWN","severity":"HIGH","realized_severity":null,"confidence":"low","rationale":"Archive review confirms that the extract_regex_functionapp endpoint (functions/regex_extractor/extractor.py) accepts a caller-supplied pattern and subject from the request JSON and calls Python's re.search(pattern, subject) with no length or complexity limit, a plausible ReDoS primitive given Python re's susceptibility to catastrophic backtracking. However, the only repository-visible invocation of this function, from the deployed Logic App, supplies a fixed regex pattern and a trigger-derived subject, and direct endpoint access requires a Function-level key; whether an external attacker can control the pattern or obtain a valid function key is not established anywhere in the repository. This unresolved trigger-capability gap, not any unreviewability of the ZIP contents, is why the verdict remains UNKNOWN.","vulnerability_details":null,"fix_guidance":"Validate and bound regex pattern complexity and length before calling re.search (or enforce a matching timeout), and determine whether the extractor endpoint can be reached by external callers without a valid function key or whether the Logic App only ever supplies fixed, non-attacker-controlled patterns.","why_this_matters":"Frontline control to prevent multiple classes of vulns.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":["extract_regex_functionapp"],"component_name":null},{"rule_id":"ATR-C0009","rule_version":"1.2.0","rule_name":"Insecure Deserialization","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"medium","rationale":"No pickle.loads, yaml.load() (unsafe), marshal.load, or other unsafe deserializer was found in any Python code across both Function App zip archives (grepped across all extracted .py files excluding vendored site-packages). All JSON handling uses the standard json.loads/json.dumps (safe), and YAML files in the repo (plugin manifests) are static configuration consumed by Security Copilot's own backend, not deserialized by application code in this repo.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Can lead to arbitrary code execution.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::functions/json_cleaner/cleaner.py","start_line":1,"end_line":5,"snippet":"import json\nimport logging\nimport re\nimport azure.functions as func"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0010","rule_version":"1.2.0","rule_name":"Lack of Output Encoding/Sanitization","finding":"VULNERABLE","severity":"MEDIUM","realized_severity":"MEDIUM","confidence":"medium","rationale":"The generate_html_report_functionapp endpoint builds its HTML report using a Jinja2 Template constructed from a raw triple-quoted string, so autoescape defaults to off, and the template interpolates values from the submitted analysis JSON via unescaped {{ value }} expressions. The companion Logic App's mailbox-triggered workflow invokes this function with parsed, attacker-influenced email-analysis content and forwards its rendered output as an outbound HTML report, so content embedded in a reported phishing email (e.g. '<script>' markup) can reach the unescaped template interpolation and be reflected as live markup in the generated report.","vulnerability_details":"req_body = req.get_json() is the full attacker-controlled POST body passed unmodified into create_html(req_body); Template() defaults to autoescape=False and the template's {{ value }} expressions do not apply |e, so any value containing e.g. '<script>' is reflected as live markup in the HTTP response body served with mimetype text/html.","fix_guidance":"Use jinja2.Environment(autoescape=True) or select_autoescape() instead of the bare Template() class, and apply the |e escape filter to every interpolated value sourced from the analysis JSON before rendering.","why_this_matters":"Prevents UI-level injection and operator compromise.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0010 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals MEDIUM.","within_declared_contract":false,"transport_gated":false,"mitigation_present":false,"evidence":[{"path":"Plugins/Published Plugins/Netskope-Copilot-Plugin/CoPilotOpenAPISpec.yaml","start_line":12260,"end_line":160,"snippet":"    Response:\n      type: object\n      properties:\n        status:\n          type: string\n          enum:\n            - success\n            - error\n        data:\n          oneOf:\n            - $ref: '#/components/schemas/Forensics'"},{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/FunctionAppV2.zip::functions/html_report/generator.py","start_line":1,"end_line":17,"snippet":"import logging\nfrom jinja2 import Template\nfrom urllib.parse import unquote\nimport azure.functions as func\n\nlogger = logging.getLogger(__name__)\n\nCATEGORY_STYLES = {\n    \"PHISHING\": \"background-color: #d9534f; ...\",\n    ...\n}\n\ndef create_html(json_data):\n    html_template = '''\n    <html>"},{"path":"Plugins/Published Plugins/Netskope-Copilot-Plugin/CoPilotOpenAPISpec.yaml","start_line":12260,"end_line":165,"snippet":"    Response:\n      type: object\n      properties:\n        status:\n            return func.HttpResponse(... status_code=400)\n          enum:\n            - success\n        return func.HttpResponse(html_report, status_code=200, mimetype=\"text/html\", ...)"}],"affected_tools":["generate_html_report_functionapp"],"component_name":null},{"rule_id":"ATR-C0011","rule_version":"1.4.0","rule_name":"Path Traversal & Symlink Bypass (Filesystem Tools)","finding":"VULNERABLE","severity":"HIGH","realized_severity":"HIGH","confidence":"medium","rationale":"The downloaded promptbook's 'name' field originates from the Security Copilot API response and is passed through a chain of string replacements that strip quote, parenthesis, and bracket characters but leave '..' sequences and path separators intact. The sanitized name is concatenated onto the fixed './Downloads/' prefix and written via Out-File, which resolves '../' segments in the resulting path, so a crafted promptbook name containing traversal sequences can cause the script to write a file outside the intended Downloads directory.","vulnerability_details":null,"fix_guidance":"Strip or reject '..' sequences and path separators from the promptbook name (or resolve the final output path and verify it remains within the Downloads directory) before passing it to Out-File.","why_this_matters":"Traversal exposes arbitrary host files; can lead to code execution.","context_note":"[none|relief:none] No context relief applies; realized severity equals HIGH.","within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":30,"end_line":38,"snippet":"$response = Invoke-WebRequest -Uri $url -Method GET -Headers $headers\n$jsonContent = $response.content\n$fromJson = $jsonContent | ConvertFrom-Json \n\nWrite-Host \"Number of promptbooks Downloaded: $($fromJson.value.Count)\" #$jsonContent\n\n# Iterate for each promptbook in JSON\n$folder = './Downloads/'\nforeach ($pb in $fromJson.value) {"},{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":41,"end_line":49,"snippet":"        $fileName = $pb.name + \".json\"\n        # Remove all special chars from filename\n        $fileName= $fileName.replace(\"'\",\"\")\n        $fileName= $fileName.replace(\"(\",\"\")\n        $fileName= $fileName.replace(\")\",\"\")\n        $fileName= $fileName.replace(\"[\",\"-\")\n        $fileName= $fileName.replace(\"]\",\"-\")\n        $fileName= $fileName.replace(' ','_') \n        $fileName = $folder + $fileName "},{"path":"Promptbook samples/Powershell to Manage Promptbooks/PromptbooksDownload.ps1","start_line":65,"end_line":70,"snippet":"\n        $json = $pb | ConvertTo-Json\n        #Write-Host $json\n        \"$json\" | out-file -filepath $fileName #-encoding utf8NoBOM\n\n        Write-Host \"Written file $($fileName)\""}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0012","rule_version":"1.2.0","rule_name":"Denial of Wallet / Cost Controls","finding":"VULNERABLE","severity":"MEDIUM","realized_severity":"MEDIUM","confidence":"low","rationale":"The FunctionAppV2 ARM template explicitly provisions the Y1/Dynamic consumption hosting plan, and the companion Logic App polls a shared mailbox, triggering a metered run -- including attachment parsing and Function invocations -- for each arriving email. No repository-defined per-sender quota, rate limit, or budget gate exists on this mailbox-triggered path, so an attacker able to send email to the monitored mailbox can drive consumption-based billing at volume.","vulnerability_details":null,"fix_guidance":"Add a per-sender or per-time-window rate limit and a budget alert in front of the mailbox-triggered workflow, and consider a hosting plan with a fixed cost ceiling to bound consumption-driven billing exposure.","why_this_matters":"Prevents cost-based disruption.","context_note":"[capability_by_design|relief:none|ineligible:within_declared_contract] within_declared_contract is ineligible for relief on ATR-C0012 because the rule declares that signal orthogonal to its risk (discount_ineligible_signals); the reported behaviour is within the tool's declared capability, and that does not reduce this finding's severity. No context relief applies; realized severity equals MEDIUM.","within_declared_contract":null,"transport_gated":null,"mitigation_present":null,"evidence":[{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/logicapp_azuredeploy.json","start_line":180,"end_line":203,"snippet":"                    \"triggers\": {\n                        \"When_a_new_email_arrives_in_a_shared_mailbox_(V2)\": {\n                            \"recurrence\": {\n                                \"interval\": 3,\n                                \"frequency\": \"Minute\"\n                            },\n                            \"evaluatedRecurrence\": {\n                                \"interval\": 3,\n                                \"frequency\": \"Minute\"\n                            },\n                            \"splitOn\": \"@triggerBody()?['value']\",\n                            \"type\": \"ApiConnection\",\n                            \"inputs\": {\n                                \"host\": {\n                                    \"connection\": {\n                                        \"name\": \"@parameters('$connections')['office365-1']['connectionId']\"\n                                    }\n                                },\n                                \"method\": \"get\",\n                                \"path\": \"/v2/SharedMailbox/Mail/OnNewEmail\",\n                                \"queries\": {\n                                    \"mailboxAddress\": \"[parameters('SharedMailboxAddress')]\",\n                                    \"importance\": \"Any\",\n                                    \"hasAttachments\": false,"},{"path":"Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsingV2/functionapp_azuredeploy.json","start_line":33,"end_line":48,"snippet":"            \"type\": \"Microsoft.Web/serverfarms\",\n            \"apiVersion\": \"2018-02-01\",\n            \"name\": \"[variables('FunctionAppName')]\",\n            \"location\": \"[resourceGroup().location]\",\n            \"sku\": {\n                \"name\": \"Y1\",\n                \"tier\": \"Dynamic\"\n            },\n            \"kind\": \"functionapp,linux\",\n            \"properties\": {\n                \"name\": \"[variables('FunctionAppName')]\",\n                \"workerSize\": \"0\",\n                \"workerSizeId\": \"0\",\n                \"numberOfWorkers\": \"1\",\n                \"reserved\": true\n            }"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0013","rule_version":"1.1.0","rule_name":"Tool Output Sanitization & Injection Containment","finding":"NOT_APPLICABLE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"This rule targets MCP tool-output handling that gets concatenated into an LLM's context window (envelope/untrustedReturn annotation, control-character stripping before injection into a model prompt). No MCP server or LLM-tool-calling host exists in this repository; the Function Apps here return data to a Logic App orchestration / Azure consumer, not into an LLM context window managed by this codebase. The HTML-report-generation XSS issue (ATR-C0010) is a related but distinct rendering-sanitization concern already captured under its own rule.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"Tool outputs are a primary prompt-injection vector. Third-party content (web pages, files, API responses) may contain text crafted to override instructions or impersonate system/tool messages. Without a host-enforced envelope, sanitization, and an explicit untrusted-return signal, the model can be coerced into executing attacker-controlled directives, leaking secrets, or chaining further tool calls on behalf of the adversary.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[],"affected_tools":null,"component_name":null},{"rule_id":"ATR-C0014","rule_version":"1.2.0","rule_name":"CI/CD Workflow Script Injection","finding":"SECURE","severity":"HIGH","realized_severity":null,"confidence":"high","rationale":"The only workflow in this repo, .github/workflows/codeql.yml, has a single 'run:' block (lines 78-83) that is a static, hardcoded multi-line echo/message with NO interpolation of any github.event.*, github.head_ref, inputs.*, or needs.* expression -- it only prints fixed instructional text about manual build steps. Triggers are push/pull_request (both scoped to the 'main' branch) and a weekly schedule; none of pull_request_target, issue_comment, workflow_run, or repository_dispatch are used. The only '${{ }}' expressions in the file (matrix.language, matrix.build-mode) are workflow-internal matrix values defined in the same file, not attacker-controlled external input, and none of them reach a shell run block -- they are consumed only as 'with:' action inputs (languages:, build-mode:, category:) to the github/codeql-action, not re-parsed by a shell.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"CI/CD script injection can execute attacker-controlled commands with workflow tokens, repository secrets, trusted-runner access, artifact or cache authority, and release or deployment privileges.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":".github/workflows/codeql.yml","start_line":74,"end_line":83,"snippet":"    - if: matrix.build-mode == 'manual'\n      run: |\n        echo 'If you are using a \"manual\" build mode for one or more of the' \\\n          'languages you are analyzing, replace this with the commands to build' \\\n          'your code, for example:'\n        echo '  make bootstrap'\n        echo '  make release'\n        exit 1"},{"path":".github/workflows/codeql.yml","start_line":16,"end_line":16,"snippet":"on:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n  schedule:\n    - cron: '38 6 * * 5'"}],"affected_tools":null,"component_name":null},{"rule_id":"ATR-R0001","rule_version":"1.3.0","rule_name":"Weaponization: Malicious-Purpose Artifact (Offensive Capability by Design)","finding":"SECURE","severity":"CRITICAL","realized_severity":null,"confidence":"high","rationale":"This repository is entirely composed of defensive/detective security-operations content: Microsoft Security Copilot plugin manifests for threat intelligence lookups (CrowdSec, GreyNoise, HaveIBeenPwned), KQL hunting-query plugins for detecting ransomware activity signs, phishing/AiTM detection, anomaly detection, and incident investigation; Logic App automation for triage/reporting; and promptbook samples for SOC analyst workflows. Manual review of the 'Ransomware Signs' plugin (hunts for taskkill.exe/cipher.exe/wevtutil indicators to DETECT ransomware activity, not perform it), the QR-code AiTM phishing DETECTION plugin, and the GEO-IP workshop's 'script_decode.txt' (a benign training exercise asking students to decode and analyze a hex-encoded PowerShell snippet as a SOC exercise, explicitly framed as 'suspicious script analysis' for a defender audience, not an operational payload) found no artifact whose declared purpose is to generate or perform offensive capability. No ransomware-builder, credential-harvester, C2/loader, or mass-abuse tooling exists; all offensive-adjacent content is framed and used for detection/defense/training.","vulnerability_details":null,"fix_guidance":null,"why_this_matters":"An artifact whose purpose is to weaponize the agent -- to produce malware, steal credentials, evade defenses, or run attacks at scale -- is dangerous regardless of how securely it is built; posture controls (auth, input validation, least privilege) cannot make a weapon safe, which is why a confirmed weaponization finding caps the trust verdict to `blocked` rather than being averaged against a good posture score. Catching malicious PURPOSE is a distinct safety control, and it must be conservative because offensive capability is dual-use: legitimate pentest, CTF, defensive, and research work must abstain (UNKNOWN), never block -- unless the artifact itself hides from the people who install, run or audit it.","context_note":null,"within_declared_contract":null,"transport_gated":false,"mitigation_present":null,"evidence":[{"path":"Plugins/Community Based Plugins/Microsoft Defender XDR Custom Plugin Scenarios/Ransomware Signs/Readme.md","start_line":1,"end_line":11,"snippet":"### Signs of ransomware activity Custom Plugin\n\nWelcome to the Signs of ransomware activity custom plugin! Here, you'll discover a Skills that looking up signs of ransomware activity in Defender Advanced Hunting that create queries that locate individual artifacts associated with ransomware activity..."},{"path":"Technical Workshops/Custom Plugin Workshop/Task04_GEO_IP_script/readme.md","start_line":48,"end_line":61,"snippet":"####  Use case\nYou are Soc Analyst in woodgrove Domain, During an endpoint Incident investigation, you found suspicious script that run on your DMZ server, your job is to analyze this script, and share your final to your team member.\nYour task is:\n1. Input this information about the script from the script_decode.txt and ask Copilot to decode it\n2. Extract only the IPs from this script.\n3. Employ the MDTI reputation score to assess these Ip."}],"affected_tools":null,"component_name":null}],"component_tools":[{"tool_name":"PromptbooksDownload.ps1","tool_description":"PowerShell script: downloads all Security Copilot Promptbooks for a tenant via GET using an operator-supplied bearer token, strips identifying fields, writes each as a local JSON file.","types":["read-only","write","secrets-access"],"status":"IMPLEMENTED","component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"},{"tool_name":"PromptbooksUpload.ps1","tool_description":"PowerShell script: uploads every JSON file under ./Uploads to the Security Copilot Promptbooks API via POST using an operator-supplied bearer token.","types":["write","secrets-access"],"status":"IMPLEMENTED","component_name":"cli/Promptbook samples/Powershell to Manage Promptbooks"}],"summary":{"high_level_risks":["This repo is NOT an MCP server / agentic-AI codebase: it is Microsoft's public Security Copilot community content repository (plugin manifests, Logic App ARM templates, Azure Function Apps, promptbook samples, workshop material). All ATR-M (mcp-server) rules are NOT_APPLICABLE -- no MCP server, stdio/SSE/streamable-HTTP transport, or tool registry exists anywhere in the codebase.","Two Azure Function Apps (bundled as binary zip deployment artifacts under 'Logic Apps/SecCopilot-UserReportedPhishing-FuncApp_parsing(V2)') parse untrusted, attacker-influenced phishing-report email content and contain a plausible SSRF primitive: expand_url()/UrlProcessor.expand_url() follows HTTP redirects on URLs extracted from email bodies, gated only by a non-authoritative domain-substring match against known URL-shortener providers (no RFC1918/loopback/metadata-IP denylist). Because this source exists only inside committed binary .zip artifacts rather than plain-text repo files, several related findings (SSRF, DoS via unbounded max_depth, logging hygiene, denial-of-wallet) were adjudicated as UNKNOWN rather than VULNERABLE per the evidence-citation contract, but the underlying code pattern is worth a human follow-up review.","generate_html_report_functionapp (FunctionAppV2) renders attacker-controlled JSON directly into an HTML report using a bare Jinja2 Template() with autoescape OFF and no per-value escaping -- a stored/reflected XSS vector for anyone viewing the generated phishing-analysis report.","Supply-chain hygiene gaps: FunctionAppV2's requirements.txt uses open-ended '>=' version floors with no lockfile; GitHub Actions workflow (.github/workflows/codeql.yml) pins third-party actions to mutable tags (@v3/@v4) instead of commit SHAs (flagged by Semgrep); Dependabot config has no cooldown period and an empty package-ecosystem value.","No MCP server, agent framework, or LLM tool-use component of any kind was found in this repository -- it is a plugin/documentation/IaC repo for Microsoft's first-party Security Copilot product, not an agentic AI system under the MCP threat model this ruleset primarily targets.","No evidence of weaponized/offensive-purpose content: all security-adjacent plugins (ransomware-signs detection, AiTM phishing detection, threat-intel lookups) are defensive/detective in framing and function; no malware-builder, credential-harvester, or C2 tooling exists."],"top_remediations":["Extract and commit the Azure Function App source code as plain text (not only inside binary .zip blobs) so it can be properly code-reviewed and so future SAST/security scans can analyze it directly.","Add IP-class validation (reject RFC1918/loopback/link-local/169.254.169.254) before following any URL extracted from untrusted email content in expand_url()/UrlProcessor.expand_url(), and re-validate on every redirect hop.","Switch generate_html_report_functionapp's Jinja2 Template() to an Environment with autoescape=True (or select_autoescape()) to prevent HTML/script injection into generated phishing-analysis reports.","Pin GitHub Actions to full commit SHAs instead of mutable version tags; add a Dependabot cooldown period; generate and commit a Python lockfile for the Function App's dependencies.","Clamp the caller-controllable 'max_depth' parameter in parse_email_functionapp to a fixed, small ceiling to prevent unbounded-recursion resource exhaustion."]},"rollup":{"component_findings_count":{"vulnerable":0,"secure":0,"not_applicable":11},"repo_findings_inherited_count":{"vulnerable":4,"secure":4,"not_applicable":2},"component_tools_count":{"read_only":1,"write":2,"secrets_access":2},"worst_case_severity":"HIGH"},"trust_scores":{"repo_level":{"score":60,"tier":"low","capability_band":"high","score_confidence":"low","score_interval":{"low":36,"high":84},"factors":["ATR-C0007 HIGH","ATR-C0010 MEDIUM","ATR-C0011 HIGH","ATR-C0012 MEDIUM"]},"component_level":{"score":82,"tier":"medium","capability_band":"high","score_confidence":"medium","score_interval":{"low":65,"high":99},"factors":[]}}}]}