MY GIT picoCTF 2026 Solution

Published: March 20, 2026

Description

I have built my own Git server with my own rules! You want the flag - make sure to push the flag. Only flag.txt pushed by root (name: root, email: root@picoctf) will be updated with the flag.

Launch the challenge instance and clone the repository using the provided command.

Note the password shown on the challenge page.

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Clone the repository
    Observation
    I noticed the challenge provided an HTTP Git URL and a password on the instance page, which indicated a remote repository was waiting to be cloned as the necessary first step before any commit manipulation could occur.
    Clone the repository using the command provided on the challenge page. Note the password.
    bash
    git clone http://<HOST>:<PORT_FROM_INSTANCE>/repo.git
    bash
    cd repo
    What didn't work first

    Tried: Browsing to the repo URL in a browser to look for files or the flag directly

    The HTTP Git server only speaks the Git smart-HTTP protocol, not a file browser. The browser gets a dumb index page with no useful content. The flag is only revealed after you push a specially-crafted commit, so direct HTTP browsing will never expose it.

    Tried: Cloning with SSH instead of the provided HTTP URL

    The challenge instance does not expose an SSH port - only the HTTP port shown on the challenge page is open. An SSH clone attempt will time out or be refused. Use the exact URL format provided.

    Learn more

    This challenge has a server-side Git hook that runs when you push commits. The hook checks the committer name and email - it only updates flag.txt if the push comes from a commit with name root and email root@picoctf. Git allows you to set any name and email locally, so you can impersonate this identity.

  2. Step 2
    Configure git identity as root
    Observation
    I noticed the challenge description explicitly stated that only flag.txt pushed by a committer with name 'root' and email 'root@picoctf' would trigger the flag, which suggested spoofing the local git identity before creating the commit.
    Set your local git user name to 'root' and email to 'root@picoctf'. These values appear in commit metadata and the server hook checks them.
    bash
    git config user.name root
    bash
    git config user.email root@picoctf
    What didn't work first

    Tried: Setting the global git config (git config --global user.name root) instead of the local repo config

    The global flag writes to ~/.gitconfig and affects all repositories on your system, but it works for this challenge as long as you do it before committing. The risk is that you accidentally leave a polluted global identity after the CTF. Using the local form (no --global flag) inside the cloned repo is safer and more precise.

    Tried: Setting the GIT_AUTHOR_NAME/GIT_AUTHOR_EMAIL environment variables instead of the committer fields

    Git distinguishes author (who wrote the change) from committer (who recorded it). The server hook checks the committer identity embedded in the commit object, not the author identity. If you only set author env vars, the committer still defaults to your real git config and the hook rejects the push.

    Learn more

    Git commit metadata (author name and email) is entirely client-controlled. There is no authentication binding a git identity to an actual user. This is why signed commits (GPG or SSH signing) exist - to provide cryptographic proof that a commit came from a specific key, not just a self-reported name.

    The challenge illustrates a real security risk: if a server grants permissions based on the committer name/email in the commit object, any client can impersonate any identity by simply changing their local git config.

  3. Step 3
    Create flag.txt, commit, and push
    Observation
    I noticed the server hook was specifically watching for a push of flag.txt from the root identity, which meant creating that file and pushing it would trigger the hook to respond with the real flag in the push output.
    Create a flag.txt file, stage it, commit with the root identity, and push. The server hook will detect the commit came from 'root' and update flag.txt with the flag.
    bash
    touch flag.txt
    bash
    git add flag.txt
    bash
    git commit -m 'add flag'
    bash
    git push
    bash
    # Enter the password from the challenge page when prompted

    Expected output

    picoCTF{1mp3rs0n4t10n_g1t_...}
    What didn't work first

    Tried: Committing flag.txt with actual flag content (e.g. the placeholder picoCTF{...}) hoping the hook will accept it

    The hook does not validate what is inside flag.txt - it only checks that the committer identity is root/root@picoctf and then overwrites flag.txt with the real flag on the server side. Putting any content in flag.txt before committing makes no difference to the outcome; the flag comes back in the push response, not from what you wrote.

    Tried: Forgetting to enter the password and pressing Enter at the prompt, then trying to read flag.txt from the local clone

    An empty password causes authentication failure and the push is rejected before the hook runs. Even if the push succeeds, the flag is delivered in the push output from the server hook - it does not automatically appear in your local clone until you run git pull after the push.

    Learn more

    The server-side Git hook (typically a post-receive or update hook) runs after you push. It inspects the committer identity in the pushed commits. Since we configured our local git to use name "root" and email "root@picoctf", the hook recognizes this as the privileged identity and replaces flag.txt with the actual flag content, which the hook then echoes back in the push output.

Flag

Reveal flag

picoCTF{1mp3rs0n4t10n_g1t_...}

Configure git user.name=root and user.email=root@picoctf, create flag.txt, commit, and push. The server hook grants the flag to commits from 'root'.

Key takeaway

Git commit metadata such as author name and email is entirely self-reported by the client and has no cryptographic binding to any real identity; any developer can set git config user.name and user.email to any value before committing. Access control systems that trust these fields are trivially bypassed by impersonation, exactly as a server trusting a caller's claimed username in an HTTP header would be. The correct countermeasure is to authenticate at the transport layer (SSH keys or personal access tokens) and use signed commits (GPG or SSH commit signing) when you need non-repudiable proof of authorship.

How to prevent this

Git commit identity is completely client-controlled. Never grant permissions based on committer name or email.

  • Use signed commits (GPG or SSH signing) if you need to verify who made a commit. The signature is cryptographically tied to a private key the committer controls, unlike the name/email which anyone can set to anything.
  • Authenticate at the transport layer (SSH keys, HTTPS tokens) rather than inside commit metadata. The connection identity is harder to fake than the metadata inside the commit object.

Related reading

Want more picoCTF 2026 writeups?

Useful tools for General Skills

What to try next