AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Build Yaml Misconfiguration

skill-redhatproductsecurity-prodsec-skills-build-yaml-misconfiguration · by RedHatProductSecurity

>

No reviews yet
0 installs
7 views
0.0% view→install

Install

$ agentstack add skill-redhatproductsecurity-prodsec-skills-build-yaml-misconfiguration

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-redhatproductsecurity-prodsec-skills-build-yaml-misconfiguration)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Build Yaml Misconfiguration? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Build YAML Misconfiguration

Detect and prevent security misconfigurations in GitLab CI and Tekton pipeline definitions. Misconfigured build YAML is a common source of secret leakage, privilege escalation, and supply chain compromise.

GitLab CI (.gitlab-ci.yml)

Secret Exposure

  • Never hardcode secrets in .gitlab-ci.yml, variables:, or script: blocks. Use CI/CD protected variables or an external vault.
  • Mask and protect variables: set masked: true and protected: true on sensitive CI/CD variables. Masked variables are redacted from job logs.
  • Never echo secrets: avoid echo $SECRET, printenv, env, or set -x in scripts that handle credentials. Debug output is stored in job logs.
  • Restrict variable scope: use protected: true to limit variables to protected branches/tags only. Use environment scoping to restrict which jobs see which secrets.
  • Artifacts and caches: never include files containing secrets (.env, credentials, tokens) in artifacts: or cache: paths. These are stored and downloadable.
# BAD -- secret visible in logs and available on all branches
variables:
  DB_PASSWORD: "hunter2"

# GOOD -- use CI/CD protected variable (set in GitLab UI)
# Reference as $DB_PASSWORD in scripts; set masked + protected in settings

Runner and Execution Isolation

  • Never use shared runners for secret-heavy jobs without understanding the trust boundary. Prefer project-specific or group runners for sensitive pipelines.
  • Never use privileged: true in runner config unless absolutely required (e.g., container builds). Privileged runners can escape to the host.
  • Use docker or kubernetes executor over shell executor. Shell executors share the host filesystem and can leak state between jobs.
  • Tag sensitive jobs to run only on hardened, dedicated runners.
# BAD -- no runner restriction, runs on any available shared runner
deploy-production:
  script:
    - ./deploy.sh

# GOOD -- pinned to a dedicated runner
deploy-production:
  tags:
    - production-deploy
    - privileged-denied
  script:
    - ./deploy.sh

Pipeline Permissions and Trust

  • Protected branches: ensure deploy and release jobs use only: refs: [main] or rules: with branch restrictions. Never allow feature branches to trigger production deploys.
  • Merge request pipelines: use rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' to prevent MR pipelines from accessing protected variables.
  • allow_failure: true: never set this on security scanning jobs (SAST, SCA, secret detection). Failures in security gates must block the pipeline.
  • when: manual: use for production deploys to enforce human approval. Never auto-deploy to production from CI.
# BAD -- security scan can fail silently
sast:
  allow_failure: true
  script:
    - run-sast-scanner

# GOOD -- security scan blocks pipeline on failure
sast:
  allow_failure: false
  script:
    - run-sast-scanner
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

Container Image Builds in CI

  • Never use docker:dind with --privileged without understanding the risk. Prefer Kaniko, Buildah, or Podman for unprivileged image builds.
  • Pin base images by digest, not just tag. Tags are mutable.
  • Do not mount the Docker socket (/var/run/docker.sock) in CI jobs.
  • Scan built images before pushing to registry.
# BAD -- privileged DinD with mutable tag
build-image:
  image: docker:latest
  services:
    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2375
  script:
    - docker build -t myapp .

# GOOD -- unprivileged build with pinned image
build-image:
  image: quay.io/buildah/stable@sha256:
  script:
    - buildah bud --layers -t myapp .
    - buildah push myapp $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Include and Extends Risks

  • Audit remote includes: include: remote: pulls YAML from external URLs. If the remote changes, your pipeline changes. Pin to a specific ref or commit.
  • Audit cross-project includes: include: project: pulls from other GitLab projects. Ensure the source project has proper access controls.
  • Review inherited configuration: extends: and include: can override variables:, script:, and rules: in unexpected ways. Verify the final merged configuration.
# RISKY -- remote include with no version pinning
include:
  - remote: 'https://example.com/ci-templates/build.yml'

# BETTER -- pinned project include
include:
  - project: 'my-group/ci-templates'
    ref: 'v2.1.0'
    file: '/templates/build.yml'

Tekton Pipelines

Secret Exposure

  • Never inline secrets in Task or Pipeline YAML. Use Kubernetes Secrets referenced via secretKeyRef in env: or mounted as volumes.
  • Never log secrets in steps: avoid echo, printenv, cat on mounted secret files in script: blocks. Tekton step logs are stored and accessible.
  • Workspace binding: when binding secrets as workspaces, ensure the workspace is not shared with untrusted tasks in the same pipeline.
  • Results: never write secrets to Tekton results. Results are stored in the TaskRun/PipelineRun status and visible to anyone with read access.
