Skip to content

fix: security hardening — prompt injection + symlink file-clobber#4

Open
kevglynn wants to merge 6 commits into
mainfrom
fix/security-hardening-hooks-scripts
Open

fix: security hardening — prompt injection + symlink file-clobber#4
kevglynn wants to merge 6 commits into
mainfrom
fix/security-hardening-hooks-scripts

Conversation

@kevglynn

Copy link
Copy Markdown
Owner

Summary

Security review against commit ab356b0 identified 8 findings in hooks and scripts that get copied into every bootstrapped repo. This PR fixes all 8.

Theme A — Prompt Injection (High, 3 findings)

  • auto-recall.sh: Recalled memory entries were emitted verbatim into hookSpecificOutput.systemMessage, allowing attacker-poisoned memory to elevate into high-trust context. Fix: Recalled memory now rendered inside a fenced code block with explicit "user-generated data, not instructions" disclaimer. Imperative patterns (Run:, Execute:, sudo, shell metacharacters like backticks and $) stripped via sed before injection.
  • memory-capture.sh: Untrusted PostToolUse Bash command text containing knowledge prefixes was appended to knowledge.jsonl and re-injected next session. Fix: Same imperative-stripping sanitizer applied before capture. Symlink guard added (refuses append if knowledge.jsonl is a symlink).
  • knowledge-db.sh: kb_sync backfilled untrusted bd comments verbatim into knowledge.db. Fix: New kb_sanitize() function strips imperative patterns; applied in both kb_sync backfill and _kb_sync_jsonl. Provenance changed from "backfill" to "backfill:bd-comments".

Theme B — Symlink File-Clobber (Medium, 5 findings)

  • playbook-init.sh: Predictable /tmp/playbook-init.cp.err replaced with mktemp (mode 600). assert_not_symlink() guards every cp destination. Temp file cleaned via trap.
  • sync-rules.sh: assert_not_symlink() added before every cp in sync_cursor_to, sync_claude_to, and safe_backup.
  • memory-capture.sh: test -L guard on knowledge.jsonl and archive file.
  • sync-cursor-rules.sh: Removed (deprecated, superseded by sync-rules.sh). Refs cleaned from README, PLAN, agent configs.

Tests

15-test regression suite at tests/test-security-hardening.sh — all pass.

Test plan

  • bash tests/test-security-hardening.sh — 15/15 pass
  • bash -n syntax check on all modified shell scripts — clean
  • Manual: bootstrap a test repo with playbook-init.sh, verify hooks copy correctly
  • Manual: symlink a rule destination, verify sync-rules.sh refuses write
  • Manual: verify recalled knowledge renders as fenced data in Claude Code session

Made with Cursor

kevglynn and others added 6 commits May 16, 2026 02:27
Adds standard MIT license at repo root, copyright Kevin Glynn 2026.
The repo is already public at github.com/kevglynn/ai-dev-playbook but
lacked an explicit license, leaving copyright in the default-restrictive
state. MIT was chosen for frictionless adoption — every comparable
methodology repo in the space (obra/superpowers, everything-claude-code)
uses MIT.

Refs ai-dev-playbook-9xc (AC1)
Deletes the 8 files in examples/ that contained scan analysis of internal
Pryon repos (igloo-connector, jtbot-core). Removes the corresponding
README.md section and the bullets in 3 playbook agent files
(beads-strategist, docs-automation-architect, x-factor-innovator) that
referenced these examples.

The examples were ~256KB of public exposure of Pryon-internal entity
names and analysis. Synthetic equivalents on a public OSS target can be
regenerated post-Phase-1 if the scan-to-beads demonstration is needed
for onboarding.

