Git hooks are programs that run at defined points in a repository workflow. Their location is configurable. core.hooksPath can move hook discovery from the repository's own .git/hooks directory to a central path, or disable hooks entirely with /dev/null.

That flexibility is useful for build farms and managed developer machines. It also creates an executable policy outside the files that a repository review normally examines.

How the path is resolved

The Git configuration manual states that hooks normally live in $GIT_DIR/hooks. Setting core.hooksPath to a different path makes Git look there instead. The value can be absolute or relative. A relative path is resolved from the directory in which the hook runs.

The relative form matters in CI. Two jobs can have the same configuration but run hooks from different directories. A shared hook directory should therefore be expressed as a known absolute path, or the automation should set the path explicitly for every invocation.

core.hooksPath=/dev/null disables hooks. The manual describes this as a power-user setting and suggests using a command-scoped configuration for temporary cases. A command-scoped override is easier to audit than a machine-wide change that silently affects every repository.

Hooks are code in the workflow

Git hooks can run commands with the privileges of the Git process. In a developer session, that is the developer's account. In a build worker, it may be an account with registry credentials, signing keys, and deployment access. A hook does not need to be committed to the repository to run.

A repository administrator may operate a central hook repository to enforce commit message rules, signing, or deployment checks. That central repository becomes part of the software supply chain. Protect its branch permissions, review changes, and record the deployed hook hashes. A symlink from the hook path to a user-writable directory gives that user the same authority.

The configuration source also matters. A hook path can be supplied through repository configuration, global configuration, an environment-controlled configuration file, or a command-line override. The first step in a review is to identify which one wins for the job. git config --show-origin --get-all core.hooksPath shows the value and its source. Do not assume the repository's local config is authoritative.

Make CI explicit

For a build that does not intend to run repository hooks, disable them in the command:

git -c core.hooksPath=/dev/null commit -m "release"

For a build that requires centrally managed hooks, pin the path and protect it:

git -c core.hooksPath=/opt/company/git-hooks commit -m "release"

The second example is not a security proof. The hooks directory must be owned by a privileged deployment account, not writable by the build user or the checked-out repository. Its files should be hashed and deployed through the same reviewed path as other build tooling.

Also review the commands in the workflow. Client-side hooks can be bypassed by some Git options, while server-side hooks are part of the receiving service. A local commit hook is not a substitute for a required server-side branch protection check.

Inspect a repository without executing hooks

Before running a Git command in an untrusted checkout, inspect the configuration and the visible hook files:

git config --show-origin --get-all core.hooksPath
git --no-optional-locks status --short
find "$(git rev-parse --git-dir)/hooks" -maxdepth 1 -type f -perm -u+x

The inspection commands can themselves run aliases or external helpers in unusual configurations. Use a trusted Git configuration context and clear environment overrides when the repository is untrusted. Do not run git commit, git push, or a build script until the hook path and configuration sources are known.

Recovery after a hook change

If a hook or hook path is suspected of being compromised, preserve the configuration source, hook files, file hashes, and parent-directory permissions. Rotate credentials reachable by the account that ran the hook. Review build artifacts and deployment receipts created during the exposure window. Removing the hook file without rotating the credentials leaves the access path unaddressed.

core.hooksPath is useful because it lets an organization manage hook code centrally. It deserves the same review as any other executable loaded by a build. The repository checkout is not the only code that runs.

References