Skip to content

trapdoorsec/flynn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

flynn

note: this is a work in progress, I am currently in the process of validating this project to weed out false negatives and positives. Please wait until version 1.0.0 before using this in a build pipeline

  • Find indicators of weaponized git repositories
  • Able to be plugged into a CI/CD pipeline
  • Or run as a command line tool.
  • SARIF output supported
  • Risk scoring: INFO, MEDIUM, HIGH, CRITICAL

Installation

Requires Rust 2024 edition (1.85+).

git clone https://github.com/trapdoorsec/flynn.git
cd flynn
cargo build --release

The release binary is at target/release/flynn. Move it to somewhere on your $PATH and then call it.

Usage

# scan a repository
flynn /path/to/repo

# filter findings by minimum severity
flynn -m high /path/to/repo

# fail with exit code 2 if any critical findings (useful in CI)
flynn --fail-on critical /path/to/repo

# JSON output
flynn -f json -o findings.json /path/to/repo

# SARIF output (for GitHub Code Scanning / CI integrations)
flynn -f sarif -o findings.sarif /path/to/repo

# suppress console output (only write report file)
flynn -q -f json -o results.json /path/to/repo

Options

Flag Description Default
-f, --format <FORMAT> Output format: text, json, sarif text
-m, --min-severity <LEVEL> Minimum severity to report: info, medium, high, critical info
--fail-on <LEVEL> Exit code 2 if any finding meets this severity (none)
-o, --output <FILE> Report file path flynn_output.txt
-q, --quiet Suppress console output false

Exit codes

Code Meaning
0 Scan completed, no findings at --fail-on threshold
2 Findings met or exceeded --fail-on threshold

Todo

  • weed out false postitives and negatives
  • integration testing with GH actions
  • examples for use in GH automations
  • move documentation content into a wiki and provide URLs for further finding analysis

checks

config-based command execution

  • core.fsmonitor — shell command exec on git status, git add, git commit etc
  • core.fsmonitorv2 — newer protocol variant, same primitive
  • core.sshCommand — exec on any remote op over SSH
  • core.gitProxy — exec when connecting via git protocol
  • core.editor — exec on git commit, git rebase -i
  • sequence.editor — exec specifically on git rebase -i
  • diff.external — exec on git diff
  • diff.tool / difftool..cmd — exec on git difftool
  • merge.tool / mergetool..cmd — exec on git mergetool
  • credential.helper — exec on any auth operation
  • pager. — exec when output is paged (git log, git diff, etc)
  • filter..clean — exec on git add for matching files
  • filter..smudge — exec on git checkout for matching files
  • filter..process — long-running filter process variant
  • gpg.program — exec on signed commits/tags
  • gpg.ssh.program — SSH signing variant
  • gpg.x509.program — x509 signing variant
  • receive.procReceive — server-side hook on push
  • uploadpack.packObjectsHook — exec during git fetch/git clone from this repo
  • transfer.fsckObjects — combined with crafted objects
  • core.pager — global pager override, exec on any paged output
  • web.browser — exec when git tries to open a browser
  • sendemail.smtpserver — exec via git send-email
  • include.path — load external config, chains into any of the above
  • includeIf.*.path — conditional external config load (gitdir, onbranch, hasconfig variants)

