Skip to content

Git Daemon Service Detection

5 min read Created Apr 4, 2026 Last updated Apr 4, 2026

Git daemon serves repositories over the git:// protocol on port 9418. It is typically deployed for fast, unauthenticated read-only access to public repositories. Misconfigurations frequently expose internal repositories that should not be accessible. The service provides no authentication: any repository marked with a git-daemon-export-ok file is accessible to any connecting client. Detection is straightforward; the interesting work is in what the repositories contain.

Git daemon runs as a standalone process or under inetd or systemd socket activation. In either case it listens on TCP 9418 and accepts connections without any credential exchange. The git-daemon-export-ok flag is an empty file placed in the repository root by the admin. Its absence causes the daemon to reject the connection with an error. Administrators sometimes enable repositories globally via the --export-all flag, which removes even this weak gate. When you encounter this service on an internal network, treat every accessible repository as a data source.

  • Port Detection
  • Protocol Probe: Confirm Response
  • nmap Script Enumeration
  • Probe Common Repository Names

Port Detection

Nmap reports the service as git on port 9418. Any open result is worth following up: the daemon does not require further steps before you can interact with it directly.

┌──(kali㉿kali)-[~]
└─$ nmap -sV -p 9418 $TARGET_IP
9418/tcp open  git     Git

Protocol Probe: Confirm Response

The git protocol uses a pkt-line format. Send a minimal upload-pack request to confirm the daemon is responding and read the initial ref advertisement. If the repository name is wrong, you receive an error packet starting with ERR. A successful response begins with a packet length header, followed by a stream of ref lines. The strings filter strips the binary length prefixes and makes the refs readable. Swap the repo name until you get a valid response. Silence from the socket means the connection timed out or the request was denied at the daemon level.

┌──(kali㉿kali)-[~]
└─$ # Send a git-upload-pack request for a likely repo name and read the response
┌──(kali㉿kali)-[~]
└─$ printf '0039git-upload-pack /repo.git\0host=%s\0' $TARGET_IP | nc -w5 $TARGET_IP 9418 | strings | head -20
HEAD
refs/heads/main
refs/heads/develop
refs/tags/v1.0
refs/tags/v2.3

Ref names in the response confirm the repository exists and is accessible. Branch names and tags are immediately visible. Feature branches often contain work-in-progress code with more secrets than the main branch. Tag names with semantic version strings reveal the project's release cadence. A large number of tags suggests an active codebase with a longer history to mine. The HEAD ref points to the default branch. When it points to something other than main or master, the naming convention reveals the team's workflow. Note every branch name before moving on to cloning.

nmap Script Enumeration

The git-info NSE script attempts to enumerate repositories the daemon exposes and prints the refs it finds. It automates the pkt-line interaction and is useful for a quick, documented scan. The output lists accessible repository names along with their branches and tags. If the daemon runs with --export-all, the script may surface repositories that do not appear under obvious names. Combine it with -sV so version and script output appear in the same run.

┌──(kali㉿kali)-[~]
└─$ nmap -p 9418 $TARGET_IP --script git-info

Probe Common Repository Names

Git daemon does not list available repositories: you need to guess names. Test common repository names and check which ones respond with ref data. The loop above probes a short list of predictable names. Expand it based on context from other enumeration phases. Web application names found via HTTP enumeration, product names from banners, and company names all make good candidates. The .git suffix is optional; some configurations accept bare names. Test both forms if initial guesses fail. A successful refs/ match means the repository is accessible and ready to clone.

┌──(kali㉿kali)-[~]
└─$ for repo in repo webapp app website api backend frontend config infrastructure secrets; do
result=$(printf '003bgit-upload-pack /%s.git\0host=%s\0' $repo $TARGET_IP | nc -w2 $TARGET_IP 9418 2>/dev/null | strings | grep -c 'refs/')
[ $result -gt 0 ] && echo "FOUND: git://$TARGET_IP/$repo.git"
done
FOUND: git://10.10.10.50/repo.git
FOUND: git://10.10.10.50/config.git

A config repository is an immediate high-value target: it likely contains deployment configurations, credentials, and infrastructure details. Move to repository enumeration to explore the found repos before cloning. If none of the probe names return results, check whether the daemon uses a restricted base path. An IP-based access list is also common on internal deployments. Try connecting without specifying a repository name to see whether the connection is refused or times out. A refused TCP connection suggests firewall rules or binding to loopback only. A git-level ERR packet means the daemon is answering but denying access. Expand your wordlist before concluding the service is locked down.

References