GitLab CI Inspector

Detect security issues in GitLab CI pipelines: exposed secrets, insecure images, dangerous allow_failure, and runner misconfigurations

Enter your .gitlab-ci.yml to scan for security vulnerabilities and misconfigurations

Detecting Security Issues in GitLab CI Pipelines

GitLab CI/CD pipelines defined in .gitlab-ci.yml automate build, test, and deployment workflows. Like any automation that executes code and handles secrets, misconfigured pipelines create security vulnerabilities — hardcoded secrets in scripts, Docker-in-Docker with privileged access, insecure base images, and shared runners executing sensitive deployment jobs. The GitLab CI Inspector scans your pipeline definitions to detect these security issues before they are exploited.

Paste your .gitlab-ci.yml content to receive security analysis covering secret exposure in scripts, image security, dangerous allow_failure configurations, Docker-in-Docker privilege escalation, artifact retention policies, and runner trust boundaries. Each finding includes severity classification and specific remediation guidance. All analysis happens entirely in your browser with zero data transmission.

Secret Exposure in Pipeline Scripts

The inspector detects secrets hardcoded or improperly handled in pipeline definitions:

  • Secrets in script blocks: API keys, tokens, or passwords appearing directly in script: commands
  • Echo of secret variables: echo $SECRET_TOKEN printing secrets to job logs visible to all project members
  • Secrets in variables section: Sensitive values defined in the YAML file rather than GitLab CI/CD settings (protected/masked)
  • Unmasked variables: Variables containing secrets that are not configured as masked in GitLab settings

Docker-in-Docker and Privilege Escalation

Container-based CI/CD introduces privilege escalation risks:

  • Docker-in-Docker (dind): Services using docker:dind require privileged mode, granting full host access to the container
  • Docker socket mounting: Mounting /var/run/docker.sock enables sibling container creation with arbitrary capabilities
  • Privileged runners: Jobs executing with --privileged flag have unrestricted kernel access
  • Untagged runners: Jobs without specific runner tags may execute on shared infrastructure alongside untrusted projects

Pipeline Configuration Safety

Structural pipeline issues that create indirect security risks:

  • allow_failure on security jobs: If SAST, DAST, or dependency scanning jobs are configured with allow_failure: true, security findings never block deployment
  • Missing artifact expiry: Build artifacts without expire_in accumulate indefinitely, potentially containing sensitive build outputs
  • Insecure base images: Using :latest tags or unverified images introduces supply chain risk — images can be replaced with malicious versions
  • Deployment on shared runners: Production deployment jobs should only run on protected, organization-controlled runners — not shared infrastructure

The inspector also checks for missing rules: or only: conditions on deployment stages. Without branch restrictions, merge requests from any contributor can trigger production deployments. Best practice requires that deploy jobs include rules: - if: $CI_COMMIT_BRANCH == "main" to restrict execution to protected branches only.

Remediation Guidance and Severity Levels

Each finding includes a severity classification and actionable remediation steps:

  • CRITICAL: Immediate action required — secrets in plaintext, privileged execution without justification
  • HIGH: Should be fixed before next deployment — Docker socket exposure, untagged runners for sensitive jobs
  • WARNING: Best practice violations — mutable image tags, missing artifact expiry, allow_failure on security scans
  • INFO: Optimization suggestions — consolidating stages, caching improvements, parallel job opportunities

The inspector maps each issue to GitLab documentation references and provides copy-paste YAML snippets for the corrected configuration. For secret exposure findings, it suggests the specific GitLab CI/CD variable type (file vs variable) and protection level (protected, masked) appropriate for each secret category.

Code Examples

GitLab CI with Security Issues

# .gitlab-ci.yml with issues detected
image: node:latest  # WARN: mutable tag

variables:
  API_KEY: "sk_live_abc123"  # CRITICAL: secret in YAML

stages:
  - build
  - test
  - deploy

build:
  stage: build
  script:
    - echo "Building with key $API_KEY"  # HIGH: echoing secret
    - npm run build

security_scan:
  stage: test
  allow_failure: true  # WARN: security scan can't block pipeline
  script:
    - npm audit

deploy:
  stage: deploy
  script:
    - curl -H "Authorization: $DEPLOY_TOKEN" https://deploy.example.com
  # WARN: no runner tag restriction — may run on shared runners

services:
  - docker:24-dind  # HIGH: requires privileged mode

Frequently Asked Questions

What security issues does the GitLab CI Inspector detect?

The inspector detects exposed secrets in scripts (hardcoded passwords, API keys, GitLab tokens, AWS keys), sensitive variables defined in plaintext, insecure image references (using :latest or unverified registries), dangerous allow_failure on security jobs, missing artifact expiry, use of Docker-in-Docker (privileged mode), and deployment jobs running on shared runners without specific tags.

How is the security score calculated?

The score starts at 100 and deducts points based on finding severity: Critical issues (exposed secrets) deduct 25 points, High issues (insecure images, unprotected variables, privileged services) deduct 15, Medium issues (dangerous allow_failure, shared runner on sensitive jobs) deduct 8, and Low issues (missing artifact expiry) deduct 3. Grades map to: A (90+), B (75+), C (60+), D (40+), F (below 40).

Why should I avoid using :latest tag in CI images?

The :latest tag is mutable — it can point to different image versions over time. This means your pipeline may break unexpectedly when the upstream image changes, or worse, a compromised image could be pushed as :latest. Pin images to specific versions (e.g., node:20.11.0-alpine) or SHA digests for reproducible and secure builds.

What is wrong with allow_failure on security jobs?

When allow_failure is true on security-related jobs (SAST, DAST, dependency scanning, secret detection), the pipeline passes even if vulnerabilities are found. This defeats the purpose of security gates and may allow vulnerable code to reach production. Remove allow_failure from security-critical jobs to enforce security policies.

Why are artifacts without expire_in flagged?

GitLab stores job artifacts indefinitely if no expire_in is specified (unless instance-level defaults override this). Over time, this consumes significant project storage and may retain sensitive build outputs longer than necessary. Setting expire_in (e.g., 1 week, 30 days) ensures artifacts are cleaned up automatically.

What is the risk of Docker-in-Docker (dind) in GitLab CI?

Docker-in-Docker requires the runner to operate in privileged mode, which grants the container near-full access to the host system. A malicious job or compromised dependency could exploit this to escape the container. Alternatives like kaniko or buildah can build images without privileged mode.

Why should deployment jobs use specific runner tags?

Shared runners are accessible to all projects on a GitLab instance. Running deployment jobs (which typically access production secrets) on shared runners means other projects' jobs execute on the same infrastructure. Specific runner tags ensure sensitive jobs run on dedicated, project-specific runners with appropriate isolation.

How should I handle secrets in GitLab CI pipelines?

Never hardcode secrets in .gitlab-ci.yml. Use GitLab CI/CD Variables (Settings → CI/CD → Variables) with the 'Protected' flag (only available on protected branches) and 'Masked' flag (hidden in logs). For external secrets, integrate with HashiCorp Vault or other secret managers via GitLab's native integration.

Does the inspector support included configurations?

The inspector analyzes the YAML content you paste directly. If your pipeline uses include: directives to pull in remote or local templates, paste the resolved/merged configuration for complete analysis. The inspector will detect issues in whatever content is provided.

Is my .gitlab-ci.yml file sent to any server?

No. All analysis happens entirely in your browser using JavaScript. Your GitLab CI configuration — which may contain sensitive information like variable names, infrastructure details, and deployment targets — never leaves your device. No data is stored, logged, or transmitted.