Master

Security in the pipeline

Pipelines can leak secrets or ship vulnerable code. Learn to add security checks and protect credentials.

What you will see

Pin actions to full commit SHA: uses: actions/checkout@8ade135a415781e0c821dbd9152f81a039643307 Token scope: read-only Compromised workflow can push: No Compromised workflow can delete: No

About 1 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

A pipeline can leak secrets or ship vulnerable code, so security is layered into it. Secrets are injected from a vault and never appear in a log, actions are pinned to exact commit SHAs so they cannot drift, and scanners block the build on findings.

1

I scan a workflow source for a leaked secret and print that the build is clean, then print that real secrets come from a vault rather than the code.

print("Security in the pipeline") print("Store real passwords: encrypted in secret vault") print("Scan source: gitleaks detect -> clean") code_with_secret = 'API_KEY = "sk-live-1234567890"' secrets_scanned = ["sk-live-1234567890", "AKIAABCDEFGHIJKLMNOP"] found = [s for s in secrets_scanned if s in code_with_secret] print("Secret leaked in code: %s" % ("Yes" if found else "No"))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Security in the pipeline Store real passwords: encrypted in secret vault Scan source: gitleaks detect -> clean Secret leaked in code: Yes
A leaked secret is worse than a bug, so scanners run on every push. Any key that ever appears in a log must be rotated at once, regardless of how old it looks.
2

I pin an action to a full commit SHA so it cannot drift when a new release is published, and print that a read-only token cannot push or delete even if the workflow is compromised.

print("Pin actions to full commit SHA:") print("uses: actions/checkout@8ade135a415781e0c821dbd9152f81a039643307") print("Token scope: read-only") print("Compromised workflow can push: No") print("Compromised workflow can delete: No")

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Pin actions to full commit SHA: uses: actions/checkout@8ade135a415781e0c821dbd9152f81a039643307 Token scope: read-only Compromised workflow can push: No Compromised workflow can delete: No
A version tag can move when a maintainer publishes a new release. A full SHA freezes exactly the code that runs, which is the strongest defense against a supply-chain surprise.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Add security scans and protect secrets so the pipeline itself is safe.
1 Store secrets safely
↓
2 Scan for vulnerabilities
↓
3 Scan for leaks
↓
4 Block on findings
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

print("Security in the pipeline") Security in the pipeline
print("Store real passwords: encrypted in secret vault") Store real passwords: encrypted in secret vault
print("Scan source: gitleaks detect -> clean") Scan source: gitleaks detect -> clean
code_with_secret = 'API_KEY = "sk-live-1234567890"' sets nothing on screen
secrets_scanned = ["sk-live-1234567890", "AKIAABCDEFGHIJKLMNOP"] sets nothing on screen
found = [s for s in secrets_scanned if s in code_with_secret] sets nothing on screen
print("Secret leaked in code: %s" % ("Yes" if found else "No")) Secret leaked in code: Yes
Why this works
Secrets management

Store secrets in a secret manager, not in code. Inject them at runtime. Rotate them often.

Automated scans

Add a scanner for vulnerabilities and secrets. Run it on every push so bad code never ships.

Examples

Protecting secrets

- name: Scan secrets
  run: gitleaks detect --source .

Store real passwords as encrypted secrets in your repo settings. Never hardcode them in the workflow. A leaked secret is worse than a bug.

Read-only checkout

- uses: actions/checkout@v4
  with:
    fetch-depth: 0
    token: ${{ secrets.CI_READ_ONLY }}

Use a token with the least access the job needs. A read-only token means a compromised workflow cannot push or delete by accident. Principle of least privilege.

Pin actions to a commit

- uses: actions/checkout@8ade135...

Tagging an action by version tag can drift when the maintainer publishes a new release. Pinning to a full commit SHA freezes the exact code that runs. It is the strongest defense against a supply-chain surprise.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Parallel and matrix builds
Previous Lesson
Parallel and matrix builds
Next Lesson
Staging and environments
Staging and environments →