-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Is your feature request related to a problem? Please describe.
When a CI job's script:, before_script:, or after_script: block contains patterns like curl ... | bash or wget ... | sh, the pipeline downloads and executes code from the internet without any integrity verification. This is a well-documented supply chain attack vector:
- Script tampering: An attacker who compromises the remote URL (via DNS hijacking, CDN compromise, or maintainer account takeover) can serve a modified script that exfiltrates CI/CD secrets (
$CI_JOB_TOKEN, deploy keys, custom variables) - Server-side detection: The remote server can detect that
curlis piping tobash(vs. downloading to a file) and serve different content rendering manual verification useless - Silent exfiltration: The malicious payload can inspect environment variables for patterns like
AWS_,SECRET_,TOKEN,API_KEYand exfiltrate them via a POST request, while the legitimate tool still installs correctly
This risk compounds in CI/CD because pipelines run repeatedly, often with elevated privileges, and the same poisoned URL serves malware to every pipeline execution across the organization.
Describe the solution you'd like
Add a new control pipelineMustNotExecuteUnverifiedScripts that:
- Scans
script:,before_script:, andafter_script:blocks across all jobs (including globalbefore_script/after_script) - Detects patterns where downloaded content is piped directly to a shell interpreter or executed immediately after download
- Reports the job name, the offending line, and the detected pattern
Patterns to detect
# Direct pipe to shell
curl ... | bash
curl ... | sh
wget ... | bash
wget ... | sh
curl ... | sudo bash
curl ... | sudo sh
# Download-and-execute (single script block)
curl -o script.sh ... && bash script.sh
wget -O script.sh ... && sh script.sh
curl ... > install.sh; sh install.sh
# Python/other interpreters
curl ... | python
curl ... | python3
wget ... | perl
Configuration in .plumber.yaml
controls:
pipelineMustNotExecuteUnverifiedScripts:
enabled: true
# Severity: "error" or "warning"
severity: warning
# URLs that are trusted and should not trigger findings
# (e.g., internal artifact server with integrity checks)
trustedUrls: []
# - https://internal-artifacts.example.com/*Implementation Hints
These are just ideas. Feel free to change the implementation.
- Data source: The
PipelineOriginDatacollector already provides the merged CI configuration viaMergedConf(GitlabCIConf). TheGitlabJobstruct exposesScript,BeforeScript, andAfterScriptasinterface{}fields. The global-levelBeforeScriptandAfterScriptare onGitlabCIConfitself. UseParseJobVariables()and iterate overGitlabJobsto access each job's script blocks. - New control file: Create
control/controlGitlabPipelineUnverifiedScripts.go. - New collector (optional): A new
collector/dataCollectionGitlabPipelineScript.gomay be useful if script parsing logic is reused across multiple controls (this control + the injection control). Alternatively, the logic can live entirely in the control. - Logic:
- For each job, normalize the script blocks into a flat list of command strings
- Apply regex patterns to detect
curl|bash,wget|sh, and download-then-execute variants - For each match, check if the URL matches any
trustedUrlspattern - If not trusted, create an issue with the job name, the matched line, and the pattern type
- Regex approach: Use a set of compiled regexes. Key patterns:
(curl|wget)\s+[^|]*\|\s*(sudo\s+)?(bash|sh|zsh|python[23]?|perl|ruby)(curl|wget)\s+.*(-o|-O)\s+\S+.*&&\s*(bash|sh|source)\s+(curl|wget)\s+.*>\s*\S+\.sh\s*[;&]\s*(bash|sh|source)\s+
- Compliance: 0% if any unverified script execution is found, 100% otherwise.
Files Touched
control/controlGitlabPipelineUnverifiedScripts.go(new control)control/types.go(addUnverifiedScriptsResultfield toAnalysisResult)control/task.go(wire the new control inRunAnalysis())configuration/plumberconfig.go(add config struct and getter).plumber.yaml(add default config section)cmd/analyze.go(add output formatting)
Why It's Valuable
The curl | bash pattern is one of the most widespread and dangerous anti-patterns in CI/CD pipelines. Real-world incidents like the Codecov breach (2021) demonstrated how a compromised installation script can silently exfiltrate secrets from thousands of CI/CD pipelines for months. Unlike container image controls (which Plumber already covers), script execution controls address the second major supply chain vector: runtime code injection via untrusted downloads.