# BAD -- secret hardcoded in task
steps:
  - name: deploy
    image: registry.redhat.io/ubi9/ubi-minimal
    script: |
      curl -H "Authorization: Bearer my-secret-token" https://api.example.com

# GOOD -- secret from Kubernetes Secret
steps:
  - name: deploy
    image: registry.redhat.io/ubi9/ubi-minimal
    env:
      - name: API_TOKEN
        valueFrom:
          secretKeyRef:
            name: deploy-creds
            key: token
    script: |
      curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com

Step Image Security

  • Pin images by digest: never use :latest or mutable tags for step images. A compromised tag can inject malicious code into your pipeline.
  • Use trusted registries: prefer registry.redhat.io or your internal registry. Avoid pulling from untrusted public registries in production pipelines.
  • Minimal images: use UBI minimal or distroless images. Avoid full OS images with unnecessary tools that expand the attack surface.
# BAD -- mutable tag from public registry
steps:
  - name: build
    image: ubuntu:latest

# GOOD -- pinned digest from trusted registry
steps:
  - name: build
    image: registry.redhat.io/ubi9/ubi-minimal@sha256:

Task and Pipeline Permissions

  • Run steps as non-root: set securityContext.runAsNonRoot: true and runAsUser on steps. Never run build steps as root unless absolutely required.
  • Drop capabilities: set securityContext.capabilities.drop: ["ALL"] on step containers.
  • Do not use privileged: true in step security contexts.
  • Service account scoping: bind the minimum RBAC to the service account running the PipelineRun. Never use the pipeline service account with cluster-admin privileges.
  • Limit workspace access: use readOnly: true on workspace bindings when the task only needs to read.
# BAD -- running as root with no restrictions
steps:
  - name: build
    image: registry.redhat.io/ubi9/ubi-minimal
    script: |
      make build

# GOOD -- non-root with dropped capabilities
steps:
  - name: build
    image: registry.redhat.io/ubi9/ubi-minimal
    securityContext:
      runAsNonRoot: true
      runAsUser: 1001
      capabilities:
        drop: ["ALL"]
    script: |
      make build

Pipeline Structure Risks

  • Untrusted task references: taskRef with resolver: bundles or resolver: git can pull tasks from external sources. Pin to specific digests or commits.
  • Parameter injection: if pipeline parameters are passed into script: blocks via $(params.*), treat them as untrusted input. Validate and quote them.
  • When expressions: do not use when expressions as security controls. They skip tasks but do not enforce authorization.
  • Finally tasks: use finally: tasks for cleanup (removing credentials, revoking tokens) but never assume they will always run (node failure, timeout).
# BAD -- unpinned external task bundle
taskRef:
  resolver: bundles
  params:
    - name: bundle
      value: quay.io/someone/my-task:latest

# GOOD -- pinned by digest
taskRef:
  resolver: bundles
  params:
    - name: bundle
      value: quay.io/myorg/my-task@sha256:

Tekton Chains and Provenance

  • Enable Tekton Chains for automatic signing and attestation of TaskRun/PipelineRun results.
  • Verify signatures on built artifacts before promotion to production registries.
  • Store attestations alongside artifacts for auditability.

Containerfile / Dockerfile Hardening

Container image definitions are typically referenced or inlined in CI YAML. Misconfigurations here produce insecure images that run in production.

Run as Non-Root

  • Never leave USER unset -- the default is root. Always add a USER directive before the final CMD/ENTRYPOINT.
  • Create a dedicated user in the build stage.
# BAD -- runs as root by default
FROM registry.redhat.io/ubi9/ubi-minimal
COPY app /app
CMD ["/app/server"]

# GOOD -- explicit non-root user
FROM registry.redhat.io/ubi9/ubi-minimal
RUN microdnf install -y shadow-utils && \
    useradd -r -u 1001 appuser && \
    microdnf clean all
COPY --chown=appuser:appuser app /app
USER appuser
CMD ["/app/server"]

Secrets in Image Layers

  • Never COPY or ADD secrets (keys, credentials, .env files) into the image. Every layer is extractable.
  • Never use ARG or ENV for secrets -- they are visible in docker inspect and image history.
  • Use BuildKit secret mounts for build-time secrets. They are not persisted in layers.
# BAD -- secret baked into image layer
COPY .env /app/.env
ENV API_KEY=sk-secret-value

# GOOD -- BuildKit secret mount (not persisted in layer)
RUN --mount=type=secret,id=api_key \
    export API_KEY=$(cat /run/secrets/api_key) && \
    ./configure --with-key="$API_KEY"

Base Image Hygiene

  • Pin base images by digest, not mutable tags. :latest or :9 can change without notice.
  • Use trusted registries: prefer registry.redhat.io or your internal registry.
  • Use minimal base images: UBI minimal, micro, or distroless. Fewer packages = smaller attack surface.
  • Remove package managers from the final image when possible.
# BAD -- mutable tag, full OS image
FROM ubuntu:latest

# GOOD -- pinned digest, minimal trusted image
FROM registry.redhat.io/ubi9/ubi-minimal@sha256:

Multi-Stage Builds

  • Separate build and runtime stages. Build tools, compilers, and test dependencies must not ship in the final image.
  • Copy only the built artifact into the runtime stage.
# GOOD -- multi-stage: build tools stay in builder stage
FROM registry.redhat.io/ubi9/ubi:latest AS builder
RUN dnf install -y gcc make && dnf clean all
COPY . /src
RUN cd /src && make

FROM registry.redhat.io/ubi9/ubi-minimal@sha256:
COPY --from=builder /src/bin/app /app/server
USER 1001
CMD ["/app/server"]

Build Context Leakage

  • Always use .dockerignore (or .containerignore). Without it, the entire directory (including .git, .env, credentials, IDE configs) is sent to the build daemon.
  • Explicitly exclude sensitive paths.
# .dockerignore
.git
.env
*.pem
*.key
credentials/
node_modules/

Unnecessary Capabilities and Ports

  • Do not EXPOSE ports you don't use. While EXPOSE is documentation only, it signals intent and misconfigured orchestrators may open them.
  • Do not install sudo, su, or setuid binaries in the final image.
  • Set HEALTHCHECK so orchestrators can detect unhealthy containers.
# GOOD -- only expose what's needed, add healthcheck
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/healthz || exit 1

Read-Only and Immutability

  • Design images to run with a read-only root filesystem at runtime. Write only to explicitly mounted volumes or tmpfs.
  • Avoid writing to the container filesystem in CMD/ENTRYPOINT scripts.

Common Containerfile Misconfigurations

| Misconfiguration | Risk | Fix | |-----------------|------|-----| | No USER directive | Container runs as root | Add USER before CMD | | COPY .env or COPY *.key | Secrets baked into extractable layers | Use BuildKit --mount=type=secret | | ENV SECRET_KEY=value | Secret visible in docker inspect | Pass at runtime via orchestrator | | FROM image:latest | Mutable tag; supply chain risk | Pin by @sha256: | | No .dockerignore | .git, credentials sent to build context | Create .dockerignore with exclusions | | Single-stage with build tools | Compilers, test deps ship to production | Use multi-stage builds | | RUN chmod 777 | World-writable files in image | Use specific permissions (chmod 755) | | No HEALTHCHECK | Orchestrator cannot detect unhealthy state | Add HEALTHCHECK instruction | | sudo or setuid binaries installed | Privilege escalation path | Remove from final image |


Common Misconfigurations (Both Platforms)

| Misconfiguration | Risk | Fix | |-----------------|------|-----| | Hardcoded secrets in YAML | Credential leakage via repo access or logs | Use vault/CI variables/K8s Secrets | | allow_failure: true on security jobs | Security findings silently ignored | Set allow_failure: false | | Mutable image tags (:latest) | Supply chain compromise via tag poisoning | Pin by digest | | Privileged containers/runners | Container escape to host | Use unprivileged builds (Buildah/Kaniko) | | Unscoped variables/secrets | Secrets available to untrusted branches/jobs | Scope to protected branches/environments | | Debug output (set -x, printenv) | Secrets printed to job logs | Remove debug flags; use masked variables | | Unpinned remote includes/task refs | External changes alter your pipeline | Pin to version/commit/digest | | Missing security scan gates | Vulnerable code reaches production | Add SAST/SCA/image scanning as blocking steps | | Auto-deploy to production | No human review before deploy | Require manual approval gate | | Shell executor (GitLab) | Job-to-job state leakage on shared host | Use Docker/Kubernetes executor | | No USER in Containerfile | Container runs as root in production | Add non-root USER directive | | Secrets in image layers | Credentials extractable from image | Use BuildKit secret mounts | | No .dockerignore | Sensitive files leak into build context | Create .dockerignore with exclusions | | Single-stage build | Build tools ship to production | Use multi-stage builds |

Implementation Checklist

  • [ ] No secrets hardcoded in pipeline YAML; all credentials from vault or protected variables
  • [ ] Sensitive variables masked and scoped to protected branches/environments
  • [ ] Security scan jobs set to block pipeline on failure
  • [ ] All step/job images pinned by digest from trusted registries
  • [ ] Containers run as non-root with dropped capabilities; no privileged mode
  • [ ] Remote includes and task references pinned to specific versions/digests
  • [ ] Production deploys require manual approval
  • [ ] No debug output (set -x, printenv, env) in jobs that handle secrets
  • [ ] Pipeline parameters validated before use in scripts
  • [ ] Tekton Chains enabled for provenance and signing (where applicable)
  • [ ] Containerfiles set explicit non-root USER before CMD
  • [ ] No secrets in image layers, ARG, or ENV; use BuildKit secret mounts
  • [ ] .dockerignore / .containerignore excludes .git, .env, keys, credentials
  • [ ] Multi-stage builds separate build tools from runtime image
  • [ ] Base images from trusted registries, pinned by digest

Test Plan

  • Audit all .gitlab-ci.yml and Tekton Task/Pipeline YAML for patterns in the

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.