{"id":"PYSEC-2026-2506","summary":"GuardDog: Unsanitized human-readable scan output allows terminal escape injection from malicious package content","details":"# Summary\nGuardDog includes attacker-controlled filenames, file locations, messages, and code snippets in its default human-readable output without escaping terminal control characters. A malicious package can therefore inject ANSI or OSC escape sequences into analyst terminals or CI logs.\n\n# Description\nThe finding formatter stores file paths and snippets from scanned content:\n\n```python\nlocation = file_path + \":\" + str(start_line)\nfinding = {\n    \"location\": location,\n    \"code\": code,\n    \"message\": result[\"extra\"][\"message\"],\n}\n```\n\nThe human-readable reporter later prints these values directly:\n\n```python\n\"  * \" + finding[\"message\"] + \" at \" + finding[\"location\"] + \"\\n    \" + _format_code_line_for_output(finding[\"code\"])\n```\n\nNo escaping is applied for control characters such as `\\x1b`. A malicious package can therefore ship a filename like:\n\n```text\nevil\\x1b[2J.py\n```\n\nor matched source lines containing terminal escapes, which survive into the final CLI output.\n\n# Reproduction summary\n1. Create a file whose name contains `\\x1b[2J`.\n2. Feed a semgrep-style result referencing that file into `Analyzer._format_semgrep_response()`.\n3. Render the result with `HumanReadableReporter.print_scan_results()`.\n4. The output string contains the raw escape bytes, which a terminal may interpret.\n\n# Key code paths\n- `guarddog/analyzer/analyzer.py:377-392`\n- `guarddog/reporters/human_readable.py:36-42`\n- `guarddog/reporters/human_readable.py:84-91`\n\n# Practical impact\nThis can be used to:\n- clear or rewrite analyst terminal output\n- inject misleading or spoofed log content in CI\n- emit clickable OSC 8 hyperlinks or title changes in compatible terminals\n\n# Prior public disclosure check\nAs of 2026-03-18, no matching public GitHub advisory, CVE, or public repo issue was found for this specific bug.\n\n# Suggested fix\nEscape or strip terminal control characters before rendering any attacker-controlled value in human-readable output. This should cover package names, file paths, messages, and code snippets.","aliases":["CVE-2026-44972","GHSA-m5p4-gvpx-4mvr"],"modified":"2026-07-13T16:31:56.153094929Z","published":"2026-07-13T15:15:44.270436Z","references":[{"type":"WEB","url":"https://github.com/DataDog/guarddog/security/advisories/GHSA-m5p4-gvpx-4mvr"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-44972"},{"type":"PACKAGE","url":"https://github.com/DataDog/guarddog"},{"type":"PACKAGE","url":"https://pypi.org/project/guarddog"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-m5p4-gvpx-4mvr"}],"affected":[{"package":{"name":"guarddog","ecosystem":"PyPI","purl":"pkg:pypi/guarddog"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.6.0"},{"last_affected":"2.9.0"}]}],"versions":["2.6.0","2.7.0","2.7.1","2.8.4","2.9.0"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/guarddog/PYSEC-2026-2506.yaml"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"}]}