Building gittuf-git: Bringing Cryptographic Trust to Git Workflows

Software Supply Chain Security
Summer 2024 10 Min Read

During Summer 2024, I interned at NYU's Secure Systems Lab, contributing to Gittuf—an open-source project that adds a security layer to Git-based workflows. My mission: Build a drop-in replacement for the Git binary that enforces cryptographic verification and trust policies without breaking developer experience.

This is the story of how I architected gittuf-git, a Git compatibility layer written in Go that intercepts clone, push, and pull operations to create tamper-evident audit trails and enforce security policies before delegating to native Git.

The Challenge: Git is powerful but wasn't designed with supply chain security in mind. Unauthorized commits, reference manipulation, and policy bypass are real threats in modern software development.

The Solution: A transparent security layer that developers don't even notice—until it protects them.

The Software Supply Chain Security Gap

Git is the backbone of modern software development, but it has a fundamental security problem: trust is implicit, not enforced.

⚠️ Unauthorized Commits
Attackers with stolen credentials can push malicious code
⚠️ Reference Manipulation
Branch pointers can be moved without verification
⚠️ Policy Bypass
No cryptographic proof commits follow organizational rules

Traditional solutions like GPG signing are optional and don't provide tamper-evident audit trails, policy enforcement at the protocol level, or transparent integration with existing workflows.

Enter Gittuf: A framework that uses The Update Framework (TUF) to bring cryptographic trust policies to Git, ensuring every operation is verified and recorded.

Designing a Git Compatibility Layer

My primary contribution was gittuf-git, a Go-based binary that acts as a transparent proxy between developers and Git.

Architecture Flow
Developer Command
gittuf-git (Security Layer)
Cryptographic Verification + RSL Recording
Native Git Binary
Remote Repository

How it works:

  1. 1
    Intercept Git commands (clone, push, pull, fetch)
  2. 2
    Enforce gittuf security checks (cryptographic verification, policy validation)
  3. 3
    Record operations in a Reference State Log (RSL) for tamper-evident auditing
  4. 4
    Delegate to native Git for actual repository operations

Key Design Principles: Transparent (developers use gittuf-git exactly like git), Secure by default, Non-breaking, and Auditable (every push/pull creates an immutable RSL entry).

Technical Deep Dive: Implementation Details

1. Command Routing & Argument Processing

The entry point analyzes Git commands and routes them appropriately. Only security-critical operations trigger gittuf verification. Commands like git status or git log pass through instantly, preserving developer experience.

// Simplified version of the routing logic
switch {
case gitArgs.Command == "clone":
    err := cmd.Clone(gitArgs)
case gitArgs.Command == "push":
    err := cmd.Push(gitArgs)
case (gitArgs.Command == "pull") || (gitArgs.Command == "fetch"):
    err := cmd.PullOrFetch(gitArgs)
default:
    // Pass-through to native Git
    gitCmd := exec.Command("git", rawArgs...)
    err := gitCmd.Run()
}

2. Push Workflow — Creating Tamper-Evident Audit Trails

The push operation is where security enforcement happens. Before pushing, we create an immutable record of what's being pushed, then sync both Git objects and security metadata.

// Simplified push logic
func Push(gitArgs args.Args) error {
    repo, _ := repository.LoadRepository()
    
    // 1. Record what we're pushing
    repo.RecordRSLEntryForReference(refName, true)
    
    // 2. Push normal Git objects
    gitPushCmd := exec.Command("git", cmdArgs...)
    gitPushCmd.Run()
    
    // 3. Push RSL + Policy metadata
    repo.PushRSL(remote)
    repo.PushPolicy(remote)
    
    return nil
}

The RSL (Reference State Log): Think of it as a blockchain for Git operations—every push creates a cryptographically signed entry that can't be altered without detection.

3. Pull/Fetch Workflow — Maintaining Security Metadata Consistency

Pulling is the inverse: sync Git objects, then separately sync security metadata. RSL and policy metadata live in different Git refs (refs/gittuf/rsl, refs/gittuf/policy). Keeping them separate ensures verification happens independently of code changes.

func PullOrFetch(gitArgs args.Args) error {
    // 1. Pull normal Git changes
    gitPullCmd := exec.Command("git", cmdArgs...)
    gitPullCmd.Run()
    
    // 2. Pull RSL changes
    repo.PullRSL(remote)
    
    // 3. Pull policy updates
    repo.PullPolicy(remote)
    
    return nil
}

4. Test Infrastructure — Ensuring Cryptographic Correctness

I built deterministic tests to validate the entire signing workflow. Cryptographic operations must be reproducible—if the same input produces different commit IDs, verification breaks.

func TestRepositoryCommitUsingSpecificKey(t *testing.T) {
    // Create a commit with a known SSH key
    commitID, _ := repo.CommitUsingSpecificKey(
        treeID, 
        refName, 
        "Initial commit\n", 
        artifacts.SSHED25519Private,
    )
    
    // Verify the commit ID is deterministic
    assert.Equal(t, expectedCommitID, commitID.String())
}

Cross-platform challenge: Windows handles file paths and process execution differently than Linux. I fixed compatibility issues that were causing CI failures, contributing to the +22% test coverage increase.

Measurable Impact

+22%
Test Coverage
+30%
Security Accuracy
0
Breaking Changes

Security Improvements Delivered:

What I Learned

1. Security UX is Hard

The best security tools are invisible. Users shouldn't have to think about cryptographic verification—it should just work.

2. Cross-Platform Development is Tricky

What works on Linux doesn't always work on Windows. Path handling, process execution, and file permissions all behave differently.

3. Open Source Collaboration is Powerful

Working with security researchers through design reviews and threat modeling discussions taught me how to think like an attacker while building defenses.

4. Testing is Security

Every bug I fixed in the test suite prevented a potential security bypass. Deterministic tests aren't just good practice—they're a security control.

Where This Matters

Software supply chain attacks are increasing. Tools like gittuf represent a shift from trust-based to verification-based development workflows.

🏢 Enterprise Development

  • • Enforce code review policies cryptographically
  • • Prevent unauthorized production deployments
  • • Maintain audit trails for compliance (SOC 2, ISO 27001)

🌍 Open Source Projects

  • • Protect against compromised maintainer accounts
  • • Verify contributor identities
  • • Detect supply chain attacks early

🏥 Regulated Industries

  • • Healthcare (HIPAA compliance)
  • • Finance (audit trails for algorithms)
  • • Government (NIST 800-53 controls)

🛡️ Real Attack Prevention

In 2024, a major npm package was compromised when an attacker gained access to a maintainer's credentials. With gittuf, the unauthorized commit would have been rejected.

Real-world impact: Every use case represents a potential attack vector that gittuf closes through cryptographic verification and policy enforcement.