Skip to content

[Bug]: extensions/git auto-commit.sh stages every untracked file with git add . — risks committing secrets / artifacts #2478

@hsmorikawa

Description

@hsmorikawa

Bug Description

`extensions/git/scripts/bash/auto-commit.sh` line 137 calls `git add .` to stage changes for the auto-commit, which indiscriminately stages every modified or untracked file in the working tree at the time the hook fires (after_specify / after_plan / after_tasks etc.). Anything not in `.gitignore` — `.env`, ad-hoc local debug files, build artifacts, IDE state — gets committed and pushed under `[Spec Kit] Auto-commit ...`.

Source: https://github.com/github/spec-kit/blob/main/extensions/git/scripts/bash/auto-commit.sh#L136-L138

# Stage and commit
_git_out=\$(git add . 2>&1) || { ... }
_git_out=\$(git commit -q -m \"\$_commit_msg\" 2>&1) || { ... }

The auto-commit hook is intended to capture Spec Kit artifacts (spec.md, plan.md, tasks.md, .specify/, etc.). Bulk `git add .` violates least-privilege staging and turns a workflow hook into a foot-gun for users who keep transient files in their workspace.

Steps to Reproduce

  1. Initialize Spec Kit with the git extension enabled (the default on recent versions).
  2. In the project root, create a file the user did not intend to commit: `echo 'OPENAI_API_KEY=sk-real' > .env.local` (or any uncommitted untracked file not covered by gitignore).
  3. Run `/speckit.specify` or any command whose `after_*` hook triggers auto-commit.
  4. Inspect `git log -p -1` — the unrelated untracked file is included in the auto-commit.

Expected Behavior

The hook stages only Spec Kit's own artifacts. Suggested set:

  • `.specify/` (excluding generated scratch state if any)
  • `specs//spec.md`, `plan.md`, `tasks.md`, `research.md`, `data-model.md`, `quickstart.md`, `contracts/`
  • `.claude/`, `.gemini/`, `.copilot/` etc. depending on integration
  • `CLAUDE.md` / `AGENTS.md` if the integration appended SPECKIT markers

Actual Behavior

`git add .` stages everything not gitignored, including secrets the user simply hadn't gitignored yet.

Specify CLI Version

0.7.4.dev0

AI Agent

Claude Code

Suggested Fix

Replace line 137 with an explicit allowlist of paths Spec Kit owns. Example sketch (refine per integration):

_paths=(
  \".specify\"
  \"specs\"
  \"CLAUDE.md\" \"AGENTS.md\" \"GEMINI.md\"   # only the ones that exist
)
# Resolve integration-managed dotdirs (.claude/, .gemini/, .copilot/, .agents/ ...)
case \"\$INTEGRATION\" in
  claude) _paths+=(\".claude\") ;;
  gemini) _paths+=(\".gemini\") ;;
  copilot) _paths+=(\".github\") ;;
  ...
esac
# Filter to existing entries to avoid \"pathspec did not match\" errors:
_existing=()
for _p in \"\${_paths[@]}\"; do [ -e \"\$_p\" ] && _existing+=(\"\$_p\"); done
[ \${#_existing[@]} -gt 0 ] && git add -- \"\${_existing[@]}\"

If a generic allowlist is too tight (for users who customize), an opt-in env var (e.g. `SPECKIT_AUTO_COMMIT_ALL=1`) could preserve the current bulk behavior for users who want it.

Context

Surfaced during a defensive code review while bulk-installing Spec Kit + auto-commit hooks across 20 internal repos. Several of those repos contain medical / security tooling where stray local files would be high-impact to commit. The current `git add .` makes the extension unsafe to enable by default in any repo where users keep `.env*` or similar locally.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions