T09 · Insecure Skill Coding Practices
- Location
`; overrides ad-hoc pricing in proposals | | voice_file | path | none | How the user writes to clients (register, length, sign-off) at `~/Clawic/data/clients/<file>`; overrides the default plain register in every draft | ``` `memory-template.md:21`: ```markdown | **Anything durable this table does not name** | `~/Clawic/data/clients/<plural-noun>.md`, or `artifacts/<kebab-name>.md` if it is a long text read whole | Name the file after what it holds, never after when it was made; add its `## Boxes` line in ...[truncated 3834 chars]:30- Finding
Unsanitized Dynamic File Paths Can Escape Declared Storage Boundaries
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:30-34,SKILL.md:152-153,memory-template.md:21,memory-template.md:196,memory-template.md:202,memory-template.md:235,memory-template.md:256, andmemory-template.md:286
Vulnerability Type: Path traversal through unvalidated names, paths, and index entries
Risk Level: MediumVulnerable Code Snippets
SKILL.md:30:markdown **Data.** At the start of every session, read `~/Clawic/data/clients/config.yaml` (what the user declared) and `~/Clawic/data/clients/memory.md` (what you observed, plus its `## Boxes` index and its `## Due` table). Open any file `## Boxes` names the moment the condition written on its line applies — that index *is* the list of files; never work from a list of names memorised here, because most boxes are created after this skill was written.SKILL.md:34:markdown Table until ~15 people; past that, one file per person at `~/Clawic/data/contacts/<name>.md`, with `contacts.md` left as the index. ... Every engagement with a start, an end and milestones goes to `~/Clawic/data/projects/<project>.md`, one file from the first, identified by the project name;SKILL.md:152-153:markdown | rate_card_file | path | none | Long-form rates and packages at `~/Clawic/data/clients/<file>`; overrides ad-hoc pricing in proposals | | voice_file | path | none | How the user writes to clients (register, length, sign-off) at `~/Clawic/data/clients/<file>`; overrides the default plain register in every draft |memory-template.md:21:markdown | **Anything durable this table does not name** | `~/Clawic/data/clients/<plural-noun>.md`, or `artifacts/<kebab-name>.md` if it is a long text read whole | Name the file after what it holds, never after when it was made; add its `## Boxes` line in the same turn |memory-template.md:196:markdown - **Scale cut**: one row per person while there are ≤15. Past that, one file per person at `~/Clawic/data ...[truncated 3554 chars]- Remediation
View remediation
Remediation Suggestions
- Convert all client, project, contact, and artifact names into generated slugs using a strict allowlist such as
[a-z0-9-]. - Reject absolute paths,
..path segments, directory separators in names, null bytes, and Unicode control or bidirectional characters. - Resolve every target to its canonical path before each read, write, move, or deletion.
- Verify that the canonical target remains beneath an explicitly approved root, such as:
~/Clawic/data/clients/~/Clawic/data/contacts/~/Clawic/data/projects/
- Reject symlinks whose resolved targets escape the corresponding approved root.
- Restrict
rate_card_file,voice_file, and## Boxesvalues to validated relative paths rather than arbitrary paths. - Store stable generated identifiers separately from display names so attacker-controlled names never become filesystem paths.
- Require explicit user confirmation before deleting shared contact or project records.
- Add negative tests for absolute paths, traversal components, mixed separators, encoded traversal, Unicode separators, and symlink escapes.
- Convert all client, project, contact, and artifact names into generated slugs using a strict allowlist such as
