CI/CD provider
Secret leak in pipeline configuration
Control: Pipeline must not leak secrets in configuration· Config key: pipelineMustNotLeakSecretsInConfig
📋 What is this?
The resolved pipeline configuration contains a pattern that matches a hardcoded secret (API token, private key, password, or other credential) embedded directly in the YAML. Plumber resolved the full merged .gitlab-ci.yml (with every include: followed) and piped the result through gitleaks; any high-confidence match against the rule catalog surfaced as an ISSUE-301 finding. The detected value never left the scanner: each finding's preview carried a redacted form with the first and last four characters visible and the middle replaced with asterisks.
⚠️ Impact
Secrets committed to pipeline configuration are exposed to everyone with read access to the repository, appear in version history forever (rotation is the only fix, not deletion), and are forwarded to every runner that executes the pipeline. A leaked API key can enable unauthorised access to cloud services, data exfiltration, billing abuse, or lateral movement into production systems.
🔧 How to fix
Revoke and rotate the exposed secret immediately. Remove it from the YAML, then inject it securely as a masked, protected CI/CD variable (Settings > CI/CD > Variables) and reference it as $MY_SECRET in the pipeline. For production workloads, prefer an external secrets manager (HashiCorp Vault, AWS Secrets Manager, Doppler) over GitLab-managed variables.
# .gitlab-ci.yml: ❌ Hardcoded secrets (CRITICAL)deploy: stage: deploy script: - export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE - export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - aws s3 sync . s3://my-bucket
api-call: variables: API_TOKEN: "ghp_exampleTokenHardcodedHere123" script: - curl -H "Authorization: token $API_TOKEN" https://api.example.com# .gitlab-ci.yml: ✅ Secrets injected via CI/CD variablesdeploy: stage: deploy script: # AWS credentials injected from protected CI/CD variables - aws s3 sync . s3://my-bucket
api-call: script: - curl -H "Authorization: token $API_TOKEN" https://api.example.com
# In GitLab: Settings > CI/CD > Variables# Add: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, API_TOKEN# Set Protected: true, Masked: true for each💡 Tips
- If a secret was ever committed, treat it as compromised and rotate it immediately; deletion does not remove it from history.
- Pair with pre-commit hooks (
gitleaks protect --staged) so the next leak is caught before it lands in git.
⚙️ Configuration
This control is configured in .plumber.yaml under the gitlab section:
gitlab:
controls:
pipelineMustNotLeakSecretsInConfig:
enabled: trueSee the CLI documentation for the full configuration reference.
Secret leak in pipeline configuration
Control: Workflow must not leak secrets in configuration· Config key: pipelineMustNotLeakSecretsInConfig
📋 What is this?
A file under .github/workflows/ contains a pattern that matches a hardcoded secret (API token, private key, password, or other credential) embedded directly in the YAML. Plumber piped every workflow file through gitleaks; any high-confidence match against the rule catalog surfaced as an ISSUE-301 finding. The detected value never left the scanner: each finding's preview carried a redacted form with the first and last four characters visible and the middle replaced with asterisks.
⚠️ Impact
Secrets committed to workflow files are exposed to every collaborator, every fork, and the entire commit history. Public repositories make the leak instantly indexable by attacker tooling; private repositories still expose it to every member of the org and every workflow that runs against the repo. Rotation is the only fix.
🔧 How to fix
Revoke and rotate the exposed secret immediately. Remove the literal from the workflow YAML, then inject it via repository or environment secrets and reference it as ${{ secrets.MY_SECRET }}. Scope the reference to the smallest step that needs it; avoid passing it through job-level env: if a single step suffices.
# .github/workflows/release.yml: ❌ Hardcoded token (CRITICAL)jobs: publish: runs-on: ubuntu-latest env: SLACK_WEBHOOK: xoxb-EXAMPLE-EXAMPLE-redactedfortestingonly STRIPE_KEY: "sk_test_REDACTED_DOC_EXAMPLE_NOT_A_REAL_KEY" steps: - run: ./scripts/publish.sh# .github/workflows/release.yml: ✅ Repository / environment secretsjobs: publish: runs-on: ubuntu-latest steps: - env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} STRIPE_KEY: ${{ secrets.STRIPE_KEY }} run: ./scripts/publish.sh
# In GitHub: Settings > Secrets and variables > Actions# Add: SLACK_WEBHOOK, STRIPE_KEY (repository or environment-scoped)💡 Tips
- Pair with pre-commit hooks (
gitleaks protect --staged) and GitHub's push-protection rules so the next leak is caught before it lands on a branch.
⚙️ Configuration
This control is configured in .plumber.yaml under the github section:
github:
controls:
pipelineMustNotLeakSecretsInConfig:
enabled: trueSee the CLI documentation for the full configuration reference.