Treat every externally sourced value (API results, URLs, cached artifacts, filesystem-derived error strings, CLI/config inputs) as untrusted at the boundary, and apply context-specific hardening before it can be rendered, logged, persisted, or used in a subprocess.
Practical rules:
-- to prevent argument-injection regressions).Example (Markdown-link hardening):
import re
_SAFE_MARKDOWN_LINK_SCHEMES = ("http://", "https://")
_MARKDOWN_LINK_UNSAFE_CHARS = ("(", ")", "[", "]", "\\")
def _sanitize_url_for_single_line_output(url: str) -> str:
return re.sub(r"[\r\n]+", " ", url).strip()
def render_untrusted_url(url: str) -> str:
if not url:
return ""
url = _sanitize_url_for_single_line_output(url)
if not url.startswith(_SAFE_MARKDOWN_LINK_SCHEMES):
return url # inert plain text
if any(ch in url for ch in _MARKDOWN_LINK_UNSAFE_CHARS):
return url # inert plain text
return f"[{url}]({url})" # safe HTTP(S) only
When implementing changes, add regression tests for: delimiter/active-syntax payloads, newline injection, path-leak checks, allowlist gating, and subprocess argument/host edge cases.