Thanks for taking the time to look at security on this plugin. session-continuity is a small project with a narrow surface area, but it does ship hooks that execute shell scripts on every Claude Code session, so security issues matter.
In scope for a security report:
- Command injection, path traversal, or arbitrary-code execution in the shell hooks (
hooks/*.sh). - Any path by which untrusted input (Claude Code hook JSON payloads, user-supplied file paths, GitHub tag names fed into CI) can cause the hooks or release workflow to execute attacker-controlled code.
- Privilege escalation in
.github/workflows/release.yml(the workflow holdscontents: writeon this repo). - Leakage of secrets or credentials caused by the plugin's behavior.
Out of scope:
- Claude Code itself — report those to Anthropic directly at https://www.anthropic.com/security.
- Third-party MCP servers or other plugins that users happen to have installed alongside this one.
- Denial-of-service against a user's own machine from misusing the slash commands (e.g. asking Claude to loop forever). The slash commands are prose instructions to Claude; they don't execute user-supplied shell.
Please open a private report via GitHub's Security → Report a vulnerability tab on the repo: https://github.com/talgolan/session-continuity/security/advisories/new.
If GitHub Security Advisories isn't available to you for some reason, you can also email the maintainer directly — the email is in recent commit metadata (git log --format='%ae' -1).
Please include:
- A minimal reproduction (hook payload, commit/tag contents, etc.).
- The version of the plugin you tested against (
cat .claude-plugin/plugin.json). - What you believe the impact is.
A reasonable response should arrive within a week. If you haven't heard back after two weeks, please escalate by opening a (non-detailed) public issue pointing at the advisory.
- Hooks read stdin JSON, not env vars. Claude Code delivers hook payloads as stdin; the hooks extract
cwdandtool_input.commandfrom that JSON usinggrep/sed. These values are only used as test operands ([ -d ],[ -f ]), as an argument togit -C, or matched against acaseglob pattern — neverevaled or interpolated into a shell string that gets executed. Failure modes on malformed input are a silentexit 0. - Network call.
hooks/version-check.shmakes one unauthenticatedHEAD-style GET per week per machine to the public GitHub Releases API, with a 3-second timeout, silent failure, and an opt-out env var (SESSION_CONTINUITY_SKIP_UPDATE_CHECK=1). No analytics, no identifiers, no PII. The cache key is stored at${XDG_CACHE_HOME:-$HOME/.cache}/session-continuity/last-check. - Release workflow input validation.
.github/workflows/release.ymlreads the tag name fromGITHUB_REF_NAME, strips the leadingv, and validates the result against a strict semver regex before feeding it toawk. Additional belt-and-suspenders: theawkpattern usesindex()(string-literal match) rather than regex (~), so unusual characters in the tag name can never become pattern metacharacters. - Hook matcher scope.
hooks/hooks.jsonregisters oneSessionStarthook and sevenPreToolUsehooks, split across two matcher groups:matcher: "Bash"—pre-commit-check.shandflaky-gate.sh's commit-message check both carry a per-hookif: Bash(git commit *)filter, so they only spawn ongit commit.learnings-surface.shhas noiffilter in this group — it spawns on everyBashcall, not just commits, since its job is to match the imminent command text against LEARNINGS trigger regexes.matcher: "Write|Edit"—learnings-surface.sh,smoke-gate.sh,proven-gate.sh,occurrence-gate.sh,evidence-gate.sh,flaky-gate.sh, andbackend-parity-gate.shall spawn on everyWrite/Editcall. Each self-scopes internally (by file path pattern — plan files, spec files, orLEARNINGS.md) and exits 0 immediately for files outside its scope, so the broad matcher is narrowed in-script rather than inhooks.json.- Five of these seven (
smoke-gate,proven-gate,occurrence-gate,evidence-gate,backend-parity-gate, andflaky-gate's Write/Edit path) can returnpermissionDecision:"deny"and block the tool call — the others (session-start.sh,pre-commit-check.sh,learnings-surface.sh) are non-blocking,permissionDecision:"allow"or silent-exit only.