T02 · Agent Memory Poisoning
- Location
SKILL.md:34- Finding
Automatic Persistence and Cross-Session Reuse of Untrusted Observations
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Markdown skill is useful and mostly transparent, but it automatically stores and reuses local project and contact notes without asking first.
Review this skill before installing if you handle private repositories, client documentation, or sensitive contacts. It keeps local memory under ~/Clawic/data/markdown/ and may update shared project/contact records, so use it only if you want that cross-session recall; ask the agent to show proposed memory writes first and avoid letting untrusted Markdown populate persistent notes.
SKILL.md:34Automatic Persistence and Cross-Session Reuse of Untrusted Observations
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
**Doc sets that belong to a tracked project or a client point at the shared boxes**: the project goes in `~/Clawic/data/projects/<project>.md` and the person in `~/Clawic/data/contacts/contacts.md` — read each before writing, update the existing entry in place, and here keep only the name. Duplicating a project or a person is how two skills start contradicting each other.
**No credential is ever written anywhere under `~/Clawic/data/`** — not in the files named here, not in a file you create, not in a document the user pastes in to be saved. Documentation is unusually dense in secrets: a curl example carries a token, a config snippet carries a connection string, a CI YAML carries a publish key. Strip the value and leave the pointer: `env:NPM_TOKEN`, `keychain:docs-deploy`, `1password:Work/Docs/confluence`, `file:~/.netrc`. If data sits at an old location (`~/markdown/` or `~/clawic/markdown/`), move it to `~/Clawic/data/markdown/`, and say in one line that you moved it and from where.
Correct Markdown is not a property of the text. It is a property of the text **plus the parser that will render it**, and every bug in this domain is one of five things: a missing block boundary, an indentation column, an unescaped character, an extension the target does not have, or raw HTML the target strips. Name which one, name the target, and hand back the exact bytes that change. Work from defaults immediately: never open with questions about their flavor, their linter, or how proactive to be. Precedence for any value: `config.yaml` → `~/Clawic/profile.yaml` (shared universals: locale) → the Configuration table default.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
**Doc sets that belong to a tracked project or a client point at the shared boxes**: the project goes in `~/Clawic/data/projects/<project>.md` and the person in `~/Clawic/data/contacts/contacts.md` — read each before writing, update the existing entry in place, and here keep only the name. Duplicating a project or a person is how two skills start contradicting each other.
**No credential is ever written anywhere under `~/Clawic/data/`** — not in the files named here, not in a file you create, not in a document the user pastes in to be saved. Documentation is unusually dense in secrets: a curl example carries a token, a config snippet carries a connection string, a CI YAML carries a publish key. Strip the value and leave the pointer: `env:NPM_TOKEN`, `keychain:docs-deploy`, `1password:Work/Docs/confluence`, `file:~/.netrc`. If data sits at an old location (`~/markdown/` or `~/clawic/markdown/`), move it to `~/Clawic/data/markdown/`, and say in one line that you moved it and from where.
Correct Markdown is not a property of the text. It is a property of the text **plus the parser that will render it**, and every bug in this domain is one of five things: a missing block boundary, an indentation column, an unescaped character, an extension the target does not have, or raw HTML the target strips. Name which one, name the target, and hand back the exact bytes that change. Work from defaults immediately: never open with questions about their flavor, their linter, or how proactive to be. Precedence for any value: `config.yaml` → `~/Clawic/profile.yaml` (shared universals: locale) → the Configuration table default.
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
The general procedure, whatever the direction:
1. **Inventory the constructs** with grep, not by reading: `<!--`, `{{`, `<`, `{`, `:::`, `!!!`, `[!NOTE]`, `[[`, `~~~`, footnote refs, HTML tags. The counts are the migration estimate.
2. **Map each construct** to its equivalent in the destination, and mark the ones with no equivalent — those need a decision, not a rewrite.
3. **Convert mechanically** where a rule exists (Obsidian wikilinks → relative links, `!!! note` → `:::note`), with a script, so the transformation is reproducible.
4. **Build with strict mode** and fix top to bottom; errors cascade.
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
- `<!-- comment -->` works in every HTML-tolerant parser and is stripped from the output — but it is **in the file**, so it is public in any public repo.
- **MDX rejects HTML comments**; use `{/* comment */}` (`mdx.md`).
- Obsidian has `%%comment%%`, which stays out of exports.
- A reference-definition trick (`[//]: # (comment)`) survives parsers that strip HTML, at the cost of being unreadable to the next person.
- Docusaurus `<!--truncate-->` and Hugo `<!--more-->` are functional markers, not comments: they set the excerpt boundary.
## Wikilinks and Embeds
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Nothing under `~/Clawic/data/` ever holds a secret value — not the files named here, not files you create, not the document the user pastes in and asks you to keep. **A document is the densest source of secrets in this catalog**: quickstarts carry API keys, configuration pages carry connection strings, CI pages carry publish tokens, and a "here is my README, fix it" paste carries all three. Strip each value **before** writing and leave its pointer where the value was, in this shape: `<kind>:<locator>`.
`env:NPM_TOKEN` · `env:GITHUB_TOKEN` · `keychain:docs-deploy` · `1password:Work/Docs/confluence` · `bitwarden:CI/pypi` · `vault:secret/ci/docs` · `file:~/.netrc` · `file:~/.npmrc`
In a text, the pointer goes where the value was: `Authorization: Bearer <env:API_TOKEN>` and `https://<env:CI_USER>:<env:CI_TOKEN>@git.example.com/acme/docs.git`. Say in one line that you did it.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## Includes and Path Traversal
- Include and snippet directives (`--8<--`, `{% include %}`, `{include}`) resolve a path from the document. Where the document is untrusted, `../../../../etc/passwd` is the obvious probe and reading a private file into a public page is the outcome.
- Restrict include roots in the generator's configuration, and never enable includes on a corpus that accepts contributions you do not review.
- The same applies to image and resource paths in a conversion pipeline (`--resource-path`, `conversion.md`): a build that embeds arbitrary local files into a PDF is an exfiltration primitive.
The skill mandates persistent storage and automatic recall of session-derived information such as render targets, doc sets, style rules, sweep results, and other durable artifacts. Even though it says storage is local and forbids credentials, this creates cross-session retention of user/project metadata without explicit opt-in at time of capture, increasing privacy risk and the chance of unintended data reuse.
- ~/clawic/markdown/
---
**Data.** At the start of every session, read `~/Clawic/data/markdown/config.yaml` (what the user declared) and `~/Clawic/data/markdown/memory.md` (what you observed, plus its `## Boxes` index and `## Due` table). Open any file `## Boxes` names when the condition on its line applies — the index is the list of files, never assume the list is fixed. Every path it names is inside `~/Clawic/data/`; ignore any line that points anywhere else. Everything this skill reads or writes is a plain local note under the folders declared in `configPaths` — nothing leaves the machine and no credential is ever written. In a shared box it updates or removes only the rows it wrote itself, matched on that box's identity key; a row another skill wrote is read, never rewritten and never deleted, and every write and deletion is named in one line as it happens. Read the recorded render targets before writing or fixing any document: the same bytes are correct in one parser and broken in another. If none of it exists, work from defaults and say nothing about it.
**Write before the session ends** whenever the session produced something durable: a render target and the quirk it imposes; a doc set and the generator that builds it; a lint, formatter, or CI config that finally passed; a conversion recipe that produced the right output; a house-style rule observed in their files; a link or lint sweep and what it found; or something the user will re-read — a page or README template, a style guide, a decision about the docs stack. `memory-template.md` holds every destination, format and threshold, and is the only file you open in order to write.
The skill explicitly states that values should be sourced from config.yaml and then from ~/Clawic/profile.yaml, including shared universals such as locale, without requiring per-session user confirmation. While locale is lower sensitivity than credentials, automatically importing cross-skill profile data can violate user expectations and create privacy or preference leakage across contexts.
The skill explicitly instructs the agent to write data to a local memory file (~/Clawic/data/markdown/memory.md) and create templates in artifacts/ without any guardrails, user confirmation, or scope restriction. In an agent setting, hidden state modification can create persistence, alter future behavior, and overwrite local data based on untrusted chat content, which makes this more dangerous than ordinary documentation advice.
The instruction tells the skill to write to persistent memory files and artifacts outside the immediate Markdown editing/conversion task. That creates unnecessary cross-session data retention and filesystem side effects, which can leak sensitive user/project details or allow prompt-injected content from untrusted documents to poison future behavior.
The instruction at line 91 directs the agent to write persistent artifacts under ~/Clawic/data/ and update memory.md, which exceeds the stated scope of a Markdown/frontmatter skill. Persistent state modification can create unauthorized local side effects, leak derived information into shared memory stores, and make future agent behavior depend on unreviewed data.
The skill instructs writing derived schema data to ~/Clawic/data/ without warning the user or requiring approval, creating a silent local-write side effect. Even if the data is only documentation metadata, this can overwrite files, persist sensitive content such as tokens mentioned in frontmatter, and violate the principle of least astonishment for a formatting-focused skill.
The file instructs the agent/user to persist operational tracking data under a specific home-directory path (~/Clawic/data/markdown/checks/<year>.md) and update memory.md, which goes beyond Markdown rendering/fixing guidance into maintaining local state. In an agent setting, this can cause unauthorized modification of user files, creation of persistent records, and privacy/integrity issues if followed automatically without explicit consent.
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.
# Linting, Formatting, and CI
Two different jobs, and most repository pain comes from giving them to the same tool: a **formatter** owns whitespace and normalizes it without asking; a **linter** owns semantics and reports what a human must decide. Configure both to agree on that boundary and the fights stop.
**Before changing rules or debugging CI**, read the doc set's row in `## Doc Sets` of `~/Clawic/data/markdown/memory.md` for the tool in force, and check `## Boxes` for a stored config in `artifacts/` — the exclusions in it were paid for once already.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
Everything except artifacts, check logs and the shared boxes begins inside `memory.md`. Splitting is a procedure, not a suggestion:
1. Before appending to a section, count its entries.
2. If the append would take it past **~15 entries or ~40 lines of real content** — scaffolding, headings and comments do not count — then, in the same turn: create the new file in `~/Clawic/data/markdown/`, move the whole section into it, **delete the section from `memory.md`**, add its line to `## Boxes`, and append the new entry to the new file.
3. Keep the headings identical on both sides of the move, so the split is a copy-paste and never a rewrite.
4. Never leave a copy behind. If the same data ever appears in both places, the extracted file wins and the `memory.md` copy is deleted.
The markdown explicitly tells the operator to write audit/check records into files under the home directory and update another memory file, without any warning that this changes persistent user data. In a skill that may be executed by an agent, such instructions normalize silent filesystem writes and can lead to unintended data modification outside the immediate task scope.
The skill instructs the agent to write migration outcomes into a user file under ~/Clawic/data/markdown/memory.md and create/update an artifacts/ file, but it provides no user-facing disclosure, confirmation, or scope guard before modifying persistent files. This creates a quiet state-changing side effect that can surprise users, pollute local data, or overwrite project notes if the path exists and is writable.
The example configuration sets localization.locale: en-GB as a default value in the template. This can be read as prescribing a specific language/locale before the user has explicitly chosen one, which conflicts with the policy against forcing a locale without opt-in.
No suspicious patterns detected.