hook abuse

  • Executable files in .git/hooks/ with canonical names — pre-commit, post-commit, pre-push, post-checkout, post-merge, post-rewrite, prepare-commit-msg, commit-msg, pre-rebase, pre-auto-gc, post-update, pre-receive, update, proc-receive, push-to-checkout, fsmonitor-watchman, p4-pre-submit, p4-prepare-changelist, p4-changelist, p4-post-changelist
  • Non-.sample hooks present at all (clean repos only have .sample files)
  • World-writable hook files — privilege escalation if another user runs git
  • Hooks with unusual shebangs (#!/usr/bin/env python3, #!/usr/bin/env node, #!/usr/bin/perl — not inherently malicious but worth flagging)
  • Hooks that are symlinks pointing outside the repo
  • core.hooksPath redirecting to attacker-controlled directory
  • Hooks present in a custom core.hooksPath location

structural anomalies

  • Buried bare repo — directory containing HEAD + objects/ + refs/ with no .git parent (OVE-20210718-0001)
  • core.bare = false combined with core.worktree — the jailbreak pattern that makes a buried bare repo functional
  • .git as a file rather than directory, containing gitdir: — redirects git dir to attacker-controlled location
  • gitdir: path in .git file pointing outside the repo or to an absolute path
  • core.worktree pointing outside the repo root
  • core.hooksPath pointing to an absolute path or path outside the repo
  • Symlinks within .git/ pointing outside the repo
  • .git/ directory that is itself a symlink
  • Unexpected subdirectories inside .git/ that aren't part of standard git layout
  • .git/config containing multiple [core] sections — can be used to confuse parsers

object store anomalies

  • Oversized loose objects — blobs above a configurable threshold (e.g. >1MB) in .git/objects/
  • Binary blobs in the object store not referenced by any tree
  • Orphaned objects not reachable from any ref — potential payload staging
  • Crafted .git/index file — Driver Tom's arbitrary write primitive, abused by git pillagers
  • Unusually large .git/index
  • Objects with path-traversal-like names embedded in trees (CVE-2014-9390 class — null bytes, .., mixed case .Git on case-insensitive FS)
  • Pack files (.git/objects/pack/*.pack) that are unusually large
  • .git/objects/info/alternates — redirects object lookups to external path, enables object injection
  • .git/objects/info/http-alternates — same but fetched over HTTP at runtime

refs and HEAD anomalies

  • HEAD pointing to a non-existent ref
  • HEAD containing a raw SHA instead of a symbolic ref — valid but unusual, flag it
  • Refs with path-traversal characters in their names
  • Refs in .git/refs/ pointing to non-existent objects
  • packed-refs containing refs with unusual or suspicious names
  • FETCH_HEAD, MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD present unexpectedly — indicates interrupted operations, may indicate a state manipulation attempt
  • ORIG_HEAD pointing to unexpected commit
  • Ref names containing null bytes, newlines, or other control characters

gitattributes abuse

  • .gitattributes or .git/info/attributes assigning filter= to files — triggers filter..smudge/clean on checkout/add
  • diff= attribute assignments — triggers diff..textconv or diff.external
  • merge= attribute assignments — triggers merge..driver
  • Attributes targeting high-value filenames — Makefile, *.sh, *.py, *.rs, *.go, build.gradle, CMakeLists.txt
  • Attributes with eol= combined with filter hooks
  • export-subst attribute — substitutes variables into file content on archive, lower severity but unusual
  • ident attribute — lower severity, substitutes $Id$ into files

worktree and alternates

  • .git/worktrees/ entries present at all — flag for review
  • .git/worktrees//gitdir pointing outside expected path
  • .git/worktrees//commondir pointing to unexpected location
  • Multiple worktrees registered pointing to sensitive filesystem locations

submodule abuse

  • .gitmodules present with url = pointing to a file:// path — local filesystem access
  • .gitmodules with update = !command — arbitrary command exec on git submodule update
  • Submodule url using unusual schemes (ext::, fd::)
  • Submodule paths with .. components — path traversal
  • .git/modules/ containing nested repos with their own malicious configs — each one recurse-check

info and metadata

  • .git/info/sparse-checkout with unusual glob patterns
  • .git/info/exclude — lower severity, attacker hiding their own tracks
  • .git/description modified from default — low severity, indicates tampering, useful fingerprint
  • .git/config with unexpected [user] section — attacker identity leak or impersonation setup
  • Unexpected [remote] entries pointing to unusual URLs or local paths
  • [remote] pushurl differing from url — silent redirect of pushes
  • Remote URLs using ext:: protocol — arbitrary command exec on remote operations
  • Remote URLs using fd:: protocol
  • Remote URLs pointing to file:// paths outside the expected location

encoding and evasion

  • Config keys with unusual whitespace or tab indentation tricks
  • Unicode homoglyphs in config key names — attempting to visually spoof a safe key
  • Null bytes in config values
  • Extremely long config values — potential buffer handling edge cases in tooling
  • Config values with shell metacharacters in ostensibly non-exec fields
  • Binary content in .git/config — shouldn't be there at all

Testing

A test fixture generator builds a fully weaponized .git directory covering every check category. The fixture is not committed — it's generated on the fly.

# generate the fixture
./test/setup_fixture.sh

# run flynn against it
cargo run -- test/fixtures/malicious_repo

# with json output
cargo run -- -f json -o findings.json test/fixtures/malicious_repo

# clean up
rm -rf test/fixtures/malicious_repo

The fixture includes: malicious config keys (fsmonitor, sshCommand, etc.), all 20 canonical hooks as executables, world-writable and symlinked hooks, unusual shebangs, a buried bare repo with the core.bare/core.worktree jailbreak, a gitdir redirect file, oversized loose objects and pack files, a crafted index, alternates pointing to external paths, a detached HEAD with raw SHA, path-traversal ref names, gitattributes with filter/diff/merge drivers, worktree entries pointing to sensitive paths, submodules with file:///ext::/fd:: URLs and update = !command, tampered metadata and suspicious remotes, and encoding evasion tricks (Cyrillic homoglyphs, null bytes, 100k-char values, binary content in config).

See test/setup_fixture.sh for the full breakdown.

Output formats

  • text to console (always unless --quiet)
  • text to file
  • json to file
  • sarif to file

About

Find indicators of weaponized git repositories in your pipeline

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors