Safeguard
Security Guides•

Should a front-end build and deploy run in separate CI jobs?

Yes. Build in a job with no deploy credentials, then deploy in a second job with environment secrets and a required reviewer, away from build tools.

Safeguard Security Team
4 min read

Yes. Run the build, including the bundler, plugins and tests, in one job that holds no deploy credentials. Pass the finished output as an artifact to a second job that holds the deploy secret, ideally behind an environment with a required reviewer. Build tools then never see the key.

The problem with one big job

A single job that installs, builds, tests and deploys gives every step the same environment. Your bundler, its plugins and every transitive dependency run next to the cloud key. A malicious update to any of them can read it. See is your bundler plugin trusted code for why those tools count as trusted code.

GitHub's security guidance for Actions says that any user with write access to a repository has read access to all secrets configured in it, and that credentials used in workflows should have the least privilege required. It also notes that a secret is redacted from logs only when it is accessible to the runner and exactly matches, so redaction is not a safety net.

What GitHub gives you to split

  • Job level permissions. The GITHUB_TOKEN guidance says an action can access the token through the github.token context even if the workflow does not pass it, so you should limit the permissions granted. Set permissions at the job level.
  • Environments. GitHub says you can use required reviewers to protect environment secrets, and a job cannot access environment secrets until a reviewer approves.
  • Separate jobs. Each job runs in its own runner, so a secret given to the deploy job is not in the build job's environment.

A two job pattern

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: site
          path: dist

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment: production
    permissions:
      contents: read
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: site
      - run: ./deploy.sh
        env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}

The deploy script receives only static files. It does not run npm and does not install anything. Pin third party actions to commit SHAs, as in should you pin GitHub Actions to a commit SHA.

Table of who gets what

StepSecretsToken permissions
Install and buildNoneRead contents
Unit and browser testsOnly test fixturesRead contents
DeployEnvironment secret behind approvalOnly what the deploy needs

Extra hardening

  1. Prefer short lived credentials from OIDC over stored keys. See GitHub Actions OIDC to replace long lived cloud secrets.
  2. Put no network credentials in the build job .npmrc beyond a read only registry token.
  3. Verify the artifact before deploy. Even a hash check between jobs shows corruption in transit, though it cannot tell you the build was clean.
  4. Consider a manual approval for production, so a human looks at the commit and the build result before secrets are released.
  5. Restrict who can edit workflow files, since a workflow change can send secrets somewhere else.

What this does not stop

The build job can still produce a bad artifact if a dependency is malicious. Splitting keeps secrets safe but does not make the output clean. Pair it with lockfile review, dependency scanning and a diff of the output between releases.

Safeguard's policies and gates can check dependency changes before they reach the build, and its compliance and evidence automation can record that approval step. You can run a free scan at gold.safeguard.sh/scan.

Quick check

Do separate jobs share secrets by default?

No. A secret reaches a job only through its configuration, so give the deploy secret to the deploy job alone.

What does a required reviewer on an environment do?

Per GitHub, a job cannot access that environment's secrets until a reviewer approves.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.