← Back to Writeups
CUSTOMEasyWeb

Lab 209 — BuildForge — Path Traversal in Static File Serving

XESXOR9/10/20262 min read
#web#custom#easy#curl_path_as_is#path_traversal_prefix_bypass#string_concatenation_bypass#linux

Lab 209 — BuildForge — Path Traversal in Static File Serving

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-04-27 | Status: Solved Techniques: curl_path_as_is, path_traversal_prefix_bypass, string_concatenation_bypass

Summary

Task: CI/CD dashboard with custom static file serving at /static/{filepath}. Solution: path traversal via ../data/.env bypasses prefix check due to string concatenation without normalization.

Lab 209 — BuildForge — Path Traversal in Static File Serving — Hackadvisor

Description

BuildForge is a CI/CD management dashboard built by ForgeStack Labs. The application uses a custom static file serving layer for its frontend assets. The goal was to find and read a sensitive configuration file that should not be publicly accessible.

Target: https://b43a7a70-5af1-41a7-a308-aa616e8f4851.labs.hackadvisor.io/ Credentials: user@test.com / password123

Analysis

Reconnaissance

  1. Static file endpoint discovered: Files served at /static/{filepath} (e.g., /static/css/app.css, /static/js/app.js) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  2. Directory structure from JS comments:

    • /static maps to /app/public on the filesystem
    • Configuration files located at /app/data
  3. Technology stack: Node.js/Express behind nginx/1.25.5

  4. robots.txt revealed /data/ directory exists

  5. Honeypot detection: Decoy flags embedded in HTML to fool automated scanners:

    FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}
    

Vulnerability Analysis

The static file serving middleware has a path traversal vulnerability due to improper path validation. The security check uses string concatenation without normalizing ../ sequences before the prefix check: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerable logic:

javascript
// Pseudocode of the vulnerable check
const fullPath = '/app/public/' + userInput;
if (fullPath.startsWith('/app/public/')) {
    // Serve the file
    serveFile(fullPath);
}

The bypass:

  • Input: ../data/.env
  • Check: Does /app/public/../data/.env start with /app/public/? → YES (passes)
  • Filesystem resolution: /app/public/../data/.env → /app/data/.env (traversal succeeds)

The prefix check passes because the string comparison happens BEFORE the filesystem normalizes the path. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Use curl with --path-as-is flag to prevent client-side path normalization:

bash
curl -s --path-as-is "https://b43a7a70-5af1-41a7-a308-aa616e8f4851.labs.hackadvisor.io/static/../data/.env"

Why --path-as-is is critical:

  • Without this flag, curl normalizes /static/../data/.env to /data/.env before sending
  • The server would then reject the request or return 404
  • With --path-as-is, the literal path /static/../data/.env is sent to the server

Response

The .env file contained sensitive configuration: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

SECRET_TOKEN=FLAG{REDACTED}
DATABASE_URL=postgres://...
AWS_ACCESS_KEY_ID=...
API_SECRET=...

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