This section describes which versions of gitlab_ci_cli receive security updates.
| Version | Supported | Status |
|---|---|---|
| main | ✅ | Active development branch |
| 1.x | ✅ | Current stable release |
| < 1.0 | ❌ | Pre-release, not supported |
Version Support Timeline:
- Current stable version (1.x): Receives all security updates and patches
- Development branch (main): Latest features and security fixes
- Pre-release versions: No security support provided
We recommend always using the latest stable release for production use.
We take security vulnerabilities seriously. If you discover a security issue in gitlab_ci_cli, please report it responsibly.
DO NOT open a public issue for security vulnerabilities.
Instead, please report security issues through one of the following channels:
- Preferred: Email security concerns to the maintainer(s)
- Alternative: Open a draft security advisory on GitHub (if available)
- Private disclosure: Contact maintainers directly via secure channels
When reporting a vulnerability, please include:
- Description: Clear description of the vulnerability
- Impact: What could an attacker accomplish?
- Reproduction steps: Step-by-step instructions to reproduce the issue
- Affected versions: Which versions are vulnerable?
- Proof of concept: Example code/config demonstrating the issue (if applicable)
- Suggested fix: If you have recommendations for remediation
- Initial response: Within 72 hours of report
- Triage assessment: Within 1 week
- Fix development: Depends on severity (critical issues prioritized)
- Public disclosure: After fix is available, coordinated with reporter
We follow coordinated disclosure:
- You report the vulnerability privately
- We confirm the issue and develop a fix
- We release a security update
- We publicly disclose the vulnerability (typically 7-14 days after fix release)
- Credit is given to the reporter (unless anonymity is requested)
We appreciate security researchers who follow responsible disclosure practices.
The IncludeProcessor validates remote URLs to prevent Server-Side Request Forgery (SSRF) attacks by blocking private IP addresses. However, this protection has a known limitation:
Limitation: DNS rebinding attacks are possible. A hostname may initially resolve to a public IP address (passing validation), but subsequently resolve to a private IP when the actual HTTP request is made.
Root cause: Ruby's Net::HTTP library does not provide hooks to validate resolved IP addresses at connection time. The validation happens before DNS resolution occurs for the HTTP request.
Impact: An attacker controlling DNS could potentially bypass SSRF protection to access internal services.
Mitigation options:
- Set
GITLAB_CI_ALLOWED_DOMAINSenvironment variable to restrict remote includes to a trusted allowlist - Use local includes (
local:) instead of remote includes when possible - Review and audit all remote include URLs in CI configurations
- Deploy network-level protections (firewall rules, network segmentation)
Future work: We are investigating alternative HTTP clients or DNS resolution strategies that would allow validation at connection time.
The IncludeProcessor can fetch GitLab CI templates from the filesystem when gitlab_templates_path is configured. This provides access to the GitLab template library but also means:
- Template path must be carefully controlled
- Path traversal is mitigated by using
File.joinwith absolute base paths - Only configured template directory is accessible
Remote includes enforce HTTPS-only connections:
include:
- remote: 'https://example.com/ci-template.yml' # OK
- remote: 'http://example.com/ci-template.yml' # RejectedWhy: Prevents man-in-the-middle attacks and ensures integrity of included configurations.
Set GITLAB_CI_ALLOWED_DOMAINS to limit remote includes:
export GITLAB_CI_ALLOWED_DOMAINS="gitlab.com,trusted-domain.example.com"
gitlab_ci_cli lint --entry .gitlab-ci.ymlWhy: Reduces attack surface by limiting which external sources can be included.
Use local: includes over remote: when possible:
include:
- local: 'templates/security-scanning.yml' # PreferredWhy: Eliminates network-based attacks and ensures templates are version-controlled.
Audit all included YAML files, especially from external sources:
- Check for unexpected script commands
- Validate variable usage
- Review artifact collection patterns
- Verify image sources
Why: Included files execute with the same permissions as your main CI configuration.
Store runner configuration files securely:
chmod 600 runners/*.jsonWhy: Runner configurations may contain sensitive metadata about your infrastructure.
Use gitlab_ci_cli lint in pre-commit hooks:
# .git/hooks/pre-commit
#!/bin/bash
gitlab_ci_cli lint --entry .gitlab-ci.ymlWhy: Catches configuration errors and potential security issues early.
Protection: ChildPipelineHandler uses Open3.capture2e with direct argument passing.
Implementation:
# Secure: Arguments passed directly, no shell interpretation
output, status = Open3.capture2e(*args)What this prevents:
- Command injection via crafted job names or variables
- Shell metacharacter exploitation
- Arbitrary command execution
Example attack prevented:
# Malicious CI config attempting injection
variables:
MALICIOUS: "; rm -rf / #"
# Our implementation safely passes this as a literal string, not executedProtection: IncludeProcessor blocks remote includes to private IP addresses.
Blocked IP ranges:
- Loopback:
127.0.0.0/8 - Private Class A:
10.0.0.0/8 - Private Class B:
172.16.0.0/12 - Private Class C:
192.168.0.0/16 - Link-local:
169.254.0.0/16 - Multicast:
224.0.0.0/4 - Broadcast:
255.255.255.255 - Unspecified:
0.0.0.0
Implementation:
def validate_not_private_ip(hostname)
ip = Resolv.getaddress(hostname)
raise "Private IP detected" if ip.start_with?('127.', '10.', '192.168.')
# ... additional checks
endWhat this prevents:
- Access to internal services (databases, admin panels, metadata APIs)
- Port scanning of internal network
- Reading local files via file:// protocol (blocked by HTTPS-only requirement)
Known limitation: See "DNS Rebinding Vulnerability" above.
Protection: Remote includes require HTTPS protocol.
Implementation:
unless uri.scheme == 'https'
raise "Remote includes must use HTTPS for security"
endWhat this prevents:
- Man-in-the-middle attacks
- Configuration tampering in transit
- Credential exposure
Protection: Validates CLI arguments, YAML structure, and runner configurations.
Validation points:
- YAML parsing with safe_load and restricted classes
- File path validation (existence checks, no path traversal)
- URL validation (scheme, host, format)
- Circular include detection
- Include depth limiting (max 150 levels)
What this prevents:
- YAML deserialization attacks
- Path traversal attacks
- Infinite recursion / resource exhaustion
- Circular dependency deadlocks
Protection: Network requests have timeouts to prevent resource exhaustion.
Implementation:
Net::HTTP.start(
uri.host, uri.port,
use_ssl: true,
read_timeout: 5, # 5 second read timeout
open_timeout: 3, # 3 second connection timeout
verify_mode: OpenSSL::SSL::VERIFY_PEER
)What this prevents:
- Slowloris-style attacks
- Resource exhaustion from hanging connections
- Denial of service via slow responses
Protection: SSL certificates are verified for all HTTPS connections.
Implementation:
verify_mode: OpenSSL::SSL::VERIFY_PEERWhat this prevents:
- Man-in-the-middle attacks
- Impersonation attacks
- Credential interception
Protection: Maximum include depth of 150 levels (matches GitLab's limit).
Implementation:
MAX_DEPTH = 150
raise IncludeDepthExceededError if depth > MAX_DEPTHWhat this prevents:
- Stack overflow from infinite recursion
- Resource exhaustion
- Denial of service attacks
Protection: Tracks processed includes to prevent circular references.
Implementation:
@processed_includes = Set.new
raise "Circular include detected" if @processed_includes.include?(identifier)What this prevents:
- Infinite loops
- Resource exhaustion
- Denial of service
- Malicious included configurations: SSRF protection and HTTPS enforcement reduce risk of fetching malicious configs
- Command injection: Direct argument passing prevents shell injection
- Resource exhaustion: Timeouts, depth limits, and circular detection prevent DoS
- Path traversal: Input validation prevents access to arbitrary files
- Compromised remote includes: HTTPS enforcement and SSL verification protect integrity
- DNS attacks: Domain allowlist reduces attack surface (though DNS rebinding remains possible)
- Template tampering: Local templates are version-controlled and auditable
-
Malicious CI scripts: This tool simulates pipeline execution but does not sandbox or restrict script commands. If a CI configuration contains malicious scripts, this tool will show what would be executed but provides no runtime protection.
-
Host system compromise: If the system running
gitlab_ci_cliis compromised, all protections can be bypassed. -
Credential exposure in configs: This tool does not scan for or redact secrets in YAML files. Users must manage secrets appropriately.
-
GitLab submodule vulnerabilities: The tool uses GitLab source code as a submodule. Vulnerabilities in GitLab itself may affect this tool.
-
Ruby interpreter vulnerabilities: Security depends on the Ruby interpreter and standard library.
-
DNS rebinding attacks: See "Known Limitations" above.
-
Time-of-check-time-of-use (TOCTOU): File system checks are not atomic. Files could change between validation and use.
-
Social engineering: No technical control prevents users from manually adding malicious configurations.
This tool operates within the following trust boundaries:
┌─────────────────────────────────────────────────────────┐
│ Trusted Zone │
│ │
│ ┌──────────────┐ ┌─────────────┐ │
│ │ User Input │────────▶│ gitlab_ci │ │
│ │ (.gitlab-ci) │ │ _cli │ │
│ └──────────────┘ └─────────────┘ │
│ │ │
│ ┌──────────────┐ │ │
│ │ Runners/ │◀───────────────┘ │
│ │ (local JSON)│ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
│
│ HTTPS + SSRF Protection
▼
┌─────────────────────────────────────────────────────────┐
│ Untrusted Zone │
│ │
│ • Remote include sources (external URLs) │
│ • DNS resolvers │
│ • Network infrastructure │
│ │
└─────────────────────────────────────────────────────────┘
Trusted: Local filesystem, user-provided configurations, runner definitions Untrusted: Remote URLs, network responses, DNS results
This project minimizes dependencies to reduce attack surface:
Core dependencies:
- Ruby standard library (YAML, Net::HTTP, Open3, Resolv)
- Minimal external gems (see Gemfile)
Security practices:
- Dependencies are managed via Bundler with Gemfile.lock
- Nix shell provides reproducible environment
- Regular dependency updates (monitor for CVEs)
The project includes GitLab as a git submodule for CI/CD logic reuse.
Security considerations:
- Submodule pinned to specific version (not floating)
- Zero-patch policy: No modifications to GitLab code
- Upstream security updates tracked
- Version compatibility tested
Updating submodule:
just update-gitlab # Updates to latest stable versionWhen security vulnerabilities are discovered:
- Assessment: Evaluate severity and impact
- Fix development: Develop and test patch
- Release preparation: Prepare security advisory
- Coordinated disclosure: Notify affected users
- Public release: Release fix with security advisory
- Postmortem: Document lessons learned
If you're contributing to this project:
- Fail-fast validation: Validate input early and loudly
- Avoid shell commands: Use Ruby APIs directly (no system calls with user input)
- Validate file paths: Use
File.expand_pathand check for path traversal - Limit network access: Validate URLs and implement timeouts
- Log security events: Log authentication failures, blocked requests, validation errors
- Test edge cases: Include security test cases for injection, traversal, SSRF
- Document security implications: Note security trade-offs in code comments
- OWASP Top 10
- GitLab Security Best Practices
- Ruby Security Guide
- CONTRIBUTING.md - Development guidelines
- README.md - Project documentation
For security-related questions or concerns that are not vulnerabilities:
- Open a discussion on GitHub
- Review existing security issues
- Consult project documentation
For security vulnerabilities, follow the "Reporting a Vulnerability" process above.
Last Updated: 2025-10-14 Version: 1.0