The repo never left the server.
A staging deploy of the Byte Lotus guest platform shipped with its
.git directory sitting in the public webroot. That one
oversight was enough to walk the commit history straight back to a
flag someone meant to delete before launch — and never did.
A basic nmap sweep showed two open ports — 8080 (the guest platform's
staging build) and 22 (SSH). A gobuster pass against 8080 turned up
something that shouldn't ever answer on a production or staging host:
/.git/HEAD resolving with a 200.
$ curl -s http://10.64.154.218:8080/.git/HEAD ref: refs/heads/main
A live HEAD file means the entire .git
directory is very likely being served the same way — objects, refs,
logs, all of it. That's the whole history of the repository,
recoverable with nothing more than an HTTP client.
Rather than hand-crafting requests for every object, loose object,
and pack file, git-dumper reconstructs the repo by
walking .git/ the same way a real git client would.
$ git-dumper http://10.64.154.218:8080/.git/ ./byte-lotus-repo [-] Testing http://10.64.154.218:8080/.git/HEAD [200] [-] Fetching .git recursively [-] Fetching http://10.64.154.218:8080/.git/objects/pack/ [200] [-] Fetching http://10.64.154.218:8080/.git/refs/heads/main [200] [-] Running git checkout . Updated 3 paths from the index
Checkout produced exactly three files — app.js,
index.html, and README.md — all from a
single commit on main.
A keyword grep across the full history (key,
secret, token, password,
aws_) came back empty. That ruled out the "amend and
force-push over a leaked credential" pattern — the reflog confirmed
it too, showing a single initial commit and nothing dangling or
rewritten:
$ cat .git/logs/HEAD 0000000...0000000 0f13550 night-shift <dev@byte-lotus.internal> commit (initial): initial Byte Lotus guest platform
A keyword grep only catches what it's told to look for. Reading the
actual diff — rather than trusting a filtered search — is what found it,
sitting in plain sight in README.md:
diff --git a/README.md b/README.md new file mode 100644 index 0000000..a5965c5 --- /dev/null +++ b/README.md +# Byte Lotus — Guest Experience Platform + +Internal staging repository for the guest app and concierge personalization +service. Do not deploy this folder to production. + +Staging flag (remove before launch): THM{byt3_l0tus_n3v3r_f0rg3ts}
app.js also references a stubbed
/api/guest endpoint, and the README mentions a separate
"profiling service." Neither is wired up in this repo — worth
flagging for a later stage, but not part of this finding.
The label on the line is the whole story: "remove before launch." It wasn't. A staging build shipped with its version control metadata intact, and that alone was enough to hand over the complete commit history — no credentials, no misconfigured IAM role, just a directory that should never have been reachable over HTTP.
Never deploy a .git directory into a served webroot —
exclude it at the build/deploy step, not just via
.gitignore (which does nothing to stop it being served
once it exists on disk). Add a web-server rule denying access to
dotfiles/dot-directories as defense in depth. And treat "remove
before launch" comments as a signal to actually purge the commit
(via history rewrite) rather than trusting that no one will look —
anything ever committed should be treated as permanently public.