I’ve been spending a lot of time lately reading through different GitHub workflow files. One thing that always intrigues me is how differently each one is written—no two repositories seem to handle their workflows in exactly the same way. Recently, I came across several snippets that made use of the [labeled]
event, and it got me curious. Could the simple act of requiring labels actually make malicious code execution harder for an attacker? That question led me down an interesting path of exploration. Let’s dive in.
When most developers think about labels in GitHub, the first things that come to mind are organization and workflow management. “Bug,” “enhancement,” “documentation,” “good first issue”—labels are usually seen as a way to sort through the chaos of issues and pull requests.
But labels can do more than just keep things tidy—they can actually play a crucial role in repository security. By controlling which workflows run, who can trigger them, and how issues or PRs are processed, labels can act as a simple yet powerful guard against potentially malicious code.
What Are Labels in GitHub?
Labels in GitHub are tags that can be applied to issues and pull requests. Think of them as colorful sticky notes that give extra context. For example:
bug
→ marks an issue as a defect.enhancement
→ marks a feature request.good first issue
→ highlights beginner-friendly tasks.security
→ flags vulnerabilities or sensitive topics.
Labels are fully customizable—you can create your own to match your workflow. Only users with write access (or higher) can add or remove labels, which makes them particularly useful for access control.

While they’re commonly used for project management and triage, their real strength comes when you tie them into GitHub Actions, where labels can decide what workflows run, and when
Labels in GitHub Actions: The Security Angle
GitHub Actions allows developers to automate tasks like running tests, deploying code, or scanning for vulnerabilities. These workflows often have access to sensitive resources—think secrets, tokens, or deployment keys.
Here’s the problem: not all PRs are created equal. External contributors submitting PRs from forks do not have the same permissions as collaborators inside your organization. If a workflow runs automatically on every PR, a malicious actor could inject code to exfiltrate secrets or perform other harmful actions.
This is where labels come in. By setting up workflows to trigger only when a specific label is applied, you can effectively prevent untrusted PRs from accessing sensitive resources. Since external contributors cannot apply labels themselves, only trusted maintainers can authorize the workflow to run.
Example: Securing Workflows With Labels
Suppose you have a workflow to build and deploy code to production. You don’t want this running automatically for PRs coming from forks. Here’s how a label-based approach can help:
name: Secure Build
on:
pull_request:
types: [labeled]
jobs:
build:
if: contains(github.event.pull_request.labels.*.name, 'run-ci')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run tests
run: npm install && npm test
- name: Deploy
run: ./deploy.sh
env:
PROD_TOKEN: ${{ secrets.PROD_TOKEN }}
How this works:
- The workflow triggers only when a PR is labeled.
- The job checks if the PR has the
run-ci
label. - Only if the label exists, the workflow proceeds and can access sensitive secrets.
Since external contributors cannot apply the run-ci
label, their PRs are prevented from executing workflows that could be dangerous.
Real-World Scenarios
- Preventing Secret Leaks
Imagine a forked PR that modifies the workflow file to print out secrets (like AWS keys). If your workflows run on every PR automatically, that secret is gone. By requiring asafe-to-test
label before workflows run, you stop this cold. - Controlled Deployment
A repository has a workflow that deploys to staging whenever a PR is opened. Without label control, an external contributor could force deployments repeatedly. With aready-to-deploy
label, only trusted maintainers decide when it’s safe. - Security-Specific Workflows
You may run heavy or sensitive scans (SAST, dependency scans, SBOM generation) only on PRs labeledneeds-security-review
. This saves compute costs and avoids exposing results unnecessarily.
While hunting on targets, I came across a scenario where presence of labels
increased the attack complexity as a certain workflow which was using attacker controlled input would only run if there was a certain label. As an external user, I could not add that label. I would require some level of access on the repo to successfully trigger the workflow.
Anti-Pattern: What Happens Without Labels
Let’s say you don’t use labels at all, and every PR runs all workflows.
- A malicious contributor opens a PR from a fork.
- They add a line in the workflow to echo
${{ secrets.GITHUB_TOKEN }}
or another secret. - GitHub automatically runs this PR’s workflow because it’s treated like any other.
- The attacker gains access to sensitive tokens or even your deployment pipeline.
This isn’t a theoretical risk—it’s a real attack vector that has burned projects in the past. Labels are one of the simplest and most effective ways to put a human review gate in place.
Labels Beyond Security
While security is a strong use case, labels also shine in:
- Triage: Prioritizing issues with
critical
orhigh-priority
. - Ownership: Routing issues with
frontend
orbackend
to the right teams. - Community management: Helping new contributors find
good first issue
.
Conclusion
Labels in GitHub may seem trivial at first glance, but they are a silent guardian for your repository. By controlling workflow execution, you can prevent external contributors from running malicious code, protect secrets, and ensure that only trusted PRs touch critical parts of your project.
Next time you add a label, remember: it’s not just about organization. It might just save your repository from a disaster.
PS: I don’t mean to suggest that you should keep your workflows vulnerable and rely on labels as a safety net. 🙂 Labels are not a replacement for secure coding practices—they’re simply another best practice to add to your toolkit. Think of them as one more layer in a defense-in-depth approach.
That’s all for this post. See you in the next one. Until then, happy hunting!!