Prefect is a modern Python-native workflow orchestration platform (successor to Luigi/Airflow patterns) used extensively in data engineering and MLOps pipelines. Its security surface includes: Prefect Server's REST API and UI on port 4200 requires no authentication on default self-hosted deployments — any network client can enumerate all deployments, trigger flow runs, inject parameters, and read all flow execution history including output artifacts; flow run parameters containing database connection strings, API keys, and other secrets are stored in the Prefect database as part of the run record and accessible via the API without additional access controls; Prefect workers executing flows inherit the full environment of the worker process, including cloud provider credentials in environment variables; work pool deployments allow users to override Docker image tags and Kubernetes Job specifications, potentially executing untrusted images; and Prefect Cloud API keys (used to connect self-hosted workers to Prefect Cloud) are frequently stored in .env files and CI/CD secrets that may be leaked. This guide covers systematic Prefect security assessment.
# Prefect Server default: port 4200 (both REST API and UI)
# Prefect Cloud: api.prefect.cloud (requires API key)
# Check Prefect Server API (no auth required on default deployments)
curl -s http://prefect.example.com:4200/api/health 2>/dev/null | \
python3 -c "import json,sys; d=json.load(sys.stdin); print('Prefect Server:', d)" 2>/dev/null
# List all deployments (no auth required)
curl -s -X POST http://prefect.example.com:4200/api/deployments/filter \
-H "Content-Type: application/json" \
-d '{}' 2>/dev/null | \
python3 -c "
import json,sys
data = json.load(sys.stdin)
print(f'Deployments: {len(data)}')
for d in data[:10]:
print(f\" {d.get('name','?')} flow={d.get('flow_id','?')}\")
" 2>/dev/null
# List recent flow runs including their parameters (no auth)
curl -s -X POST http://prefect.example.com:4200/api/flow_runs/filter \
-H "Content-Type: application/json" \
-d '{"limit":5,"sort":"START_TIME_DESC"}' 2>/dev/null | \
python3 -c "
import json,sys
runs = json.load(sys.stdin)
for r in runs[:5]:
params = r.get('parameters', {})
print(f\"Run: {r.get('name','?')} params_keys={list(params.keys())}\")
for k,v in params.items():
print(f\" {k}: {str(v)[:80]}\")
" 2>/dev/null
| Security Test | Method | Risk |
|---|---|---|
| Prefect Server API unauthenticated access | POST /api/deployments/filter — list all deployments without credentials | High |
| Flow run parameters contain plaintext secrets | GET /api/flow_runs/{id} — read run parameters including API keys passed as flow inputs | High |
| Trigger arbitrary flow run via API injection | POST /api/deployments/{id}/create_flow_run — execute any registered deployment without auth | High |
| Worker inherits cloud credentials from environment | Deploy flow that prints os.environ — AWS_ACCESS_KEY_ID, GCP credentials visible in flow output | High |
| PREFECT_API_KEY in repository or CI/CD secrets | Search GitHub/GitLab for PREFECT_API_KEY — worker API keys grant full workspace access | High |
| Work pool Docker image override | Override job.image in flow run creation to execute untrusted container image via worker | Medium |
Ironimo tests Prefect deployments for unauthenticated Prefect Server API access on port 4200 allowing deployment enumeration and arbitrary flow run triggering, flow run parameter exposure containing plaintext secrets and credentials, worker process environment variable leakage via flow output logging, work pool infrastructure override injection executing untrusted container images, Prefect Cloud API key exposure in repository secrets or .env files, and Prefect Server accessible without authentication proxy from unauthorized network ranges.
Start free scan