T09 · Insecure Skill Coding Practices
- Location
scripts/auto_log.py:64- Finding
Unvalidated Pipeline Summary Fields Permit Filesystem Path Traversal and Persistent Memory Poisoning
- Content
View full analysis
Vulnerability Details
File Location:
scripts/auto_log.py:64-91
Vulnerability Type: Path traversal through untrusted path components
Risk Level: HighVulnerable Code
python def write_memory_record(project: Path, task: dict) -> Path: """写单个 task 的 memory record""" task_type = task.get("task_type", "unknown") timestamp = task.get("timestamp", datetime.now().isoformat()) try: dt = datetime.fromisoformat(timestamp) ts_filename = dt.strftime("%Y-%m-%dT%H-%M-%S") except ValueError: ts_filename = timestamp[:19].replace(":", "-") slug = slugify(task.get("description", "unnamed")) filename = f"{ts_filename}-{slug}.md" memory_dir = project / ".synapse" / "memory" / task_type memory_dir.mkdir(parents=True, exist_ok=True) filepath = memory_dir / filename qa_line = f"qa_result: {task['qa_result']}" if task.get("qa_result") else "" commit_line = f"commit: {task['commit']}" if task.get("commit") else "" content = MEMORY_TEMPLATE.format( task_type=task_type, description=task.get("description", ""), outcome=task.get("outcome", "unknown"), qa_line=qa_line, commit_line=commit_line, timestamp=timestamp, ) filepath.write_text(content.strip() + "\n")Technical Analysis
The
task_typevalue is loaded directly from pipeline-summary JSON and used as a filesystem path component without validation. Python'spathlibpath composition does not enforce containment:- A
task_typecontaining../can traverse outside.synapse/memory. - An absolute
task_typecan cause preceding path components to be discarded, redirecting the write to an arbitrary writable directory. - If timestamp parsing fails, the first 19 timestamp characters are used in the filename after replacing only colons. Path separators and traversal sequences are not removed.
...[truncated 2182 chars]
- A
- Remediation
View remediation
Remediation Suggestions
- Define a strict allowlist of supported task types, such as
feature,bugfix,refactor, anddocumentation. - Reject absolute paths,
.and..components, path separators, null bytes, and unexpected characters. - Sanitize the timestamp through strict date parsing. If parsing fails, generate a server-side timestamp instead of reusing untrusted input.
- Resolve and verify the final destination before writing:
python memory_root = (project / ".synapse" / "memory").resolve() destination = (memory_root / safe_task_type / safe_filename).resolve() if memory_root not in destination.parents: raise ValueError("Memory destination escapes the allowed root") - Open new records using exclusive creation mode where overwriting is not required.
- Treat persisted pipeline content as untrusted data. Escape or delimit free-form values and mark their origin so agents do not interpret them as authoritative instructions.
- Validate the complete summary against a strict JSON schema, including field types, maximum lengths, allowed task types, and timestamp format.
- Add tests covering absolute paths, traversal sequences, malformed timestamps, symlink-based escapes, and instruction-like content.
- Define a strict allowlist of supported task types, such as