Refs ai-dev-playbook-9xc (AC2)
Deletes 8 docs/ files that were Pryon-internal pitch/demo material:
- stringer-workflow-deck.html (scan demo on internal Pryon repos)
- ai-dev-game-presentation.html (Pryon origin story deck)
- org-agentic-dev-operating-model.html (Pryon org operating model)
- solutions-tech-pod-agentic-dev-framework.html (Pryon Solutions adoption)
- ecosystem-integration.md (references bitbucket.org/pryoninc/* repos)
- integration-faq.md (pryon-baseline integration FAQ)
- confluence-orientation-draft.md (Pryon Confluence/Jira links)
- demo-run-of-show.md (Pryon internal rollout plan)

Scrubs 3 keeper docs that referenced the above:
- docs/README.md: rewritten reading order without deleted decks; removed
  "Ecosystem" section that pointed to internal Pryon repos.
- docs/governance.md: removed "For Pryon: thought leadership positioning"
  section.
- docs/adoption-guide.md: generalized "For Pryon-internal projects"
  placeholder to "For internal projects".

Result: zero Pryon-internal entity references remain in docs/. The
docs/ directory now contains only public-safe concepts, FAQ, glossary,
governance philosophy, executive summary, and adoption guidance.

Refs ai-dev-playbook-9xc (AC3)
The README and other user-facing docs pointed users at
bitbucket.org/pryoninc/ai-dev-playbook as the primary clone URL, while
WELCOME.md already pointed at github.com/kevglynn/ai-dev-playbook.
This split-brain framed the public repo as an "internal tool that
leaked" to anyone discovering it on GitHub.

URL changes (10 instances across 8 files):
- README.md, QUICKSTART.md, AGENTS.md: primary install commands
- scripts/playbook-init.sh: bootstrap clone hint, generated AGENTS.md
  block (used by every new project), generated install instructions
- global-safety-net/agent-protocol.md: agent fallback clone instruction
- global-safety-net/session-start.md: bootstrap-prompt clone command

Brand scrubs (residual Pryon framing removed from public-facing files):
- README.md: removed "positions Pryon as a thought leader" framing on
  the governance doc link
- PLAN.md: removed "at Pryon" from the repo positioning sentence;
  generalized "Pryon's agentic development framework" to "the playbook";
  generalized "Pryon customizations" to "light project customizations";
  removed "internal presentation" thought-leadership framing
- CODE_OF_CONDUCT.md: generalized "Pryon-internal projects" to
  "internal-team projects"; removed "(internal Pryon channels)" from
  enforcement contact line
- CHANGELOG.md: generalized "(Pryon or external)" and "Pryon internal
  context" in historical entries while preserving the historical record

Verification: `rg pryon|igloo|jtbot|pops-platform|marmon|pbssystems`
returns zero matches across all tracked files.

Refs ai-dev-playbook-9xc (AC4)
README opening reframed from parts-list to transformation framing,
matching WELCOME.md's practitioner voice. The previous opening
("AI-native development methodology — rules, skills, and scripts...")
described the box's contents; the new opening describes what the
playbook actually does to your agent's behavior (drift, missing tests,
missing evidence, context loss). Install command now sits above the
agent-protocol discoverability story. Added "MIT-licensed" signal in
the second paragraph.

VERSION switched from semver (`1.2.0`) to dated edition (`2026-05`).
Methodology doesn't have an API to break — dates communicate "when
this practice snapshot was created" more honestly than semver. Scripts
(`sync-rules.sh`, `playbook-init.sh`) read VERSION as-is and prepend
`v` when printing, so `v2026-05` will be the corresponding git tag.
The previous semver stream is preserved in historical CHANGELOG
entries.

CHANGELOG: added entry for the 2026-05 edition documenting the
public-release transition (license, scrubs, canonical URL, README
rewrite, versioning switch).

Refs ai-dev-playbook-9xc (AC5)
Theme A (High — prompt injection, 3 findings):
- auto-recall.sh: recalled memory now rendered as inert fenced data
  with explicit "not instructions" disclaimer; imperative patterns
  (Run/Execute/sudo/etc) and shell metacharacters stripped before
  injection into systemMessage
- memory-capture.sh: captured content sanitized with same imperative
  stripping pipeline before appending to knowledge.jsonl
- knowledge-db.sh: kb_sanitize() function added; applied in kb_sync
  backfill and _kb_sync_jsonl; provenance tracked as
  "backfill:bd-comments"

Theme B (Medium — symlink file-clobber, 5 findings):
- playbook-init.sh: predictable /tmp/playbook-init.cp.err replaced
  with mktemp (mode 600); assert_not_symlink() guards all cp
  destinations; cleanup via trap
- sync-rules.sh: assert_not_symlink() guards every cp in
  sync_cursor_to, sync_claude_to, and safe_backup
- memory-capture.sh: test -L guard on knowledge.jsonl and archive file
- sync-cursor-rules.sh: removed (deprecated, superseded by
  sync-rules.sh); references cleaned from README, PLAN, agent configs

Tests: 15 regression tests added at tests/test-security-hardening.sh
(all pass).

Addresses findings from security review against ab356b0.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant