Reject path-traversing agent_ids before we touch the filesystem. ``agent_id`` is internally generated by ``generate_task_id`` (CSPRNG base36), so this is defense-in-depth — a future caller passing a user-supplied id would otherwise be able to write to arbitrary paths via ``../../etc
(agent_id: str)
| 97 | |
| 98 | |
| 99 | def _sanitize_agent_id(agent_id: str) -> str: |
| 100 | """Reject path-traversing agent_ids before we touch the filesystem. |
| 101 | |
| 102 | ``agent_id`` is internally generated by ``generate_task_id`` (CSPRNG |
| 103 | base36), so this is defense-in-depth — a future caller passing a |
| 104 | user-supplied id would otherwise be able to write to arbitrary |
| 105 | paths via ``../../etc/passwd``. Mirrors the chapter's symlink-attack |
| 106 | rationale on TS Task.ts:96. |
| 107 | """ |
| 108 | if not agent_id or not all(c.isalnum() or c in "_-" for c in agent_id): |
| 109 | raise ValueError( |
| 110 | f"invalid agent_id for transcript path: {agent_id!r} " |
| 111 | "(allowed: alphanumeric + '_' + '-')" |
| 112 | ) |
| 113 | if len(agent_id) > 64: |
| 114 | raise ValueError(f"agent_id too long ({len(agent_id)} > 64 chars)") |
| 115 | return agent_id |
| 116 | |
| 117 | |
| 118 | # --------------------------------------------------------------------------- |
no outgoing calls
no test coverage detected