T02 · Agent Memory Poisoning
- Location
scripts/create_postman_collection.py:47- Finding
Unescaped User Input Enables Persistent Agent Memory Poisoning
- Content
View full analysis
Vulnerability Details
File Location:
scripts/create_postman_collection.py, lines 47–72
Related Workflow Location:SKILL.md, lines 24–26
Vulnerability Type: Persistent agent memory poisoning through unsanitized Markdown insertion
Risk Level: MediumVulnerable Code
python def remember_domain(domains_path: str, service: str, domain: str) -> None: path = Path(domains_path) path.parent.mkdir(parents=True, exist_ok=True) service = service.strip() domain = domain.strip().rstrip("/") if not service or not domain: raise SystemExit("--service and --domain are required with --remember-domain") if path.exists(): text = path.read_text(encoding="utf-8") else: text = "# Stored Service Domains\n\n## Service mappings\n\n| Service | Domain | Notes |\n| --- | --- | --- |\n" row = f"| {service} | {domain} | Remembered after user confirmation |" if row in text: return if f"| {service} | {domain} |" in text: return marker = "| --- | --- | --- |" if marker in text: text = text.replace(marker, marker + "\n" + row, 1) else: text = text.rstrip() + "\n\n## Service mappings\n\n| Service | Domain | Notes |\n| --- | --- | --- |\n" + row + "\n" path.write_text(text.rstrip() + "\n", encoding="utf-8")The associated workflow explicitly treats the modified file as durable memory:
markdown - After the user provides a new service domain, persist it immediately in `references/domains.md` before generating the Postman file. - Treat `references/domains.md` as the durable memory for service/domain answers. Do not rely only on chat history.Technical Analysis
The
remember_domain()function acceptsserviceanddomainvalues originating from command-line arguments that may be derived directly from user input. It only strips surrounding whitespace and a trailing slash. It does not:- Reject newline or control characters.
- Validate ...[truncated 2691 chars]
- Remediation
View remediation
Remediation Suggestions
-
Strictly validate the domain
- Parse the supplied value with
urllib.parse.urlparse. - Permit only
httpandhttps. - Require a nonempty, syntactically valid hostname.
- Reject credentials, control characters, whitespace, fragments, and unexpected URL components.
- Define an explicit policy for ports, paths, and query strings.
- Parse the supplied value with
-
Validate and constrain service names
- Allow only a restricted character set such as letters, digits, underscores, periods, and hyphens.
- Enforce a reasonable maximum length.
- Reject newline, carriage-return, null, and other control characters.
-
Prevent Markdown injection
- Reject multiline values.
- Escape table metacharacters such as
|and backslashes before Markdown serialization. - Do not rely on simple string interpolation to construct structured storage.
-
Use schema-validated structured storage
- Store mappings in JSON or another format parsed strictly as data.
- Validate loaded records against a schema before use.
- Render Markdown documentation from validated data if human readability is required.
-
Treat persisted content as untrusted
- Explicitly instruct the agent that stored values are data only and must never be followed as instructions.
- Extract only validated mapping fields instead of loading the complete free-form Markdown document into the agent context.
-
Write safely
- Write updates to a temporary file in the same directory and atomically replace the destination after successful validation and serialization.
- Add tests covering newlines, Markdown delimiters, malformed URLs, embedded credentials, fragments, control characters, and oversized values.
-
