T02 · Agent Memory Poisoning
- Location
SKILL.md:390- Finding
Persistent Agent Instruction Injection Through AGENTS.md
- Content
View full analysis
/AGENTS.md` into context at session start. That's the right place for the orchestrator's hardrails to live so they fire even on free-form user prompts that don't cleanly match any SKILL.md trigger. On every orchestrator run, ensure the routing block is present AND that no stale-version blocks co-exist with the current one. **Always run the stripper unconditionally** — never trust a "current-version-is- present" grep to short-circuit, because an older block from a prior version can still be there alongside it and the agent may read the older (weaker) rules first. ```bash SHARED="${HOME}/.openclaw/skills/outclaw/shared" TENANT=$(bash "$SHARED/scripts/tenant.sh") WS_AGENTS="${HOME}/.openclaw/workspace/${TENANT}/AGENTS.md" mkdir -p "$(dirname "$WS_AGENTS")" touch "$WS_AGENTS" # Unconditional strip-then-append: removes EVERY versioned outclaw-routing # block (v*), then appends the current snippet. Idempotent: a second run # with the same snippet produces the same file content. python3 - "$WS_AGENTS" "$SHARED/references/AGENTS_SNIPPET.md" <<'PY' import re, sys ws, snip_path = sys.argv[1], sys.argv[2] try: t = open(ws).read() except FileNotFoundError: t = "" # Strip ALL versions of the routing block, not just older ones. Current # version gets re-added from the snippet below. t = re.sub( r'[\s\S]*?\n?', '', t, flags=re.DOTALL, ) # Collapse resulting blank-line runs to at most one t = re.sub(r'\n{3,}', '\n\n', t) snip = open(snip_path).read() open(ws, "w").write(t.rstrip() + "\n\n" + snip) # Assert exactly one version marker remains remaining = re.finda ...[truncated 2384 chars]- Remediation
View remediation
