GitHub Actions: From Zero to Production(EP8)🚀

GitHub Actions: From Zero to Production(EP8)🚀

Source: Dev.to

Episode 8 – Security, Permissions & the Fork PR Model ## Why Security Matters in CI/CD ## 1️⃣ What is GITHUB_TOKEN? ## 2️⃣ Permissions & Least Privilege ## ❌ Bad (implicit permissions) ## ✅ Good (least privilege) ## Common permissions you’ll see ## 3️⃣ Job-Level Permission Overrides ## 4️⃣ Forked Pull Requests (Critical Concept) ## 5️⃣ The Danger of pull_request_target ## Use it ONLY for: ## 6️⃣ Third-Party Actions: Trust Carefully ## 7️⃣ Secure Deployment Pattern (Recommended) ## Common Security Mistakes 🚨 ## Final Mental Model (Lock This In) ## What’s Next? In the previous episodes, we learned how to: Now we’ll cover the topic that most broken pipelines get wrong: This episode explains: A GitHub Actions workflow can: A vulnerable workflow can compromise your entire system. GitHub Actions is secure by default — but only if you understand how its model works. GITHUB_TOKEN is a short-lived, auto-generated token created for every workflow run. You don’t create it. You don’t store it. GitHub injects it automatically. By default, workflows run with restricted permissions. You should explicitly define what your workflow can access. You can restrict permissions per job. Pull requests from forks are untrusted code. GitHub protects you by: “Malicious PR steals secrets” ❌ Never run untrusted code with it. Using an action is equivalent to: Running someone else’s code in your pipeline ❌ Running deploys on PRs ❌ Over-permissive tokens ❌ Printing secrets in logs ❌ Trusting all marketplace actions ❌ Skipping environment protection Secure pipelines are: If you follow this model, most security issues disappear. 👉 Episode 9: Debugging & Troubleshooting GitHub Actions This is where theory turns into real-world confidence 🚀 Thanks for reading! Build safely 👋 Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CODE_BLOCK: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CODE_BLOCK: jobs: build: runs-on: ubuntu-latest Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: jobs: build: runs-on: ubuntu-latest CODE_BLOCK: jobs: build: runs-on: ubuntu-latest CODE_BLOCK: permissions: contents: read jobs: build: runs-on: ubuntu-latest Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: permissions: contents: read jobs: build: runs-on: ubuntu-latest CODE_BLOCK: permissions: contents: read jobs: build: runs-on: ubuntu-latest CODE_BLOCK: jobs: deploy: permissions: contents: read id-token: write Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: jobs: deploy: permissions: contents: read id-token: write CODE_BLOCK: jobs: deploy: permissions: contents: read id-token: write CODE_BLOCK: on: pull_request_target Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: on: pull_request_target CODE_BLOCK: on: pull_request_target CODE_BLOCK: uses: actions/checkout@v4 Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: uses: actions/checkout@v4 CODE_BLOCK: uses: actions/checkout@v4 CODE_BLOCK: permissions: contents: read jobs: test: runs-on: ubuntu-latest deploy: needs: test if: github.ref == 'refs/heads/main' environment: production permissions: contents: read id-token: write Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: permissions: contents: read jobs: test: runs-on: ubuntu-latest deploy: needs: test if: github.ref == 'refs/heads/main' environment: production permissions: contents: read id-token: write CODE_BLOCK: permissions: contents: read jobs: test: runs-on: ubuntu-latest deploy: needs: test if: github.ref == 'refs/heads/main' environment: production permissions: contents: read id-token: write CODE_BLOCK: Untrusted code → no secrets Trusted branch → controlled access Least privilege → always Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: Untrusted code → no secrets Trusted branch → controlled access Least privilege → always CODE_BLOCK: Untrusted code → no secrets Trusted branch → controlled access Least privilege → always - build clean CI/CD pipelines - reuse workflows - speed things up with cache and artifacts - how GitHub Actions protects your secrets - what GITHUB_TOKEN really is - why forked pull requests are treated differently - how to design secure pipelines without fear - access your source code - deploy to production - publish packages - modify repositories - read repository contents - comment on PRs - create releases - push commits (if allowed) - CI jobs stay minimal - deploy jobs get only what they need - ❌ not passing secrets - 🔒 making GITHUB_TOKEN read-only - 🚫 blocking write access - runs in the base repository context - has access to secrets - can be dangerous if misused - labeling PRs - metadata tasks - use official or well-maintained actions - pin versions (@v4, not @main) - avoid unknown or inactive repos - consider SHA pinning for high-security pipelines - tests run first - deploy only from main - environment approvals apply - permissions are minimal - predictable - read logs effectively - debug secrets and permissions - understand silent failures - fix flaky pipelines