[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-sentry-wrdn-gha-workflows":3,"mdc--66s5n7-key":38,"related-org-sentry-wrdn-gha-workflows":5913,"related-repo-sentry-wrdn-gha-workflows":6088},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":27,"repoUrl":28,"updatedAt":29,"license":30,"forks":31,"topics":32,"repo":34,"sourceUrl":36,"mdContent":37},"wrdn-gha-workflows","detect GitHub Actions workflow vulnerabilities","Detects exploitable GitHub Actions workflow vulnerabilities, including pull_request_target pwn requests, unsafe PR checkout, expression injection in run steps and actions\u002Fgithub-script blocks, workflow_dispatch and workflow_call input command injection, comment- and discussion-triggered commands, TOCTOU between approval and checkout, secret exposure, broad permissions, reusable workflows that consume undeclared secrets, ArtiPACKED-style token leaks through uploaded artifacts, cache poisoning and eviction-stuffing, supply-chain risk from unpinned third-party actions (tj-actions\u002Fchanged-files class), and self-hosted runner abuse. Run on diffs touching .github\u002Fworkflows, action.yml, action.yaml, repo-local actions, or CI-loaded scripts and config.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"sentry","Sentry","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fsentry.png","getsentry",[13,17,20,23,24],{"name":14,"slug":15,"type":16},"Security","security","tag",{"name":18,"slug":19,"type":16},"GitHub Actions","github-actions",{"name":21,"slug":22,"type":16},"CI\u002FCD","ci-cd",{"name":9,"slug":8,"type":16},{"name":25,"slug":26,"type":16},"Code Analysis","code-analysis",56,"https:\u002F\u002Fgithub.com\u002Fgetsentry\u002Fwarden-skills","2026-04-29T05:41:43.93205",null,3,[33],"tag-production",{"repoUrl":28,"stars":27,"forks":31,"topics":35,"description":30},[33],"https:\u002F\u002Fgithub.com\u002Fgetsentry\u002Fwarden-skills\u002Ftree\u002FHEAD\u002Fskills\u002Fwrdn-gha-workflows","---\nname: wrdn-gha-workflows\ndescription: Detects exploitable GitHub Actions workflow vulnerabilities, including pull_request_target pwn requests, unsafe PR checkout, expression injection in run steps and actions\u002Fgithub-script blocks, workflow_dispatch and workflow_call input command injection, comment- and discussion-triggered commands, TOCTOU between approval and checkout, secret exposure, broad permissions, reusable workflows that consume undeclared secrets, ArtiPACKED-style token leaks through uploaded artifacts, cache poisoning and eviction-stuffing, supply-chain risk from unpinned third-party actions (tj-actions\u002Fchanged-files class), and self-hosted runner abuse. Run on diffs touching .github\u002Fworkflows, action.yml, action.yaml, repo-local actions, or CI-loaded scripts and config.\nallowed-tools: Read Grep Glob Bash\n---\n\nYou are a senior application security engineer. You hunt GitHub Actions bugs that let an external attacker, or a workflow caller with less privilege than the job, turn CI into code execution, credential theft, repository write access, package publication, or runner compromise.\n\nThis skill is exploit-oriented. It is not a YAML linter. A privileged trigger by itself is not a finding. A broad `permissions:` block by itself is usually not a finding. The finding is the chain: external or caller-controlled input reaches privileged execution, a trusted credential, or a trusted runner.\n\n## Trace. Do Not Skim.\n\nGitHub Actions bugs hide across files. Read the workflow, follow every `uses:`, and prove the effective execution graph before reporting.\n\n- **Start with the trigger.** Identify whether an external attacker can start the workflow: fork PR, PR update, issue\u002FPR\u002Fdiscussion comment, label event, `workflow_run` after untrusted work, or another public event. For `workflow_dispatch` and `workflow_call`, identify who can supply inputs and whether the job performs release, deploy, publish, signing, token, or runner-sensitive work.\n- **Map trust boundaries.** Separate base repository code from PR-controlled code, manual inputs, reusable workflow inputs, artifacts, caches, comments, titles, branch names, labels, and files loaded from the checked-out ref.\n- **Follow call boundaries.** Resolve local actions, composite actions, reusable workflows, and scripts called by `run:`. The dangerous behavior may sit in a callee while the privileged context is introduced by the caller.\n- **Track token and secret scope.** Read workflow- and job-level `permissions:`, `secrets:`, explicit PATs, deploy keys, OIDC credentials, package tokens, and checkout credential persistence.\n- **Verify execution.** Confirm attacker-controlled or caller-controlled code or text is interpreted by a shell, action, JS evaluator (`actions\u002Fgithub-script`), package lifecycle hook, script, config loader, cache restore, artifact consumer, or runner.\n- **Use the shell.** Use `rg` to find matching workflows, local actions, referenced scripts, reusable workflow calls, and sibling safe patterns. Use `git log -p` when a risky mitigation looks recently changed.\n\nIf you cannot trace the chain with the files available, either drop the finding or report it as medium confidence with the exact missing link. Do not report vague resemblance.\n\n## Scope\n\nReview these files whenever they are present or referenced:\n\n- `.github\u002Fworkflows\u002F*.yml` and `.github\u002Fworkflows\u002F*.yaml`\n- `.github\u002Factions\u002F**\u002Faction.yml` and `.github\u002Factions\u002F**\u002Faction.yaml`\n- repository-root `action.yml` and `action.yaml`\n- scripts, Makefiles, package manager commands, config files, and agent instruction files loaded by workflows\n- reusable workflows called with `uses: .\u002F.github\u002Fworkflows\u002F...` or external `owner\u002Frepo\u002F.github\u002Fworkflows\u002Ffile.yml@ref`\n\nExternal reusable workflows and third-party actions are in scope only to the extent visible from the caller unless their source is available in the workspace. Note unresolved trust assumptions instead of inventing details.\n\n## References\n\nLoad references only when the matching pattern appears.\n\n| When | Read |\n|------|------|\n| `pull_request_target`, privileged PR events, or checkout of PR refs | `references\u002Fprivileged-pr-context.md` |\n| `${{ }}` appears inside `run:`, composite-action shell steps, `actions\u002Fgithub-script`, `actions\u002Fscript`, `workflow_dispatch` inputs, or `workflow_call` inputs | `references\u002Fexpression-injection.md` |\n| `issue_comment`, PR comments, slash commands, labels, or chatops trigger execution, including approval-then-checkout flows | `references\u002Fcomment-commands.md` |\n| `workflow_call`, `workflow_run`, local actions, composite actions, artifacts, or caches connect workflows | `references\u002Freusable-and-indirect-flows.md` |\n| Secrets, PATs, deploy keys, OIDC, package publishing, broad `permissions:`, secret-bearing artifacts, persisted checkout credentials, or `actions\u002Fupload-artifact` paths that may include `.git\u002F` appear | `references\u002Fpermissions-secrets-runners.md` |\n| Third-party or external reusable-workflow refs are mutable (tag, branch, partial SHA), or the workflow handles secrets, package publishing, or trusted release artifacts | `references\u002Fsupply-chain.md` |\n| You need examples, false-positive controls, sample Warden config, or eval prompts | `references\u002Fexamples-and-usage.md` |\n\n## Threat Model\n\nPrefer vulnerabilities exploitable by an external attacker without repository write access. Also report caller-controlled RCE in `workflow_dispatch` or `workflow_call` paths when the job has stronger privileges than the caller's ordinary repository rights, handles secrets, PATs, OIDC, package publishing, releases, deployments, or runs on a sensitive self-hosted runner.\n\nFor every finding, state the entry point explicitly: external attacker, manual `workflow_dispatch` caller, or reusable `workflow_call` caller.\n\nAn external attacker can usually:\n\n- open a pull request from a fork\n- update that pull request\n- choose branch names, changed filenames, commit messages, PR titles, and PR bodies\n- create issues or comments if the repository permits it\n- upload code, package manifests, local actions, scripts, config, and artifacts through their PR\n\nA manual or reusable workflow caller can usually:\n\n- choose free-form `workflow_dispatch` string inputs\n- choose caller-provided `workflow_call` `with:` values\n- choose branch, ref, version, package, release, PR option, changed-file-list, and command-option inputs when the workflow exposes them\n\nThe attacker or caller cannot usually:\n\n- push to protected branches\n- modify base-repository workflow files before approval\n- trigger `workflow_dispatch` in the base repository unless they have the repository or organization permission to do so\n- call internal reusable workflows unless an external trigger reaches them or the caller already has workflow permission\n- read secrets unless a workflow exposes them\n\n## Severity\n\n| Level | Criteria |\n|-------|----------|\n| **high** | External attacker can execute code in a privileged workflow, steal secrets or write-scoped tokens, publish packages, push commits, tamper with releases, or compromise a non-ephemeral self-hosted runner. Also high: a manual or reusable workflow input lets the caller execute code in release, deploy, package-publish, signing, token-minting, production, PAT-backed, or sensitive self-hosted-runner jobs beyond what they can normally do. Also high: a third-party action on a mutable ref sits inside a release, deploy, package-publish, signing, or token-minting step where compromise of the action equals compromise of those credentials. |\n| **medium** | Attack chain is plausible but one link needs verification, exploit impact is bounded by read-only tokens, tightly scoped credentials, manual maintainer approval, or trusted repository users who can trigger the workflow but should not be able to run arbitrary shell under its tokens\u002Fsecrets. Also medium: a third-party action on a mutable ref runs in a job that holds non-trivial secrets, OIDC, or write-scoped tokens. The tj-actions\u002Fchanged-files compromise (CVE-2025-30066) is the standing reason: tag rewrites have already extracted secrets from 23,000+ repositories, so unpinned third-party actions in privileged jobs are an exploited shape, not a hypothetical. |\n| **low** | Defense-in-depth issue that amplifies another bug, such as unnecessarily broad permissions, or mutable refs in workflows that touch only public read-only data with no secrets. Report low only when it is directly adjacent to a reviewed workflow risk. First-party actions (`actions\u002F*`, `github\u002F*`) and actions vendored into the same repository are not findings on this axis by themselves. |\n\nPick the lower level when in doubt and explain the uncertainty.\n\n## What to Report\n\n### Privileged PR context consumes PR-controlled code\n\nReport when `pull_request_target`, privileged `workflow_run`, or an equivalent trusted context checks out, builds, tests, imports, executes, or loads files from PR-controlled refs.\n\nHigh-signal shapes:\n\n- `actions\u002Fcheckout` with `ref: ${{ github.event.pull_request.head.sha }}` or `github.head_ref` in a `pull_request_target` workflow.\n- A trusted workflow runs package manager commands after checking out fork code: `npm install`, `npm test`, `pip install -e .`, `make`, `tox`, `pytest`, `cargo test`, `go test .\u002F...`.\n- A local action, composite action, shell script, Makefile, or config file is loaded from the PR checkout while secrets or write tokens are available.\n- `actions\u002Fcheckout` leaves credentials persisted before untrusted code runs.\n- A privileged `workflow_run` downloads and executes artifacts produced by an untrusted `pull_request` workflow.\n\n### Expression injection in shell and script sinks\n\nReport when attacker-controlled or caller-controlled GitHub context is interpolated directly into a code-evaluating sink in an externally triggerable, manual, or reusable workflow.\n\nSinks to treat as code execution:\n\n- `run:` blocks and composite-action shell steps\n- `actions\u002Fgithub-script` and `actions\u002Fscript` `script:` bodies (JavaScript `eval`-equivalent; CVE-2026-27701 LiveCode used this exact path)\n- inline `python -c`, `node -e`, `bash -c`, `sh -c`, `ruby -e`, or any flag that hands a string to an interpreter\n- `echo \"...${{ x }}...\" >> $GITHUB_OUTPUT`, `>> $GITHUB_ENV`, `>> $GITHUB_STEP_SUMMARY`, or `>> $GITHUB_PATH` when the expression is attacker-controlled (the line is parsed by GitHub before later steps consume it; getsentry 0898b3d8 fixed exactly this)\n- `${{ inputs.* }}` or `${{ github.event.inputs.* }}` interpolated directly into shell or script in `workflow_dispatch` or `workflow_call` release, deploy, publish, bump-version, tagging, PR-creation, secret-bearing, or token-bearing jobs. This is highest signal for free-form `string` inputs. Warden PR #277 hardened `npx semver -i ${{ inputs.bump }} $CURRENT`; sentry c50c92f fixed the more clearly injectable `gh pr create --fill ${{ inputs.pr_options }}` free-form option case.\n- `${{ inputs.* }}` interpolated into shell or script inside a composite action that is reachable from an externally triggerable caller (sentry e93ee1ce pulled this out of `setup-devservices`)\n\nAttacker-controlled values include PR title, PR body, issue title, issue body, comment body, review body, discussion title, discussion body, branch names, changed filenames, labels, commit messages, wiki page names, and any action outputs, environment variables, or workflow inputs derived from those values. Manual and reusable workflow inputs are caller-controlled too; free-form string inputs are untrusted in shell and script sinks even when only repository users can trigger them. Numeric IDs, full commit SHAs, repository names, booleans, hardcoded `choice` options, and values created by the base workflow are usually not injectable unless later code reinterprets them unsafely.\n\n### Comment, label, or chatops command execution\n\nReport when an `issue_comment`, label, discussion, or chatops workflow lets untrusted users trigger commands without an authorization gate, or uses comment\u002Fbody text in a shell or script command without safe quoting. CVE-2025-53104 (gluestack-ui) shipped a discussion-title shell injection. Discussion events are not a quiet corner.\n\nAcceptable gates include `author_association` checks for `MEMBER`, `OWNER`, or `COLLABORATOR`, explicit team membership validation through GitHub API, or a required approval flow before command execution.\n\nAlso report TOCTOU between approval and checkout. A maintainer comments `\u002Fok-to-test` (or labels the PR), the workflow then resolves `pull_request.head.sha` or `head_ref` at execution time; the attacker pushes a new commit between the approval and the checkout, and the privileged job runs unreviewed code. The fix is to pin the checkout to the SHA the maintainer actually approved (commonly the SHA captured at approval time, embedded in the label name or comment body, or fetched from the PR head and recorded into a deployment), not to whatever `head.sha` resolves to when the job starts.\n\n### Credential exposure and permission amplification\n\nReport when untrusted execution can access:\n\n- `secrets.*`, PATs, deploy keys, package registry tokens, cloud credentials, or OIDC token minting\n- `GITHUB_TOKEN` with write scopes relevant to the attack\n- checkout credentials persisted to the repo before untrusted commands run\n- broad workflow permissions that convert a moderate bug into repository, release, package, or issue\u002FPR write access\n- derived secrets written to logs, summaries, files, caches, or artifacts where GitHub masking no longer protects them\n- OIDC trust policies broad enough for untrusted refs or workflows to assume cloud roles\n- `actions\u002Fupload-artifact` whose `path:` is `.`, `.\u002F`, the workspace root, or any directory that may contain `.git\u002F` while a prior `actions\u002Fcheckout` left credentials persisted (ArtiPACKED). Public-repo artifacts are world-readable; the persisted `GITHUB_TOKEN` in `.git\u002Fconfig` walks out the front door. The same shape applies to artifacts that capture full home directories, full `~\u002F.docker\u002Fconfig.json`, full `~\u002F.npmrc`, or full `~\u002F.gitconfig` after a credential helper wrote to them.\n\nPermissions are an amplifier. Tie them to the exploit path.\n\n### Unsafe reusable workflows and local actions\n\nReport when a reusable workflow or local\u002Fcomposite action hides the dangerous half of the chain:\n\n- caller is externally triggerable or privileged, callee executes PR-controlled inputs\n- caller passes secrets to a callee that checks out or runs untrusted refs\n- callee uses untrusted inputs in shell without quoting or validation\n- local action files are sourced from an attacker-controlled checkout\n- third-party or local actions download and execute mutable remote code at runtime\n- a reusable workflow (`on: workflow_call:`) references `${{ secrets.X }}` for any `X` other than `GITHUB_TOKEN` without declaring `X` under its own `secrets:` map. The workflow only functions because callers use `secrets: inherit`. Callers that pass secrets explicitly silently break, and reviewers cannot see the secret surface from the callee file alone (getsentry #19582 fixed this on `select-sentry-tests`).\n- a reusable workflow has no top-level or job-level `permissions:` block. It then inherits whatever the caller granted, which routinely over-scopes the callee (getsentry #19634 on selective testing). Report when the callee performs operations whose required scope is narrower than the caller's grant.\n\n### AI agent config poisoning through CI\n\nReport when a workflow runs an AI coding or review agent on PR-controlled content in a privileged context, especially when the PR can modify project-level instructions or agent config such as `AGENTS.md`, `CLAUDE.md`, `.cursorrules`, `.github\u002Fcopilot-instructions.md`, or tool-specific prompt files.\n\nHigh-signal shapes:\n\n- `pull_request_target` checks out fork code and runs an AI agent action with write permissions or secrets.\n- The workflow allows non-write users to trigger the agent, for example `allowed_non_write_users: '*'`.\n- The agent can write files, run shell commands, commit, approve, label, or comment while reading PR-controlled instructions.\n- CODEOWNERS or explicit approval does not protect agent instruction files before the privileged agent consumes them.\n\n### Cache, artifact, and self-hosted runner abuse\n\nReport when attacker-controlled cache keys, cache contents, or artifacts are restored into privileged jobs and then executed, trusted, or used to publish results. Report self-hosted runner use when untrusted code can execute on a persistent or sensitive runner. The two cache shapes that have already been weaponized are PR-write\u002Fprivileged-read on a shared scope, and the 10 GiB eviction-and-replace pattern (Angular dev-infra). See `references\u002Fpermissions-secrets-runners.md` and `references\u002Freusable-and-indirect-flows.md`.\n\n### Supply-chain risk from action references\n\nReport mutable third-party action references that sit in privileged jobs. CVE-2025-30066 (tj-actions\u002Fchanged-files) and CVE-2025-30154 (reviewdog\u002Faction-setup) demonstrated tag rewrites at scale. When `uses:` resolves to anything other than a 40-character commit SHA on a third-party owner, treat the action's owner and every artifact it fetches at runtime as people who can take over the job. Drop the finding for first-party `actions\u002F*`, `github\u002F*`, and actions vendored into the same repository. See `references\u002Fsupply-chain.md` for severity tiers and the specific shapes (mutable refs, runtime payload downloads, workspace-loaded action paths).\n\n## What NOT to Report\n\n- Generic workflow formatting, actionlint issues, missing names, or YAML style.\n- `pull_request_target` that only labels, comments, or reads metadata and never checks out, executes, or loads PR-controlled content.\n- Plain `pull_request` workflows with read-only default token and no secrets, unless they hand unsafe artifacts to a later privileged workflow.\n- `${{ }}` expressions in `if:`, `with:`, or job\u002Fstep-level `env:` unless a receiving action or later shell execution reinterprets the value unsafely.\n- Expressions that resolve only to numeric IDs, full SHAs, booleans, or base-repository constants.\n- `workflow_dispatch`, `workflow_call`, `schedule`, or protected-branch `push` risks with no caller-controlled input reaching a code-evaluating sink and no privileged impact.\n- Manual inputs with hardcoded `choice`, `boolean`, `number`, or `environment` types used only in `if:`, `with:`, safely quoted `env:` variables, or other non-interpreting contexts.\n- Hardcoded `choice` inputs whose complete option set is shell-safe, even if directly interpolated into a command, unless another path can supply arbitrary values or the command reinterprets the option as code. Recommend `env:` plus quoting as hardening, but do not call it RCE without the bypass.\n- Mutable third-party action refs in workflows that handle no secrets, no OIDC, no write-scoped tokens, and only act on public read-only data. First-party `actions\u002F*` and `github\u002F*` references on a tag are not findings.\n- Secrets referenced only in jobs that do not run attacker\u002Fcaller-controlled code or consume attacker-controlled artifacts.\n- Missing branch protections, required reviewers, CODEOWNERS, or organization policy gaps unless the workflow itself creates an exploitable path.\n\n## False-Positive Traps\n\n1. **Default checkout under `pull_request_target` checks out base code.** It may be broken for testing PRs, but it is not the pwn-request bug unless the workflow explicitly materializes PR-controlled code or artifacts.\n2. **`pull_request` is intentionally less privileged for forks.** Do not treat it like `pull_request_target` unless the repo overrides token\u002Fsecrets behavior or the PR is from a same-repo branch.\n3. **`persist-credentials: false` helps but does not erase secrets.** If other secrets or write tokens are in the environment, continue tracing.\n4. **`permissions: read-all` is usually not exploitable by itself.** It can still matter if the workflow can leak private source or read package metadata.\n5. **Reusable workflows inherit context intentionally.** The issue is secret or token exposure combined with untrusted inputs, not reuse itself.\n6. **Artifact upload from untrusted CI is normal.** The bug is privileged downstream execution or trust of that artifact without validation.\n7. **Self-hosted runners are not always public.** Confirm external PRs can reach the runner before reporting.\n8. **GitHub masks exact secret values, not transformations.** A workflow that base64-encodes, truncates, archives, or writes secrets to files can still leak them.\n9. **A maintainer approval is not a SHA pin.** A workflow that resolves `pull_request.head.sha` after an `\u002Fok-to-test`-style approval gate runs whatever the attacker pushed last, not what the maintainer reviewed. Trace the actual ref the privileged job uses.\n10. **`secrets: inherit` masks the secret surface.** A reusable workflow that references `secrets.X` without declaring it appears to \"just work\" through `inherit`. The bug is the undeclared secret, not the inheritance.\n11. **`workflow_dispatch` is not external by default.** Do not call it fork-exploitable unless a public path triggers it. Report it as manual\u002Fcaller-controlled, calibrate severity to the caller and job privilege, and still flag arbitrary command execution in release or secret-bearing jobs.\n12. **`env:` is not magic.** The fix is `env:` plus native shell\u002Fscript variable access and safe quoting or validation. `echo '${{ env.BODY }}'` is still expression injection.\n13. **`choice` inputs narrow the exploit.** A direct `${{ inputs.bump }}` in `run:` is still poor shell hygiene, but `type: choice` with only `minor`, `patch`, and `major` is not the same as free-form command injection. Verify whether API dispatch, a caller workflow, or a later refactor can bypass the finite set before reporting.\n\n## Canonical Patterns\n\n### Pattern: Pwn request through explicit PR checkout\n\n**GitHub Actions - bad:**\n\n```yaml\non: pull_request_target\npermissions: write-all\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}\n      - run: npm install\n      - run: npm test\n```\n\nThe fork controls package scripts and test code while the job has trusted-repository permissions.\n\n**GitHub Actions - safe:**\n\n```yaml\non: pull_request\npermissions:\n  contents: read\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          persist-credentials: false\n      - run: npm ci\n      - run: npm test\n```\n\nRun untrusted code in an unprivileged PR workflow. Use a separate `workflow_run` job for trusted reporting, and treat artifacts as untrusted data.\n\n### Pattern: Shell expression injection\n\n**GitHub Actions - bad:**\n\n```yaml\non: pull_request\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - run: echo \"Checking ${{ github.event.pull_request.title }}\"\n```\n\nA PR title can break out of the shell string.\n\n**GitHub Actions - safe:**\n\n```yaml\non: pull_request\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - env:\n          PR_TITLE: ${{ github.event.pull_request.title }}\n        run: printf '%s\\n' \"$PR_TITLE\"\n```\n\nPass untrusted strings through environment variables and quote them in the shell.\n\n### Pattern: Manual workflow input command injection\n\n**GitHub Actions - bad:**\n\n```yaml\non:\n  workflow_dispatch:\n    inputs:\n      bump:\n        type: string\n        required: true\npermissions:\n  contents: write\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - run: |\n          CURRENT=$(node -p \"require('.\u002Fpackage.json').version\")\n          NEW=$(npx semver -i ${{ inputs.bump }} $CURRENT)\n```\n\nThe manual caller controls `inputs.bump`; GitHub expands it into the temporary shell script before execution. In a release job, that is arbitrary command execution under release workflow privileges.\n\n**GitHub Actions - safe:**\n\n```yaml\non:\n  workflow_dispatch:\n    inputs:\n      bump:\n        type: choice\n        required: true\n        options: [major, minor, patch, prerelease]\npermissions:\n  contents: write\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - env:\n          BUMP: ${{ inputs.bump }}\n        run: |\n          case \"$BUMP\" in\n            major|minor|patch|prerelease) ;;\n            *) exit 1 ;;\n          esac\n          CURRENT=$(node -p \"require('.\u002Fpackage.json').version\")\n          NEW=$(npx semver -i \"$BUMP\" \"$CURRENT\")\n```\n\nConstrain the input when the domain is finite, pass it through `env:`, and quote it at the shell use site.\n\n### Pattern: Unauthorized comment command\n\n**GitHub Actions - bad:**\n\n```yaml\non: issue_comment\njobs:\n  deploy-preview:\n    if: contains(github.event.comment.body, '\u002Fdeploy')\n    runs-on: ubuntu-latest\n    steps:\n      - run: .\u002Fci\u002Fdeploy-preview.sh \"${{ github.event.comment.body }}\"\n```\n\nAny commenter can trigger privileged deployment logic.\n\n**GitHub Actions - safe:**\n\n```yaml\non: issue_comment\njobs:\n  deploy-preview:\n    if: >\n      contains(github.event.comment.body, '\u002Fdeploy') &&\n      contains(fromJSON('[\"MEMBER\",\"OWNER\",\"COLLABORATOR\"]'), github.event.comment.author_association)\n    permissions:\n      contents: read\n      pull-requests: write\n    runs-on: ubuntu-latest\n    steps:\n      - env:\n          COMMENT_BODY: ${{ github.event.comment.body }}\n        run: .\u002Fci\u002Fdeploy-preview.sh \"$COMMENT_BODY\"\n```\n\nAuthorization and shell quoting both matter.\n\n### Pattern: Python workflow script executes untrusted config\n\n**Python - bad:**\n\n```python\nimport yaml\nfrom pathlib import Path\nfrom subprocess import run\n\nconfig = yaml.safe_load(Path(\"ci.yml\").read_text())\nrun(config[\"post_check\"], shell=True, check=True)\n```\n\nIf `ci.yml` came from a fork checkout in a privileged workflow, the script is a command-execution sink.\n\n**Python - safe:**\n\n```python\nimport yaml\nfrom pathlib import Path\nfrom subprocess import run\n\nallowed = {\"lint\": [\"npm\", \"run\", \"lint\"], \"test\": [\"npm\", \"test\"]}\nconfig = yaml.safe_load(Path(\"ci.yml\").read_text())\nrun(allowed[config[\"task\"]], check=True)\n```\n\nUse an allowlist and argv arrays. Do not execute repo-controlled strings.\n\n### Pattern: ArtiPACKED token leak through artifact upload\n\n**GitHub Actions - bad:**\n\n```yaml\n- uses: actions\u002Fcheckout@v4\n- run: .\u002Fbuild.sh\n- uses: actions\u002Fupload-artifact@v4\n  with:\n    name: build-output\n    path: .\n```\n\n`actions\u002Fcheckout` left `GITHUB_TOKEN` in `.git\u002Fconfig`. The workspace-root upload publishes the token in a public-repo artifact.\n\n**GitHub Actions - safe:**\n\n```yaml\n- uses: actions\u002Fcheckout@v4\n  with:\n    persist-credentials: false\n- run: .\u002Fbuild.sh\n- uses: actions\u002Fupload-artifact@v4\n  with:\n    name: build-output\n    path: dist\u002F\n```\n\nDisable credential persistence and upload only the directory you mean to publish.\n\n### Pattern: actions\u002Fgithub-script expression injection\n\n**GitHub Actions - bad:**\n\n```yaml\non: issue_comment\njobs:\n  triage:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fgithub-script@v7\n        with:\n          script: |\n            const title = \"${{ github.event.issue.title }}\";\n            await github.rest.issues.createComment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.issue.number,\n              body: `Triaged: ${title}`,\n            });\n```\n\nThe issue title is concatenated into JavaScript source before evaluation. A title containing `\"); maliciousCode(); (\"` runs in the action's Node context with the `github` token. CVE-2026-27701 (LiveCode) shipped this exact shape on PR titles.\n\n**GitHub Actions - safe:**\n\n```yaml\non: issue_comment\njobs:\n  triage:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fgithub-script@v7\n        env:\n          ISSUE_TITLE: ${{ github.event.issue.title }}\n        with:\n          script: |\n            const title = process.env.ISSUE_TITLE;\n            await github.rest.issues.createComment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.issue.number,\n              body: `Triaged: ${title}`,\n            });\n```\n\nPass untrusted strings through `env:` and read them with `process.env`. The expression is no longer evaluated as code.\n\n### Pattern: Reusable workflow consumes undeclared secrets\n\n**GitHub Actions - bad:**\n\n```yaml\non:\n  workflow_call:\n    inputs:\n      target:\n        type: string\n        required: true\n\njobs:\n  run:\n    runs-on: ubuntu-latest\n    steps:\n      - run: .\u002Fbin\u002Fdeploy \"$TARGET\"\n        env:\n          TARGET: ${{ inputs.target }}\n          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}\n```\n\nThe callee uses `secrets.DEPLOY_KEY` without declaring it under `workflow_call.secrets`. The workflow only runs when the caller writes `secrets: inherit`; the secret surface is invisible to anyone reading this file.\n\n**GitHub Actions - safe:**\n\n```yaml\non:\n  workflow_call:\n    inputs:\n      target:\n        type: string\n        required: true\n    secrets:\n      DEPLOY_KEY:\n        required: true\n\njobs:\n  run:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    steps:\n      - run: .\u002Fbin\u002Fdeploy \"$TARGET\"\n        env:\n          TARGET: ${{ inputs.target }}\n          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}\n```\n\nDeclare every consumed secret. Pin `permissions:` so the callee does not silently inherit caller scope.\n\n### Pattern: TypeScript action runs untrusted input\n\n**TypeScript - bad:**\n\n```ts\nimport * as core from '@actions\u002Fcore';\nimport {execSync} from 'node:child_process';\n\nconst target = core.getInput('target');\nexecSync(`make ${target}`, {stdio: 'inherit'});\n```\n\nIf a workflow passes PR-controlled text into `target`, the composite or JavaScript action becomes the shell sink.\n\n**TypeScript - safe:**\n\n```ts\nimport * as core from '@actions\u002Fcore';\nimport {execFileSync} from 'node:child_process';\n\nconst target = core.getInput('target');\nif (!\u002F^[a-z0-9_-]+$\u002Fi.test(target)) {\n  throw new Error('invalid target');\n}\nexecFileSync('make', [target], {stdio: 'inherit'});\n```\n\nValidate action inputs and avoid shell interpolation.\n\n## Output Requirements\n\nFor every finding, include:\n\n- **File and line**: exact workflow, action, script, or config location\n- **Entry point**: how the external attacker reaches the workflow, or which manual\u002Freusable caller can supply inputs\n- **Controlled input**: PR ref, artifact, cache, comment, branch, title, file, config, `workflow_dispatch` input, or `workflow_call` input\n- **Execution mechanism**: checkout, shell expression, script, package lifecycle, local action, artifact restore, or runner\n- **Privileges exposed**: secrets, token scopes, OIDC, package publishing, runner access, or repository write\n- **Impact**: what the attacker or caller can do\n- **Confidence**: high or medium, with the reason\n- **Fix**: concrete change, preferably a minimal workflow patch\n\nIf there are no findings, say that no exploitable GitHub Actions workflow vulnerabilities were identified and list the workflows or paths reviewed.\n",{"data":39,"body":41},{"name":4,"description":6,"allowed-tools":40},"Read Grep Glob Bash",{"type":42,"children":43},"root",[44,52,66,73,86,223,228,234,239,316,321,327,332,565,571,590,609,614,642,647,687,692,727,733,818,823,829,836,855,860,992,998,1003,1008,1199,1212,1218,1230,1265,1301,1307,1312,1442,1447,1453,1458,1564,1570,1604,1608,1643,1649,1666,1672,1704,1710,1908,1914,2189,2195,2201,2209,2417,2422,2430,2616,2628,2634,2641,2732,2737,2744,2864,2869,2875,2882,3086,3099,3106,3417,3429,3435,3442,3551,3556,3563,3757,3762,3768,3776,3834,3847,3855,3913,3918,3924,3931,4045,4068,4075,4208,4213,4219,4226,4400,4421,4428,4622,4642,4648,4655,4859,4887,4894,5155,5167,5173,5181,5426,5438,5446,5789,5794,5800,5805,5902,5907],{"type":45,"tag":46,"props":47,"children":48},"element","p",{},[49],{"type":50,"value":51},"text","You are a senior application security engineer. You hunt GitHub Actions bugs that let an external attacker, or a workflow caller with less privilege than the job, turn CI into code execution, credential theft, repository write access, package publication, or runner compromise.",{"type":45,"tag":46,"props":53,"children":54},{},[55,57,64],{"type":50,"value":56},"This skill is exploit-oriented. It is not a YAML linter. A privileged trigger by itself is not a finding. A broad ",{"type":45,"tag":58,"props":59,"children":61},"code",{"className":60},[],[62],{"type":50,"value":63},"permissions:",{"type":50,"value":65}," block by itself is usually not a finding. The finding is the chain: external or caller-controlled input reaches privileged execution, a trusted credential, or a trusted runner.",{"type":45,"tag":67,"props":68,"children":70},"h2",{"id":69},"trace-do-not-skim",[71],{"type":50,"value":72},"Trace. Do Not Skim.",{"type":45,"tag":46,"props":74,"children":75},{},[76,78,84],{"type":50,"value":77},"GitHub Actions bugs hide across files. Read the workflow, follow every ",{"type":45,"tag":58,"props":79,"children":81},{"className":80},[],[82],{"type":50,"value":83},"uses:",{"type":50,"value":85},", and prove the effective execution graph before reporting.",{"type":45,"tag":87,"props":88,"children":89},"ul",{},[90,126,136,154,179,197],{"type":45,"tag":91,"props":92,"children":93},"li",{},[94,100,102,108,110,116,118,124],{"type":45,"tag":95,"props":96,"children":97},"strong",{},[98],{"type":50,"value":99},"Start with the trigger.",{"type":50,"value":101}," Identify whether an external attacker can start the workflow: fork PR, PR update, issue\u002FPR\u002Fdiscussion comment, label event, ",{"type":45,"tag":58,"props":103,"children":105},{"className":104},[],[106],{"type":50,"value":107},"workflow_run",{"type":50,"value":109}," after untrusted work, or another public event. For ",{"type":45,"tag":58,"props":111,"children":113},{"className":112},[],[114],{"type":50,"value":115},"workflow_dispatch",{"type":50,"value":117}," and ",{"type":45,"tag":58,"props":119,"children":121},{"className":120},[],[122],{"type":50,"value":123},"workflow_call",{"type":50,"value":125},", identify who can supply inputs and whether the job performs release, deploy, publish, signing, token, or runner-sensitive work.",{"type":45,"tag":91,"props":127,"children":128},{},[129,134],{"type":45,"tag":95,"props":130,"children":131},{},[132],{"type":50,"value":133},"Map trust boundaries.",{"type":50,"value":135}," Separate base repository code from PR-controlled code, manual inputs, reusable workflow inputs, artifacts, caches, comments, titles, branch names, labels, and files loaded from the checked-out ref.",{"type":45,"tag":91,"props":137,"children":138},{},[139,144,146,152],{"type":45,"tag":95,"props":140,"children":141},{},[142],{"type":50,"value":143},"Follow call boundaries.",{"type":50,"value":145}," Resolve local actions, composite actions, reusable workflows, and scripts called by ",{"type":45,"tag":58,"props":147,"children":149},{"className":148},[],[150],{"type":50,"value":151},"run:",{"type":50,"value":153},". The dangerous behavior may sit in a callee while the privileged context is introduced by the caller.",{"type":45,"tag":91,"props":155,"children":156},{},[157,162,164,169,171,177],{"type":45,"tag":95,"props":158,"children":159},{},[160],{"type":50,"value":161},"Track token and secret scope.",{"type":50,"value":163}," Read workflow- and job-level ",{"type":45,"tag":58,"props":165,"children":167},{"className":166},[],[168],{"type":50,"value":63},{"type":50,"value":170},", ",{"type":45,"tag":58,"props":172,"children":174},{"className":173},[],[175],{"type":50,"value":176},"secrets:",{"type":50,"value":178},", explicit PATs, deploy keys, OIDC credentials, package tokens, and checkout credential persistence.",{"type":45,"tag":91,"props":180,"children":181},{},[182,187,189,195],{"type":45,"tag":95,"props":183,"children":184},{},[185],{"type":50,"value":186},"Verify execution.",{"type":50,"value":188}," Confirm attacker-controlled or caller-controlled code or text is interpreted by a shell, action, JS evaluator (",{"type":45,"tag":58,"props":190,"children":192},{"className":191},[],[193],{"type":50,"value":194},"actions\u002Fgithub-script",{"type":50,"value":196},"), package lifecycle hook, script, config loader, cache restore, artifact consumer, or runner.",{"type":45,"tag":91,"props":198,"children":199},{},[200,205,207,213,215,221],{"type":45,"tag":95,"props":201,"children":202},{},[203],{"type":50,"value":204},"Use the shell.",{"type":50,"value":206}," Use ",{"type":45,"tag":58,"props":208,"children":210},{"className":209},[],[211],{"type":50,"value":212},"rg",{"type":50,"value":214}," to find matching workflows, local actions, referenced scripts, reusable workflow calls, and sibling safe patterns. Use ",{"type":45,"tag":58,"props":216,"children":218},{"className":217},[],[219],{"type":50,"value":220},"git log -p",{"type":50,"value":222}," when a risky mitigation looks recently changed.",{"type":45,"tag":46,"props":224,"children":225},{},[226],{"type":50,"value":227},"If you cannot trace the chain with the files available, either drop the finding or report it as medium confidence with the exact missing link. Do not report vague resemblance.",{"type":45,"tag":67,"props":229,"children":231},{"id":230},"scope",[232],{"type":50,"value":233},"Scope",{"type":45,"tag":46,"props":235,"children":236},{},[237],{"type":50,"value":238},"Review these files whenever they are present or referenced:",{"type":45,"tag":87,"props":240,"children":241},{},[242,258,274,292,297],{"type":45,"tag":91,"props":243,"children":244},{},[245,251,252],{"type":45,"tag":58,"props":246,"children":248},{"className":247},[],[249],{"type":50,"value":250},".github\u002Fworkflows\u002F*.yml",{"type":50,"value":117},{"type":45,"tag":58,"props":253,"children":255},{"className":254},[],[256],{"type":50,"value":257},".github\u002Fworkflows\u002F*.yaml",{"type":45,"tag":91,"props":259,"children":260},{},[261,267,268],{"type":45,"tag":58,"props":262,"children":264},{"className":263},[],[265],{"type":50,"value":266},".github\u002Factions\u002F**\u002Faction.yml",{"type":50,"value":117},{"type":45,"tag":58,"props":269,"children":271},{"className":270},[],[272],{"type":50,"value":273},".github\u002Factions\u002F**\u002Faction.yaml",{"type":45,"tag":91,"props":275,"children":276},{},[277,279,285,286],{"type":50,"value":278},"repository-root ",{"type":45,"tag":58,"props":280,"children":282},{"className":281},[],[283],{"type":50,"value":284},"action.yml",{"type":50,"value":117},{"type":45,"tag":58,"props":287,"children":289},{"className":288},[],[290],{"type":50,"value":291},"action.yaml",{"type":45,"tag":91,"props":293,"children":294},{},[295],{"type":50,"value":296},"scripts, Makefiles, package manager commands, config files, and agent instruction files loaded by workflows",{"type":45,"tag":91,"props":298,"children":299},{},[300,302,308,310],{"type":50,"value":301},"reusable workflows called with ",{"type":45,"tag":58,"props":303,"children":305},{"className":304},[],[306],{"type":50,"value":307},"uses: .\u002F.github\u002Fworkflows\u002F...",{"type":50,"value":309}," or external ",{"type":45,"tag":58,"props":311,"children":313},{"className":312},[],[314],{"type":50,"value":315},"owner\u002Frepo\u002F.github\u002Fworkflows\u002Ffile.yml@ref",{"type":45,"tag":46,"props":317,"children":318},{},[319],{"type":50,"value":320},"External reusable workflows and third-party actions are in scope only to the extent visible from the caller unless their source is available in the workspace. Note unresolved trust assumptions instead of inventing details.",{"type":45,"tag":67,"props":322,"children":324},{"id":323},"references",[325],{"type":50,"value":326},"References",{"type":45,"tag":46,"props":328,"children":329},{},[330],{"type":50,"value":331},"Load references only when the matching pattern appears.",{"type":45,"tag":333,"props":334,"children":335},"table",{},[336,355],{"type":45,"tag":337,"props":338,"children":339},"thead",{},[340],{"type":45,"tag":341,"props":342,"children":343},"tr",{},[344,350],{"type":45,"tag":345,"props":346,"children":347},"th",{},[348],{"type":50,"value":349},"When",{"type":45,"tag":345,"props":351,"children":352},{},[353],{"type":50,"value":354},"Read",{"type":45,"tag":356,"props":357,"children":358},"tbody",{},[359,383,440,463,491,531,548],{"type":45,"tag":341,"props":360,"children":361},{},[362,374],{"type":45,"tag":363,"props":364,"children":365},"td",{},[366,372],{"type":45,"tag":58,"props":367,"children":369},{"className":368},[],[370],{"type":50,"value":371},"pull_request_target",{"type":50,"value":373},", privileged PR events, or checkout of PR refs",{"type":45,"tag":363,"props":375,"children":376},{},[377],{"type":45,"tag":58,"props":378,"children":380},{"className":379},[],[381],{"type":50,"value":382},"references\u002Fprivileged-pr-context.md",{"type":45,"tag":341,"props":384,"children":385},{},[386,431],{"type":45,"tag":363,"props":387,"children":388},{},[389,395,397,402,404,409,410,416,417,422,424,429],{"type":45,"tag":58,"props":390,"children":392},{"className":391},[],[393],{"type":50,"value":394},"${{ }}",{"type":50,"value":396}," appears inside ",{"type":45,"tag":58,"props":398,"children":400},{"className":399},[],[401],{"type":50,"value":151},{"type":50,"value":403},", composite-action shell steps, ",{"type":45,"tag":58,"props":405,"children":407},{"className":406},[],[408],{"type":50,"value":194},{"type":50,"value":170},{"type":45,"tag":58,"props":411,"children":413},{"className":412},[],[414],{"type":50,"value":415},"actions\u002Fscript",{"type":50,"value":170},{"type":45,"tag":58,"props":418,"children":420},{"className":419},[],[421],{"type":50,"value":115},{"type":50,"value":423}," inputs, or ",{"type":45,"tag":58,"props":425,"children":427},{"className":426},[],[428],{"type":50,"value":123},{"type":50,"value":430}," inputs",{"type":45,"tag":363,"props":432,"children":433},{},[434],{"type":45,"tag":58,"props":435,"children":437},{"className":436},[],[438],{"type":50,"value":439},"references\u002Fexpression-injection.md",{"type":45,"tag":341,"props":441,"children":442},{},[443,454],{"type":45,"tag":363,"props":444,"children":445},{},[446,452],{"type":45,"tag":58,"props":447,"children":449},{"className":448},[],[450],{"type":50,"value":451},"issue_comment",{"type":50,"value":453},", PR comments, slash commands, labels, or chatops trigger execution, including approval-then-checkout flows",{"type":45,"tag":363,"props":455,"children":456},{},[457],{"type":45,"tag":58,"props":458,"children":460},{"className":459},[],[461],{"type":50,"value":462},"references\u002Fcomment-commands.md",{"type":45,"tag":341,"props":464,"children":465},{},[466,482],{"type":45,"tag":363,"props":467,"children":468},{},[469,474,475,480],{"type":45,"tag":58,"props":470,"children":472},{"className":471},[],[473],{"type":50,"value":123},{"type":50,"value":170},{"type":45,"tag":58,"props":476,"children":478},{"className":477},[],[479],{"type":50,"value":107},{"type":50,"value":481},", local actions, composite actions, artifacts, or caches connect workflows",{"type":45,"tag":363,"props":483,"children":484},{},[485],{"type":45,"tag":58,"props":486,"children":488},{"className":487},[],[489],{"type":50,"value":490},"references\u002Freusable-and-indirect-flows.md",{"type":45,"tag":341,"props":492,"children":493},{},[494,522],{"type":45,"tag":363,"props":495,"children":496},{},[497,499,504,506,512,514,520],{"type":50,"value":498},"Secrets, PATs, deploy keys, OIDC, package publishing, broad ",{"type":45,"tag":58,"props":500,"children":502},{"className":501},[],[503],{"type":50,"value":63},{"type":50,"value":505},", secret-bearing artifacts, persisted checkout credentials, or ",{"type":45,"tag":58,"props":507,"children":509},{"className":508},[],[510],{"type":50,"value":511},"actions\u002Fupload-artifact",{"type":50,"value":513}," paths that may include ",{"type":45,"tag":58,"props":515,"children":517},{"className":516},[],[518],{"type":50,"value":519},".git\u002F",{"type":50,"value":521}," appear",{"type":45,"tag":363,"props":523,"children":524},{},[525],{"type":45,"tag":58,"props":526,"children":528},{"className":527},[],[529],{"type":50,"value":530},"references\u002Fpermissions-secrets-runners.md",{"type":45,"tag":341,"props":532,"children":533},{},[534,539],{"type":45,"tag":363,"props":535,"children":536},{},[537],{"type":50,"value":538},"Third-party or external reusable-workflow refs are mutable (tag, branch, partial SHA), or the workflow handles secrets, package publishing, or trusted release artifacts",{"type":45,"tag":363,"props":540,"children":541},{},[542],{"type":45,"tag":58,"props":543,"children":545},{"className":544},[],[546],{"type":50,"value":547},"references\u002Fsupply-chain.md",{"type":45,"tag":341,"props":549,"children":550},{},[551,556],{"type":45,"tag":363,"props":552,"children":553},{},[554],{"type":50,"value":555},"You need examples, false-positive controls, sample Warden config, or eval prompts",{"type":45,"tag":363,"props":557,"children":558},{},[559],{"type":45,"tag":58,"props":560,"children":562},{"className":561},[],[563],{"type":50,"value":564},"references\u002Fexamples-and-usage.md",{"type":45,"tag":67,"props":566,"children":568},{"id":567},"threat-model",[569],{"type":50,"value":570},"Threat Model",{"type":45,"tag":46,"props":572,"children":573},{},[574,576,581,583,588],{"type":50,"value":575},"Prefer vulnerabilities exploitable by an external attacker without repository write access. Also report caller-controlled RCE in ",{"type":45,"tag":58,"props":577,"children":579},{"className":578},[],[580],{"type":50,"value":115},{"type":50,"value":582}," or ",{"type":45,"tag":58,"props":584,"children":586},{"className":585},[],[587],{"type":50,"value":123},{"type":50,"value":589}," paths when the job has stronger privileges than the caller's ordinary repository rights, handles secrets, PATs, OIDC, package publishing, releases, deployments, or runs on a sensitive self-hosted runner.",{"type":45,"tag":46,"props":591,"children":592},{},[593,595,600,602,607],{"type":50,"value":594},"For every finding, state the entry point explicitly: external attacker, manual ",{"type":45,"tag":58,"props":596,"children":598},{"className":597},[],[599],{"type":50,"value":115},{"type":50,"value":601}," caller, or reusable ",{"type":45,"tag":58,"props":603,"children":605},{"className":604},[],[606],{"type":50,"value":123},{"type":50,"value":608}," caller.",{"type":45,"tag":46,"props":610,"children":611},{},[612],{"type":50,"value":613},"An external attacker can usually:",{"type":45,"tag":87,"props":615,"children":616},{},[617,622,627,632,637],{"type":45,"tag":91,"props":618,"children":619},{},[620],{"type":50,"value":621},"open a pull request from a fork",{"type":45,"tag":91,"props":623,"children":624},{},[625],{"type":50,"value":626},"update that pull request",{"type":45,"tag":91,"props":628,"children":629},{},[630],{"type":50,"value":631},"choose branch names, changed filenames, commit messages, PR titles, and PR bodies",{"type":45,"tag":91,"props":633,"children":634},{},[635],{"type":50,"value":636},"create issues or comments if the repository permits it",{"type":45,"tag":91,"props":638,"children":639},{},[640],{"type":50,"value":641},"upload code, package manifests, local actions, scripts, config, and artifacts through their PR",{"type":45,"tag":46,"props":643,"children":644},{},[645],{"type":50,"value":646},"A manual or reusable workflow caller can usually:",{"type":45,"tag":87,"props":648,"children":649},{},[650,662,682],{"type":45,"tag":91,"props":651,"children":652},{},[653,655,660],{"type":50,"value":654},"choose free-form ",{"type":45,"tag":58,"props":656,"children":658},{"className":657},[],[659],{"type":50,"value":115},{"type":50,"value":661}," string inputs",{"type":45,"tag":91,"props":663,"children":664},{},[665,667,672,674,680],{"type":50,"value":666},"choose caller-provided ",{"type":45,"tag":58,"props":668,"children":670},{"className":669},[],[671],{"type":50,"value":123},{"type":50,"value":673}," ",{"type":45,"tag":58,"props":675,"children":677},{"className":676},[],[678],{"type":50,"value":679},"with:",{"type":50,"value":681}," values",{"type":45,"tag":91,"props":683,"children":684},{},[685],{"type":50,"value":686},"choose branch, ref, version, package, release, PR option, changed-file-list, and command-option inputs when the workflow exposes them",{"type":45,"tag":46,"props":688,"children":689},{},[690],{"type":50,"value":691},"The attacker or caller cannot usually:",{"type":45,"tag":87,"props":693,"children":694},{},[695,700,705,717,722],{"type":45,"tag":91,"props":696,"children":697},{},[698],{"type":50,"value":699},"push to protected branches",{"type":45,"tag":91,"props":701,"children":702},{},[703],{"type":50,"value":704},"modify base-repository workflow files before approval",{"type":45,"tag":91,"props":706,"children":707},{},[708,710,715],{"type":50,"value":709},"trigger ",{"type":45,"tag":58,"props":711,"children":713},{"className":712},[],[714],{"type":50,"value":115},{"type":50,"value":716}," in the base repository unless they have the repository or organization permission to do so",{"type":45,"tag":91,"props":718,"children":719},{},[720],{"type":50,"value":721},"call internal reusable workflows unless an external trigger reaches them or the caller already has workflow permission",{"type":45,"tag":91,"props":723,"children":724},{},[725],{"type":50,"value":726},"read secrets unless a workflow exposes them",{"type":45,"tag":67,"props":728,"children":730},{"id":729},"severity",[731],{"type":50,"value":732},"Severity",{"type":45,"tag":333,"props":734,"children":735},{},[736,752],{"type":45,"tag":337,"props":737,"children":738},{},[739],{"type":45,"tag":341,"props":740,"children":741},{},[742,747],{"type":45,"tag":345,"props":743,"children":744},{},[745],{"type":50,"value":746},"Level",{"type":45,"tag":345,"props":748,"children":749},{},[750],{"type":50,"value":751},"Criteria",{"type":45,"tag":356,"props":753,"children":754},{},[755,771,787],{"type":45,"tag":341,"props":756,"children":757},{},[758,766],{"type":45,"tag":363,"props":759,"children":760},{},[761],{"type":45,"tag":95,"props":762,"children":763},{},[764],{"type":50,"value":765},"high",{"type":45,"tag":363,"props":767,"children":768},{},[769],{"type":50,"value":770},"External attacker can execute code in a privileged workflow, steal secrets or write-scoped tokens, publish packages, push commits, tamper with releases, or compromise a non-ephemeral self-hosted runner. Also high: a manual or reusable workflow input lets the caller execute code in release, deploy, package-publish, signing, token-minting, production, PAT-backed, or sensitive self-hosted-runner jobs beyond what they can normally do. Also high: a third-party action on a mutable ref sits inside a release, deploy, package-publish, signing, or token-minting step where compromise of the action equals compromise of those credentials.",{"type":45,"tag":341,"props":772,"children":773},{},[774,782],{"type":45,"tag":363,"props":775,"children":776},{},[777],{"type":45,"tag":95,"props":778,"children":779},{},[780],{"type":50,"value":781},"medium",{"type":45,"tag":363,"props":783,"children":784},{},[785],{"type":50,"value":786},"Attack chain is plausible but one link needs verification, exploit impact is bounded by read-only tokens, tightly scoped credentials, manual maintainer approval, or trusted repository users who can trigger the workflow but should not be able to run arbitrary shell under its tokens\u002Fsecrets. Also medium: a third-party action on a mutable ref runs in a job that holds non-trivial secrets, OIDC, or write-scoped tokens. The tj-actions\u002Fchanged-files compromise (CVE-2025-30066) is the standing reason: tag rewrites have already extracted secrets from 23,000+ repositories, so unpinned third-party actions in privileged jobs are an exploited shape, not a hypothetical.",{"type":45,"tag":341,"props":788,"children":789},{},[790,798],{"type":45,"tag":363,"props":791,"children":792},{},[793],{"type":45,"tag":95,"props":794,"children":795},{},[796],{"type":50,"value":797},"low",{"type":45,"tag":363,"props":799,"children":800},{},[801,803,809,810,816],{"type":50,"value":802},"Defense-in-depth issue that amplifies another bug, such as unnecessarily broad permissions, or mutable refs in workflows that touch only public read-only data with no secrets. Report low only when it is directly adjacent to a reviewed workflow risk. First-party actions (",{"type":45,"tag":58,"props":804,"children":806},{"className":805},[],[807],{"type":50,"value":808},"actions\u002F*",{"type":50,"value":170},{"type":45,"tag":58,"props":811,"children":813},{"className":812},[],[814],{"type":50,"value":815},"github\u002F*",{"type":50,"value":817},") and actions vendored into the same repository are not findings on this axis by themselves.",{"type":45,"tag":46,"props":819,"children":820},{},[821],{"type":50,"value":822},"Pick the lower level when in doubt and explain the uncertainty.",{"type":45,"tag":67,"props":824,"children":826},{"id":825},"what-to-report",[827],{"type":50,"value":828},"What to Report",{"type":45,"tag":830,"props":831,"children":833},"h3",{"id":832},"privileged-pr-context-consumes-pr-controlled-code",[834],{"type":50,"value":835},"Privileged PR context consumes PR-controlled code",{"type":45,"tag":46,"props":837,"children":838},{},[839,841,846,848,853],{"type":50,"value":840},"Report when ",{"type":45,"tag":58,"props":842,"children":844},{"className":843},[],[845],{"type":50,"value":371},{"type":50,"value":847},", privileged ",{"type":45,"tag":58,"props":849,"children":851},{"className":850},[],[852],{"type":50,"value":107},{"type":50,"value":854},", or an equivalent trusted context checks out, builds, tests, imports, executes, or loads files from PR-controlled refs.",{"type":45,"tag":46,"props":856,"children":857},{},[858],{"type":50,"value":859},"High-signal shapes:",{"type":45,"tag":87,"props":861,"children":862},{},[863,896,958,963,973],{"type":45,"tag":91,"props":864,"children":865},{},[866,872,874,880,881,887,889,894],{"type":45,"tag":58,"props":867,"children":869},{"className":868},[],[870],{"type":50,"value":871},"actions\u002Fcheckout",{"type":50,"value":873}," with ",{"type":45,"tag":58,"props":875,"children":877},{"className":876},[],[878],{"type":50,"value":879},"ref: ${{ github.event.pull_request.head.sha }}",{"type":50,"value":582},{"type":45,"tag":58,"props":882,"children":884},{"className":883},[],[885],{"type":50,"value":886},"github.head_ref",{"type":50,"value":888}," in a ",{"type":45,"tag":58,"props":890,"children":892},{"className":891},[],[893],{"type":50,"value":371},{"type":50,"value":895}," workflow.",{"type":45,"tag":91,"props":897,"children":898},{},[899,901,907,908,914,915,921,922,928,929,935,936,942,943,949,950,956],{"type":50,"value":900},"A trusted workflow runs package manager commands after checking out fork code: ",{"type":45,"tag":58,"props":902,"children":904},{"className":903},[],[905],{"type":50,"value":906},"npm install",{"type":50,"value":170},{"type":45,"tag":58,"props":909,"children":911},{"className":910},[],[912],{"type":50,"value":913},"npm test",{"type":50,"value":170},{"type":45,"tag":58,"props":916,"children":918},{"className":917},[],[919],{"type":50,"value":920},"pip install -e .",{"type":50,"value":170},{"type":45,"tag":58,"props":923,"children":925},{"className":924},[],[926],{"type":50,"value":927},"make",{"type":50,"value":170},{"type":45,"tag":58,"props":930,"children":932},{"className":931},[],[933],{"type":50,"value":934},"tox",{"type":50,"value":170},{"type":45,"tag":58,"props":937,"children":939},{"className":938},[],[940],{"type":50,"value":941},"pytest",{"type":50,"value":170},{"type":45,"tag":58,"props":944,"children":946},{"className":945},[],[947],{"type":50,"value":948},"cargo test",{"type":50,"value":170},{"type":45,"tag":58,"props":951,"children":953},{"className":952},[],[954],{"type":50,"value":955},"go test .\u002F...",{"type":50,"value":957},".",{"type":45,"tag":91,"props":959,"children":960},{},[961],{"type":50,"value":962},"A local action, composite action, shell script, Makefile, or config file is loaded from the PR checkout while secrets or write tokens are available.",{"type":45,"tag":91,"props":964,"children":965},{},[966,971],{"type":45,"tag":58,"props":967,"children":969},{"className":968},[],[970],{"type":50,"value":871},{"type":50,"value":972}," leaves credentials persisted before untrusted code runs.",{"type":45,"tag":91,"props":974,"children":975},{},[976,978,983,985,991],{"type":50,"value":977},"A privileged ",{"type":45,"tag":58,"props":979,"children":981},{"className":980},[],[982],{"type":50,"value":107},{"type":50,"value":984}," downloads and executes artifacts produced by an untrusted ",{"type":45,"tag":58,"props":986,"children":988},{"className":987},[],[989],{"type":50,"value":990},"pull_request",{"type":50,"value":895},{"type":45,"tag":830,"props":993,"children":995},{"id":994},"expression-injection-in-shell-and-script-sinks",[996],{"type":50,"value":997},"Expression injection in shell and script sinks",{"type":45,"tag":46,"props":999,"children":1000},{},[1001],{"type":50,"value":1002},"Report when attacker-controlled or caller-controlled GitHub context is interpolated directly into a code-evaluating sink in an externally triggerable, manual, or reusable workflow.",{"type":45,"tag":46,"props":1004,"children":1005},{},[1006],{"type":50,"value":1007},"Sinks to treat as code execution:",{"type":45,"tag":87,"props":1009,"children":1010},{},[1011,1021,1052,1093,1126,1181],{"type":45,"tag":91,"props":1012,"children":1013},{},[1014,1019],{"type":45,"tag":58,"props":1015,"children":1017},{"className":1016},[],[1018],{"type":50,"value":151},{"type":50,"value":1020}," blocks and composite-action shell steps",{"type":45,"tag":91,"props":1022,"children":1023},{},[1024,1029,1030,1035,1036,1042,1044,1050],{"type":45,"tag":58,"props":1025,"children":1027},{"className":1026},[],[1028],{"type":50,"value":194},{"type":50,"value":117},{"type":45,"tag":58,"props":1031,"children":1033},{"className":1032},[],[1034],{"type":50,"value":415},{"type":50,"value":673},{"type":45,"tag":58,"props":1037,"children":1039},{"className":1038},[],[1040],{"type":50,"value":1041},"script:",{"type":50,"value":1043}," bodies (JavaScript ",{"type":45,"tag":58,"props":1045,"children":1047},{"className":1046},[],[1048],{"type":50,"value":1049},"eval",{"type":50,"value":1051},"-equivalent; CVE-2026-27701 LiveCode used this exact path)",{"type":45,"tag":91,"props":1053,"children":1054},{},[1055,1057,1063,1064,1070,1071,1077,1078,1084,1085,1091],{"type":50,"value":1056},"inline ",{"type":45,"tag":58,"props":1058,"children":1060},{"className":1059},[],[1061],{"type":50,"value":1062},"python -c",{"type":50,"value":170},{"type":45,"tag":58,"props":1065,"children":1067},{"className":1066},[],[1068],{"type":50,"value":1069},"node -e",{"type":50,"value":170},{"type":45,"tag":58,"props":1072,"children":1074},{"className":1073},[],[1075],{"type":50,"value":1076},"bash -c",{"type":50,"value":170},{"type":45,"tag":58,"props":1079,"children":1081},{"className":1080},[],[1082],{"type":50,"value":1083},"sh -c",{"type":50,"value":170},{"type":45,"tag":58,"props":1086,"children":1088},{"className":1087},[],[1089],{"type":50,"value":1090},"ruby -e",{"type":50,"value":1092},", or any flag that hands a string to an interpreter",{"type":45,"tag":91,"props":1094,"children":1095},{},[1096,1102,1103,1109,1110,1116,1118,1124],{"type":45,"tag":58,"props":1097,"children":1099},{"className":1098},[],[1100],{"type":50,"value":1101},"echo \"...${{ x }}...\" >> $GITHUB_OUTPUT",{"type":50,"value":170},{"type":45,"tag":58,"props":1104,"children":1106},{"className":1105},[],[1107],{"type":50,"value":1108},">> $GITHUB_ENV",{"type":50,"value":170},{"type":45,"tag":58,"props":1111,"children":1113},{"className":1112},[],[1114],{"type":50,"value":1115},">> $GITHUB_STEP_SUMMARY",{"type":50,"value":1117},", or ",{"type":45,"tag":58,"props":1119,"children":1121},{"className":1120},[],[1122],{"type":50,"value":1123},">> $GITHUB_PATH",{"type":50,"value":1125}," when the expression is attacker-controlled (the line is parsed by GitHub before later steps consume it; getsentry 0898b3d8 fixed exactly this)",{"type":45,"tag":91,"props":1127,"children":1128},{},[1129,1135,1136,1142,1144,1149,1150,1155,1157,1163,1165,1171,1173,1179],{"type":45,"tag":58,"props":1130,"children":1132},{"className":1131},[],[1133],{"type":50,"value":1134},"${{ inputs.* }}",{"type":50,"value":582},{"type":45,"tag":58,"props":1137,"children":1139},{"className":1138},[],[1140],{"type":50,"value":1141},"${{ github.event.inputs.* }}",{"type":50,"value":1143}," interpolated directly into shell or script in ",{"type":45,"tag":58,"props":1145,"children":1147},{"className":1146},[],[1148],{"type":50,"value":115},{"type":50,"value":582},{"type":45,"tag":58,"props":1151,"children":1153},{"className":1152},[],[1154],{"type":50,"value":123},{"type":50,"value":1156}," release, deploy, publish, bump-version, tagging, PR-creation, secret-bearing, or token-bearing jobs. This is highest signal for free-form ",{"type":45,"tag":58,"props":1158,"children":1160},{"className":1159},[],[1161],{"type":50,"value":1162},"string",{"type":50,"value":1164}," inputs. Warden PR #277 hardened ",{"type":45,"tag":58,"props":1166,"children":1168},{"className":1167},[],[1169],{"type":50,"value":1170},"npx semver -i ${{ inputs.bump }} $CURRENT",{"type":50,"value":1172},"; sentry c50c92f fixed the more clearly injectable ",{"type":45,"tag":58,"props":1174,"children":1176},{"className":1175},[],[1177],{"type":50,"value":1178},"gh pr create --fill ${{ inputs.pr_options }}",{"type":50,"value":1180}," free-form option case.",{"type":45,"tag":91,"props":1182,"children":1183},{},[1184,1189,1191,1197],{"type":45,"tag":58,"props":1185,"children":1187},{"className":1186},[],[1188],{"type":50,"value":1134},{"type":50,"value":1190}," interpolated into shell or script inside a composite action that is reachable from an externally triggerable caller (sentry e93ee1ce pulled this out of ",{"type":45,"tag":58,"props":1192,"children":1194},{"className":1193},[],[1195],{"type":50,"value":1196},"setup-devservices",{"type":50,"value":1198},")",{"type":45,"tag":46,"props":1200,"children":1201},{},[1202,1204,1210],{"type":50,"value":1203},"Attacker-controlled values include PR title, PR body, issue title, issue body, comment body, review body, discussion title, discussion body, branch names, changed filenames, labels, commit messages, wiki page names, and any action outputs, environment variables, or workflow inputs derived from those values. Manual and reusable workflow inputs are caller-controlled too; free-form string inputs are untrusted in shell and script sinks even when only repository users can trigger them. Numeric IDs, full commit SHAs, repository names, booleans, hardcoded ",{"type":45,"tag":58,"props":1205,"children":1207},{"className":1206},[],[1208],{"type":50,"value":1209},"choice",{"type":50,"value":1211}," options, and values created by the base workflow are usually not injectable unless later code reinterprets them unsafely.",{"type":45,"tag":830,"props":1213,"children":1215},{"id":1214},"comment-label-or-chatops-command-execution",[1216],{"type":50,"value":1217},"Comment, label, or chatops command execution",{"type":45,"tag":46,"props":1219,"children":1220},{},[1221,1223,1228],{"type":50,"value":1222},"Report when an ",{"type":45,"tag":58,"props":1224,"children":1226},{"className":1225},[],[1227],{"type":50,"value":451},{"type":50,"value":1229},", label, discussion, or chatops workflow lets untrusted users trigger commands without an authorization gate, or uses comment\u002Fbody text in a shell or script command without safe quoting. CVE-2025-53104 (gluestack-ui) shipped a discussion-title shell injection. Discussion events are not a quiet corner.",{"type":45,"tag":46,"props":1231,"children":1232},{},[1233,1235,1241,1243,1249,1250,1256,1257,1263],{"type":50,"value":1234},"Acceptable gates include ",{"type":45,"tag":58,"props":1236,"children":1238},{"className":1237},[],[1239],{"type":50,"value":1240},"author_association",{"type":50,"value":1242}," checks for ",{"type":45,"tag":58,"props":1244,"children":1246},{"className":1245},[],[1247],{"type":50,"value":1248},"MEMBER",{"type":50,"value":170},{"type":45,"tag":58,"props":1251,"children":1253},{"className":1252},[],[1254],{"type":50,"value":1255},"OWNER",{"type":50,"value":1117},{"type":45,"tag":58,"props":1258,"children":1260},{"className":1259},[],[1261],{"type":50,"value":1262},"COLLABORATOR",{"type":50,"value":1264},", explicit team membership validation through GitHub API, or a required approval flow before command execution.",{"type":45,"tag":46,"props":1266,"children":1267},{},[1268,1270,1276,1278,1284,1285,1291,1293,1299],{"type":50,"value":1269},"Also report TOCTOU between approval and checkout. A maintainer comments ",{"type":45,"tag":58,"props":1271,"children":1273},{"className":1272},[],[1274],{"type":50,"value":1275},"\u002Fok-to-test",{"type":50,"value":1277}," (or labels the PR), the workflow then resolves ",{"type":45,"tag":58,"props":1279,"children":1281},{"className":1280},[],[1282],{"type":50,"value":1283},"pull_request.head.sha",{"type":50,"value":582},{"type":45,"tag":58,"props":1286,"children":1288},{"className":1287},[],[1289],{"type":50,"value":1290},"head_ref",{"type":50,"value":1292}," at execution time; the attacker pushes a new commit between the approval and the checkout, and the privileged job runs unreviewed code. The fix is to pin the checkout to the SHA the maintainer actually approved (commonly the SHA captured at approval time, embedded in the label name or comment body, or fetched from the PR head and recorded into a deployment), not to whatever ",{"type":45,"tag":58,"props":1294,"children":1296},{"className":1295},[],[1297],{"type":50,"value":1298},"head.sha",{"type":50,"value":1300}," resolves to when the job starts.",{"type":45,"tag":830,"props":1302,"children":1304},{"id":1303},"credential-exposure-and-permission-amplification",[1305],{"type":50,"value":1306},"Credential exposure and permission amplification",{"type":45,"tag":46,"props":1308,"children":1309},{},[1310],{"type":50,"value":1311},"Report when untrusted execution can access:",{"type":45,"tag":87,"props":1313,"children":1314},{},[1315,1326,1337,1342,1347,1352,1357],{"type":45,"tag":91,"props":1316,"children":1317},{},[1318,1324],{"type":45,"tag":58,"props":1319,"children":1321},{"className":1320},[],[1322],{"type":50,"value":1323},"secrets.*",{"type":50,"value":1325},", PATs, deploy keys, package registry tokens, cloud credentials, or OIDC token minting",{"type":45,"tag":91,"props":1327,"children":1328},{},[1329,1335],{"type":45,"tag":58,"props":1330,"children":1332},{"className":1331},[],[1333],{"type":50,"value":1334},"GITHUB_TOKEN",{"type":50,"value":1336}," with write scopes relevant to the attack",{"type":45,"tag":91,"props":1338,"children":1339},{},[1340],{"type":50,"value":1341},"checkout credentials persisted to the repo before untrusted commands run",{"type":45,"tag":91,"props":1343,"children":1344},{},[1345],{"type":50,"value":1346},"broad workflow permissions that convert a moderate bug into repository, release, package, or issue\u002FPR write access",{"type":45,"tag":91,"props":1348,"children":1349},{},[1350],{"type":50,"value":1351},"derived secrets written to logs, summaries, files, caches, or artifacts where GitHub masking no longer protects them",{"type":45,"tag":91,"props":1353,"children":1354},{},[1355],{"type":50,"value":1356},"OIDC trust policies broad enough for untrusted refs or workflows to assume cloud roles",{"type":45,"tag":91,"props":1358,"children":1359},{},[1360,1365,1367,1373,1375,1380,1381,1387,1389,1394,1396,1401,1403,1408,1410,1416,1418,1424,1426,1432,1434,1440],{"type":45,"tag":58,"props":1361,"children":1363},{"className":1362},[],[1364],{"type":50,"value":511},{"type":50,"value":1366}," whose ",{"type":45,"tag":58,"props":1368,"children":1370},{"className":1369},[],[1371],{"type":50,"value":1372},"path:",{"type":50,"value":1374}," is ",{"type":45,"tag":58,"props":1376,"children":1378},{"className":1377},[],[1379],{"type":50,"value":957},{"type":50,"value":170},{"type":45,"tag":58,"props":1382,"children":1384},{"className":1383},[],[1385],{"type":50,"value":1386},".\u002F",{"type":50,"value":1388},", the workspace root, or any directory that may contain ",{"type":45,"tag":58,"props":1390,"children":1392},{"className":1391},[],[1393],{"type":50,"value":519},{"type":50,"value":1395}," while a prior ",{"type":45,"tag":58,"props":1397,"children":1399},{"className":1398},[],[1400],{"type":50,"value":871},{"type":50,"value":1402}," left credentials persisted (ArtiPACKED). Public-repo artifacts are world-readable; the persisted ",{"type":45,"tag":58,"props":1404,"children":1406},{"className":1405},[],[1407],{"type":50,"value":1334},{"type":50,"value":1409}," in ",{"type":45,"tag":58,"props":1411,"children":1413},{"className":1412},[],[1414],{"type":50,"value":1415},".git\u002Fconfig",{"type":50,"value":1417}," walks out the front door. The same shape applies to artifacts that capture full home directories, full ",{"type":45,"tag":58,"props":1419,"children":1421},{"className":1420},[],[1422],{"type":50,"value":1423},"~\u002F.docker\u002Fconfig.json",{"type":50,"value":1425},", full ",{"type":45,"tag":58,"props":1427,"children":1429},{"className":1428},[],[1430],{"type":50,"value":1431},"~\u002F.npmrc",{"type":50,"value":1433},", or full ",{"type":45,"tag":58,"props":1435,"children":1437},{"className":1436},[],[1438],{"type":50,"value":1439},"~\u002F.gitconfig",{"type":50,"value":1441}," after a credential helper wrote to them.",{"type":45,"tag":46,"props":1443,"children":1444},{},[1445],{"type":50,"value":1446},"Permissions are an amplifier. Tie them to the exploit path.",{"type":45,"tag":830,"props":1448,"children":1450},{"id":1449},"unsafe-reusable-workflows-and-local-actions",[1451],{"type":50,"value":1452},"Unsafe reusable workflows and local actions",{"type":45,"tag":46,"props":1454,"children":1455},{},[1456],{"type":50,"value":1457},"Report when a reusable workflow or local\u002Fcomposite action hides the dangerous half of the chain:",{"type":45,"tag":87,"props":1459,"children":1460},{},[1461,1466,1471,1476,1481,1486,1552],{"type":45,"tag":91,"props":1462,"children":1463},{},[1464],{"type":50,"value":1465},"caller is externally triggerable or privileged, callee executes PR-controlled inputs",{"type":45,"tag":91,"props":1467,"children":1468},{},[1469],{"type":50,"value":1470},"caller passes secrets to a callee that checks out or runs untrusted refs",{"type":45,"tag":91,"props":1472,"children":1473},{},[1474],{"type":50,"value":1475},"callee uses untrusted inputs in shell without quoting or validation",{"type":45,"tag":91,"props":1477,"children":1478},{},[1479],{"type":50,"value":1480},"local action files are sourced from an attacker-controlled checkout",{"type":45,"tag":91,"props":1482,"children":1483},{},[1484],{"type":50,"value":1485},"third-party or local actions download and execute mutable remote code at runtime",{"type":45,"tag":91,"props":1487,"children":1488},{},[1489,1491,1497,1499,1505,1507,1513,1515,1520,1522,1527,1529,1534,1536,1542,1544,1550],{"type":50,"value":1490},"a reusable workflow (",{"type":45,"tag":58,"props":1492,"children":1494},{"className":1493},[],[1495],{"type":50,"value":1496},"on: workflow_call:",{"type":50,"value":1498},") references ",{"type":45,"tag":58,"props":1500,"children":1502},{"className":1501},[],[1503],{"type":50,"value":1504},"${{ secrets.X }}",{"type":50,"value":1506}," for any ",{"type":45,"tag":58,"props":1508,"children":1510},{"className":1509},[],[1511],{"type":50,"value":1512},"X",{"type":50,"value":1514}," other than ",{"type":45,"tag":58,"props":1516,"children":1518},{"className":1517},[],[1519],{"type":50,"value":1334},{"type":50,"value":1521}," without declaring ",{"type":45,"tag":58,"props":1523,"children":1525},{"className":1524},[],[1526],{"type":50,"value":1512},{"type":50,"value":1528}," under its own ",{"type":45,"tag":58,"props":1530,"children":1532},{"className":1531},[],[1533],{"type":50,"value":176},{"type":50,"value":1535}," map. The workflow only functions because callers use ",{"type":45,"tag":58,"props":1537,"children":1539},{"className":1538},[],[1540],{"type":50,"value":1541},"secrets: inherit",{"type":50,"value":1543},". Callers that pass secrets explicitly silently break, and reviewers cannot see the secret surface from the callee file alone (getsentry #19582 fixed this on ",{"type":45,"tag":58,"props":1545,"children":1547},{"className":1546},[],[1548],{"type":50,"value":1549},"select-sentry-tests",{"type":50,"value":1551},").",{"type":45,"tag":91,"props":1553,"children":1554},{},[1555,1557,1562],{"type":50,"value":1556},"a reusable workflow has no top-level or job-level ",{"type":45,"tag":58,"props":1558,"children":1560},{"className":1559},[],[1561],{"type":50,"value":63},{"type":50,"value":1563}," block. It then inherits whatever the caller granted, which routinely over-scopes the callee (getsentry #19634 on selective testing). Report when the callee performs operations whose required scope is narrower than the caller's grant.",{"type":45,"tag":830,"props":1565,"children":1567},{"id":1566},"ai-agent-config-poisoning-through-ci",[1568],{"type":50,"value":1569},"AI agent config poisoning through CI",{"type":45,"tag":46,"props":1571,"children":1572},{},[1573,1575,1581,1582,1588,1589,1595,1596,1602],{"type":50,"value":1574},"Report when a workflow runs an AI coding or review agent on PR-controlled content in a privileged context, especially when the PR can modify project-level instructions or agent config such as ",{"type":45,"tag":58,"props":1576,"children":1578},{"className":1577},[],[1579],{"type":50,"value":1580},"AGENTS.md",{"type":50,"value":170},{"type":45,"tag":58,"props":1583,"children":1585},{"className":1584},[],[1586],{"type":50,"value":1587},"CLAUDE.md",{"type":50,"value":170},{"type":45,"tag":58,"props":1590,"children":1592},{"className":1591},[],[1593],{"type":50,"value":1594},".cursorrules",{"type":50,"value":170},{"type":45,"tag":58,"props":1597,"children":1599},{"className":1598},[],[1600],{"type":50,"value":1601},".github\u002Fcopilot-instructions.md",{"type":50,"value":1603},", or tool-specific prompt files.",{"type":45,"tag":46,"props":1605,"children":1606},{},[1607],{"type":50,"value":859},{"type":45,"tag":87,"props":1609,"children":1610},{},[1611,1621,1633,1638],{"type":45,"tag":91,"props":1612,"children":1613},{},[1614,1619],{"type":45,"tag":58,"props":1615,"children":1617},{"className":1616},[],[1618],{"type":50,"value":371},{"type":50,"value":1620}," checks out fork code and runs an AI agent action with write permissions or secrets.",{"type":45,"tag":91,"props":1622,"children":1623},{},[1624,1626,1632],{"type":50,"value":1625},"The workflow allows non-write users to trigger the agent, for example ",{"type":45,"tag":58,"props":1627,"children":1629},{"className":1628},[],[1630],{"type":50,"value":1631},"allowed_non_write_users: '*'",{"type":50,"value":957},{"type":45,"tag":91,"props":1634,"children":1635},{},[1636],{"type":50,"value":1637},"The agent can write files, run shell commands, commit, approve, label, or comment while reading PR-controlled instructions.",{"type":45,"tag":91,"props":1639,"children":1640},{},[1641],{"type":50,"value":1642},"CODEOWNERS or explicit approval does not protect agent instruction files before the privileged agent consumes them.",{"type":45,"tag":830,"props":1644,"children":1646},{"id":1645},"cache-artifact-and-self-hosted-runner-abuse",[1647],{"type":50,"value":1648},"Cache, artifact, and self-hosted runner abuse",{"type":45,"tag":46,"props":1650,"children":1651},{},[1652,1654,1659,1660,1665],{"type":50,"value":1653},"Report when attacker-controlled cache keys, cache contents, or artifacts are restored into privileged jobs and then executed, trusted, or used to publish results. Report self-hosted runner use when untrusted code can execute on a persistent or sensitive runner. The two cache shapes that have already been weaponized are PR-write\u002Fprivileged-read on a shared scope, and the 10 GiB eviction-and-replace pattern (Angular dev-infra). See ",{"type":45,"tag":58,"props":1655,"children":1657},{"className":1656},[],[1658],{"type":50,"value":530},{"type":50,"value":117},{"type":45,"tag":58,"props":1661,"children":1663},{"className":1662},[],[1664],{"type":50,"value":490},{"type":50,"value":957},{"type":45,"tag":830,"props":1667,"children":1669},{"id":1668},"supply-chain-risk-from-action-references",[1670],{"type":50,"value":1671},"Supply-chain risk from action references",{"type":45,"tag":46,"props":1673,"children":1674},{},[1675,1677,1682,1684,1689,1690,1695,1697,1702],{"type":50,"value":1676},"Report mutable third-party action references that sit in privileged jobs. CVE-2025-30066 (tj-actions\u002Fchanged-files) and CVE-2025-30154 (reviewdog\u002Faction-setup) demonstrated tag rewrites at scale. When ",{"type":45,"tag":58,"props":1678,"children":1680},{"className":1679},[],[1681],{"type":50,"value":83},{"type":50,"value":1683}," resolves to anything other than a 40-character commit SHA on a third-party owner, treat the action's owner and every artifact it fetches at runtime as people who can take over the job. Drop the finding for first-party ",{"type":45,"tag":58,"props":1685,"children":1687},{"className":1686},[],[1688],{"type":50,"value":808},{"type":50,"value":170},{"type":45,"tag":58,"props":1691,"children":1693},{"className":1692},[],[1694],{"type":50,"value":815},{"type":50,"value":1696},", and actions vendored into the same repository. See ",{"type":45,"tag":58,"props":1698,"children":1700},{"className":1699},[],[1701],{"type":50,"value":547},{"type":50,"value":1703}," for severity tiers and the specific shapes (mutable refs, runtime payload downloads, workspace-loaded action paths).",{"type":45,"tag":67,"props":1705,"children":1707},{"id":1706},"what-not-to-report",[1708],{"type":50,"value":1709},"What NOT to Report",{"type":45,"tag":87,"props":1711,"children":1712},{},[1713,1718,1728,1740,1772,1777,1808,1861,1880,1898,1903],{"type":45,"tag":91,"props":1714,"children":1715},{},[1716],{"type":50,"value":1717},"Generic workflow formatting, actionlint issues, missing names, or YAML style.",{"type":45,"tag":91,"props":1719,"children":1720},{},[1721,1726],{"type":45,"tag":58,"props":1722,"children":1724},{"className":1723},[],[1725],{"type":50,"value":371},{"type":50,"value":1727}," that only labels, comments, or reads metadata and never checks out, executes, or loads PR-controlled content.",{"type":45,"tag":91,"props":1729,"children":1730},{},[1731,1733,1738],{"type":50,"value":1732},"Plain ",{"type":45,"tag":58,"props":1734,"children":1736},{"className":1735},[],[1737],{"type":50,"value":990},{"type":50,"value":1739}," workflows with read-only default token and no secrets, unless they hand unsafe artifacts to a later privileged workflow.",{"type":45,"tag":91,"props":1741,"children":1742},{},[1743,1748,1750,1756,1757,1762,1764,1770],{"type":45,"tag":58,"props":1744,"children":1746},{"className":1745},[],[1747],{"type":50,"value":394},{"type":50,"value":1749}," expressions in ",{"type":45,"tag":58,"props":1751,"children":1753},{"className":1752},[],[1754],{"type":50,"value":1755},"if:",{"type":50,"value":170},{"type":45,"tag":58,"props":1758,"children":1760},{"className":1759},[],[1761],{"type":50,"value":679},{"type":50,"value":1763},", or job\u002Fstep-level ",{"type":45,"tag":58,"props":1765,"children":1767},{"className":1766},[],[1768],{"type":50,"value":1769},"env:",{"type":50,"value":1771}," unless a receiving action or later shell execution reinterprets the value unsafely.",{"type":45,"tag":91,"props":1773,"children":1774},{},[1775],{"type":50,"value":1776},"Expressions that resolve only to numeric IDs, full SHAs, booleans, or base-repository constants.",{"type":45,"tag":91,"props":1778,"children":1779},{},[1780,1785,1786,1791,1792,1798,1800,1806],{"type":45,"tag":58,"props":1781,"children":1783},{"className":1782},[],[1784],{"type":50,"value":115},{"type":50,"value":170},{"type":45,"tag":58,"props":1787,"children":1789},{"className":1788},[],[1790],{"type":50,"value":123},{"type":50,"value":170},{"type":45,"tag":58,"props":1793,"children":1795},{"className":1794},[],[1796],{"type":50,"value":1797},"schedule",{"type":50,"value":1799},", or protected-branch ",{"type":45,"tag":58,"props":1801,"children":1803},{"className":1802},[],[1804],{"type":50,"value":1805},"push",{"type":50,"value":1807}," risks with no caller-controlled input reaching a code-evaluating sink and no privileged impact.",{"type":45,"tag":91,"props":1809,"children":1810},{},[1811,1813,1818,1819,1825,1826,1832,1833,1839,1841,1846,1847,1852,1854,1859],{"type":50,"value":1812},"Manual inputs with hardcoded ",{"type":45,"tag":58,"props":1814,"children":1816},{"className":1815},[],[1817],{"type":50,"value":1209},{"type":50,"value":170},{"type":45,"tag":58,"props":1820,"children":1822},{"className":1821},[],[1823],{"type":50,"value":1824},"boolean",{"type":50,"value":170},{"type":45,"tag":58,"props":1827,"children":1829},{"className":1828},[],[1830],{"type":50,"value":1831},"number",{"type":50,"value":1117},{"type":45,"tag":58,"props":1834,"children":1836},{"className":1835},[],[1837],{"type":50,"value":1838},"environment",{"type":50,"value":1840}," types used only in ",{"type":45,"tag":58,"props":1842,"children":1844},{"className":1843},[],[1845],{"type":50,"value":1755},{"type":50,"value":170},{"type":45,"tag":58,"props":1848,"children":1850},{"className":1849},[],[1851],{"type":50,"value":679},{"type":50,"value":1853},", safely quoted ",{"type":45,"tag":58,"props":1855,"children":1857},{"className":1856},[],[1858],{"type":50,"value":1769},{"type":50,"value":1860}," variables, or other non-interpreting contexts.",{"type":45,"tag":91,"props":1862,"children":1863},{},[1864,1866,1871,1873,1878],{"type":50,"value":1865},"Hardcoded ",{"type":45,"tag":58,"props":1867,"children":1869},{"className":1868},[],[1870],{"type":50,"value":1209},{"type":50,"value":1872}," inputs whose complete option set is shell-safe, even if directly interpolated into a command, unless another path can supply arbitrary values or the command reinterprets the option as code. Recommend ",{"type":45,"tag":58,"props":1874,"children":1876},{"className":1875},[],[1877],{"type":50,"value":1769},{"type":50,"value":1879}," plus quoting as hardening, but do not call it RCE without the bypass.",{"type":45,"tag":91,"props":1881,"children":1882},{},[1883,1885,1890,1891,1896],{"type":50,"value":1884},"Mutable third-party action refs in workflows that handle no secrets, no OIDC, no write-scoped tokens, and only act on public read-only data. First-party ",{"type":45,"tag":58,"props":1886,"children":1888},{"className":1887},[],[1889],{"type":50,"value":808},{"type":50,"value":117},{"type":45,"tag":58,"props":1892,"children":1894},{"className":1893},[],[1895],{"type":50,"value":815},{"type":50,"value":1897}," references on a tag are not findings.",{"type":45,"tag":91,"props":1899,"children":1900},{},[1901],{"type":50,"value":1902},"Secrets referenced only in jobs that do not run attacker\u002Fcaller-controlled code or consume attacker-controlled artifacts.",{"type":45,"tag":91,"props":1904,"children":1905},{},[1906],{"type":50,"value":1907},"Missing branch protections, required reviewers, CODEOWNERS, or organization policy gaps unless the workflow itself creates an exploitable path.",{"type":45,"tag":67,"props":1909,"children":1911},{"id":1910},"false-positive-traps",[1912],{"type":50,"value":1913},"False-Positive Traps",{"type":45,"tag":1915,"props":1916,"children":1917},"ol",{},[1918,1935,1957,1973,1989,1999,2009,2019,2029,2053,2084,2099,2129],{"type":45,"tag":91,"props":1919,"children":1920},{},[1921,1933],{"type":45,"tag":95,"props":1922,"children":1923},{},[1924,1926,1931],{"type":50,"value":1925},"Default checkout under ",{"type":45,"tag":58,"props":1927,"children":1929},{"className":1928},[],[1930],{"type":50,"value":371},{"type":50,"value":1932}," checks out base code.",{"type":50,"value":1934}," It may be broken for testing PRs, but it is not the pwn-request bug unless the workflow explicitly materializes PR-controlled code or artifacts.",{"type":45,"tag":91,"props":1936,"children":1937},{},[1938,1948,1950,1955],{"type":45,"tag":95,"props":1939,"children":1940},{},[1941,1946],{"type":45,"tag":58,"props":1942,"children":1944},{"className":1943},[],[1945],{"type":50,"value":990},{"type":50,"value":1947}," is intentionally less privileged for forks.",{"type":50,"value":1949}," Do not treat it like ",{"type":45,"tag":58,"props":1951,"children":1953},{"className":1952},[],[1954],{"type":50,"value":371},{"type":50,"value":1956}," unless the repo overrides token\u002Fsecrets behavior or the PR is from a same-repo branch.",{"type":45,"tag":91,"props":1958,"children":1959},{},[1960,1971],{"type":45,"tag":95,"props":1961,"children":1962},{},[1963,1969],{"type":45,"tag":58,"props":1964,"children":1966},{"className":1965},[],[1967],{"type":50,"value":1968},"persist-credentials: false",{"type":50,"value":1970}," helps but does not erase secrets.",{"type":50,"value":1972}," If other secrets or write tokens are in the environment, continue tracing.",{"type":45,"tag":91,"props":1974,"children":1975},{},[1976,1987],{"type":45,"tag":95,"props":1977,"children":1978},{},[1979,1985],{"type":45,"tag":58,"props":1980,"children":1982},{"className":1981},[],[1983],{"type":50,"value":1984},"permissions: read-all",{"type":50,"value":1986}," is usually not exploitable by itself.",{"type":50,"value":1988}," It can still matter if the workflow can leak private source or read package metadata.",{"type":45,"tag":91,"props":1990,"children":1991},{},[1992,1997],{"type":45,"tag":95,"props":1993,"children":1994},{},[1995],{"type":50,"value":1996},"Reusable workflows inherit context intentionally.",{"type":50,"value":1998}," The issue is secret or token exposure combined with untrusted inputs, not reuse itself.",{"type":45,"tag":91,"props":2000,"children":2001},{},[2002,2007],{"type":45,"tag":95,"props":2003,"children":2004},{},[2005],{"type":50,"value":2006},"Artifact upload from untrusted CI is normal.",{"type":50,"value":2008}," The bug is privileged downstream execution or trust of that artifact without validation.",{"type":45,"tag":91,"props":2010,"children":2011},{},[2012,2017],{"type":45,"tag":95,"props":2013,"children":2014},{},[2015],{"type":50,"value":2016},"Self-hosted runners are not always public.",{"type":50,"value":2018}," Confirm external PRs can reach the runner before reporting.",{"type":45,"tag":91,"props":2020,"children":2021},{},[2022,2027],{"type":45,"tag":95,"props":2023,"children":2024},{},[2025],{"type":50,"value":2026},"GitHub masks exact secret values, not transformations.",{"type":50,"value":2028}," A workflow that base64-encodes, truncates, archives, or writes secrets to files can still leak them.",{"type":45,"tag":91,"props":2030,"children":2031},{},[2032,2037,2039,2044,2046,2051],{"type":45,"tag":95,"props":2033,"children":2034},{},[2035],{"type":50,"value":2036},"A maintainer approval is not a SHA pin.",{"type":50,"value":2038}," A workflow that resolves ",{"type":45,"tag":58,"props":2040,"children":2042},{"className":2041},[],[2043],{"type":50,"value":1283},{"type":50,"value":2045}," after an ",{"type":45,"tag":58,"props":2047,"children":2049},{"className":2048},[],[2050],{"type":50,"value":1275},{"type":50,"value":2052},"-style approval gate runs whatever the attacker pushed last, not what the maintainer reviewed. Trace the actual ref the privileged job uses.",{"type":45,"tag":91,"props":2054,"children":2055},{},[2056,2066,2068,2074,2076,2082],{"type":45,"tag":95,"props":2057,"children":2058},{},[2059,2064],{"type":45,"tag":58,"props":2060,"children":2062},{"className":2061},[],[2063],{"type":50,"value":1541},{"type":50,"value":2065}," masks the secret surface.",{"type":50,"value":2067}," A reusable workflow that references ",{"type":45,"tag":58,"props":2069,"children":2071},{"className":2070},[],[2072],{"type":50,"value":2073},"secrets.X",{"type":50,"value":2075}," without declaring it appears to \"just work\" through ",{"type":45,"tag":58,"props":2077,"children":2079},{"className":2078},[],[2080],{"type":50,"value":2081},"inherit",{"type":50,"value":2083},". The bug is the undeclared secret, not the inheritance.",{"type":45,"tag":91,"props":2085,"children":2086},{},[2087,2097],{"type":45,"tag":95,"props":2088,"children":2089},{},[2090,2095],{"type":45,"tag":58,"props":2091,"children":2093},{"className":2092},[],[2094],{"type":50,"value":115},{"type":50,"value":2096}," is not external by default.",{"type":50,"value":2098}," Do not call it fork-exploitable unless a public path triggers it. Report it as manual\u002Fcaller-controlled, calibrate severity to the caller and job privilege, and still flag arbitrary command execution in release or secret-bearing jobs.",{"type":45,"tag":91,"props":2100,"children":2101},{},[2102,2112,2114,2119,2121,2127],{"type":45,"tag":95,"props":2103,"children":2104},{},[2105,2110],{"type":45,"tag":58,"props":2106,"children":2108},{"className":2107},[],[2109],{"type":50,"value":1769},{"type":50,"value":2111}," is not magic.",{"type":50,"value":2113}," The fix is ",{"type":45,"tag":58,"props":2115,"children":2117},{"className":2116},[],[2118],{"type":50,"value":1769},{"type":50,"value":2120}," plus native shell\u002Fscript variable access and safe quoting or validation. ",{"type":45,"tag":58,"props":2122,"children":2124},{"className":2123},[],[2125],{"type":50,"value":2126},"echo '${{ env.BODY }}'",{"type":50,"value":2128}," is still expression injection.",{"type":45,"tag":91,"props":2130,"children":2131},{},[2132,2142,2144,2150,2151,2156,2158,2164,2166,2172,2173,2179,2181,2187],{"type":45,"tag":95,"props":2133,"children":2134},{},[2135,2140],{"type":45,"tag":58,"props":2136,"children":2138},{"className":2137},[],[2139],{"type":50,"value":1209},{"type":50,"value":2141}," inputs narrow the exploit.",{"type":50,"value":2143}," A direct ",{"type":45,"tag":58,"props":2145,"children":2147},{"className":2146},[],[2148],{"type":50,"value":2149},"${{ inputs.bump }}",{"type":50,"value":1409},{"type":45,"tag":58,"props":2152,"children":2154},{"className":2153},[],[2155],{"type":50,"value":151},{"type":50,"value":2157}," is still poor shell hygiene, but ",{"type":45,"tag":58,"props":2159,"children":2161},{"className":2160},[],[2162],{"type":50,"value":2163},"type: choice",{"type":50,"value":2165}," with only ",{"type":45,"tag":58,"props":2167,"children":2169},{"className":2168},[],[2170],{"type":50,"value":2171},"minor",{"type":50,"value":170},{"type":45,"tag":58,"props":2174,"children":2176},{"className":2175},[],[2177],{"type":50,"value":2178},"patch",{"type":50,"value":2180},", and ",{"type":45,"tag":58,"props":2182,"children":2184},{"className":2183},[],[2185],{"type":50,"value":2186},"major",{"type":50,"value":2188}," is not the same as free-form command injection. Verify whether API dispatch, a caller workflow, or a later refactor can bypass the finite set before reporting.",{"type":45,"tag":67,"props":2190,"children":2192},{"id":2191},"canonical-patterns",[2193],{"type":50,"value":2194},"Canonical Patterns",{"type":45,"tag":830,"props":2196,"children":2198},{"id":2197},"pattern-pwn-request-through-explicit-pr-checkout",[2199],{"type":50,"value":2200},"Pattern: Pwn request through explicit PR checkout",{"type":45,"tag":46,"props":2202,"children":2203},{},[2204],{"type":45,"tag":95,"props":2205,"children":2206},{},[2207],{"type":50,"value":2208},"GitHub Actions - bad:",{"type":45,"tag":2210,"props":2211,"children":2216},"pre",{"className":2212,"code":2213,"language":2214,"meta":2215,"style":2215},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","on: pull_request_target\npermissions: write-all\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}\n      - run: npm install\n      - run: npm test\n","yaml","",[2217],{"type":45,"tag":58,"props":2218,"children":2219},{"__ignoreMap":2215},[2220,2244,2263,2276,2289,2307,2320,2343,2356,2374,2396],{"type":45,"tag":2221,"props":2222,"children":2225},"span",{"class":2223,"line":2224},"line",1,[2226,2232,2238],{"type":45,"tag":2221,"props":2227,"children":2229},{"style":2228},"--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC",[2230],{"type":50,"value":2231},"on",{"type":45,"tag":2221,"props":2233,"children":2235},{"style":2234},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[2236],{"type":50,"value":2237},":",{"type":45,"tag":2221,"props":2239,"children":2241},{"style":2240},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[2242],{"type":50,"value":2243}," pull_request_target\n",{"type":45,"tag":2221,"props":2245,"children":2247},{"class":2223,"line":2246},2,[2248,2254,2258],{"type":45,"tag":2221,"props":2249,"children":2251},{"style":2250},"--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178",[2252],{"type":50,"value":2253},"permissions",{"type":45,"tag":2221,"props":2255,"children":2256},{"style":2234},[2257],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2259,"children":2260},{"style":2240},[2261],{"type":50,"value":2262}," write-all\n",{"type":45,"tag":2221,"props":2264,"children":2265},{"class":2223,"line":31},[2266,2271],{"type":45,"tag":2221,"props":2267,"children":2268},{"style":2250},[2269],{"type":50,"value":2270},"jobs",{"type":45,"tag":2221,"props":2272,"children":2273},{"style":2234},[2274],{"type":50,"value":2275},":\n",{"type":45,"tag":2221,"props":2277,"children":2279},{"class":2223,"line":2278},4,[2280,2285],{"type":45,"tag":2221,"props":2281,"children":2282},{"style":2250},[2283],{"type":50,"value":2284},"  test",{"type":45,"tag":2221,"props":2286,"children":2287},{"style":2234},[2288],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2290,"children":2292},{"class":2223,"line":2291},5,[2293,2298,2302],{"type":45,"tag":2221,"props":2294,"children":2295},{"style":2250},[2296],{"type":50,"value":2297},"    runs-on",{"type":45,"tag":2221,"props":2299,"children":2300},{"style":2234},[2301],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2303,"children":2304},{"style":2240},[2305],{"type":50,"value":2306}," ubuntu-latest\n",{"type":45,"tag":2221,"props":2308,"children":2310},{"class":2223,"line":2309},6,[2311,2316],{"type":45,"tag":2221,"props":2312,"children":2313},{"style":2250},[2314],{"type":50,"value":2315},"    steps",{"type":45,"tag":2221,"props":2317,"children":2318},{"style":2234},[2319],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2321,"children":2323},{"class":2223,"line":2322},7,[2324,2329,2334,2338],{"type":45,"tag":2221,"props":2325,"children":2326},{"style":2234},[2327],{"type":50,"value":2328},"      -",{"type":45,"tag":2221,"props":2330,"children":2331},{"style":2250},[2332],{"type":50,"value":2333}," uses",{"type":45,"tag":2221,"props":2335,"children":2336},{"style":2234},[2337],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2339,"children":2340},{"style":2240},[2341],{"type":50,"value":2342}," actions\u002Fcheckout@v4\n",{"type":45,"tag":2221,"props":2344,"children":2346},{"class":2223,"line":2345},8,[2347,2352],{"type":45,"tag":2221,"props":2348,"children":2349},{"style":2250},[2350],{"type":50,"value":2351},"        with",{"type":45,"tag":2221,"props":2353,"children":2354},{"style":2234},[2355],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2357,"children":2359},{"class":2223,"line":2358},9,[2360,2365,2369],{"type":45,"tag":2221,"props":2361,"children":2362},{"style":2250},[2363],{"type":50,"value":2364},"          ref",{"type":45,"tag":2221,"props":2366,"children":2367},{"style":2234},[2368],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2370,"children":2371},{"style":2240},[2372],{"type":50,"value":2373}," ${{ github.event.pull_request.head.sha }}\n",{"type":45,"tag":2221,"props":2375,"children":2377},{"class":2223,"line":2376},10,[2378,2382,2387,2391],{"type":45,"tag":2221,"props":2379,"children":2380},{"style":2234},[2381],{"type":50,"value":2328},{"type":45,"tag":2221,"props":2383,"children":2384},{"style":2250},[2385],{"type":50,"value":2386}," run",{"type":45,"tag":2221,"props":2388,"children":2389},{"style":2234},[2390],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2392,"children":2393},{"style":2240},[2394],{"type":50,"value":2395}," npm install\n",{"type":45,"tag":2221,"props":2397,"children":2399},{"class":2223,"line":2398},11,[2400,2404,2408,2412],{"type":45,"tag":2221,"props":2401,"children":2402},{"style":2234},[2403],{"type":50,"value":2328},{"type":45,"tag":2221,"props":2405,"children":2406},{"style":2250},[2407],{"type":50,"value":2386},{"type":45,"tag":2221,"props":2409,"children":2410},{"style":2234},[2411],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2413,"children":2414},{"style":2240},[2415],{"type":50,"value":2416}," npm test\n",{"type":45,"tag":46,"props":2418,"children":2419},{},[2420],{"type":50,"value":2421},"The fork controls package scripts and test code while the job has trusted-repository permissions.",{"type":45,"tag":46,"props":2423,"children":2424},{},[2425],{"type":45,"tag":95,"props":2426,"children":2427},{},[2428],{"type":50,"value":2429},"GitHub Actions - safe:",{"type":45,"tag":2210,"props":2431,"children":2433},{"className":2212,"code":2432,"language":2214,"meta":2215,"style":2215},"on: pull_request\npermissions:\n  contents: read\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          persist-credentials: false\n      - run: npm ci\n      - run: npm test\n",[2434],{"type":45,"tag":58,"props":2435,"children":2436},{"__ignoreMap":2215},[2437,2453,2464,2481,2492,2503,2518,2529,2548,2559,2576,2596],{"type":45,"tag":2221,"props":2438,"children":2439},{"class":2223,"line":2224},[2440,2444,2448],{"type":45,"tag":2221,"props":2441,"children":2442},{"style":2228},[2443],{"type":50,"value":2231},{"type":45,"tag":2221,"props":2445,"children":2446},{"style":2234},[2447],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2449,"children":2450},{"style":2240},[2451],{"type":50,"value":2452}," pull_request\n",{"type":45,"tag":2221,"props":2454,"children":2455},{"class":2223,"line":2246},[2456,2460],{"type":45,"tag":2221,"props":2457,"children":2458},{"style":2250},[2459],{"type":50,"value":2253},{"type":45,"tag":2221,"props":2461,"children":2462},{"style":2234},[2463],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2465,"children":2466},{"class":2223,"line":31},[2467,2472,2476],{"type":45,"tag":2221,"props":2468,"children":2469},{"style":2250},[2470],{"type":50,"value":2471},"  contents",{"type":45,"tag":2221,"props":2473,"children":2474},{"style":2234},[2475],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2477,"children":2478},{"style":2240},[2479],{"type":50,"value":2480}," read\n",{"type":45,"tag":2221,"props":2482,"children":2483},{"class":2223,"line":2278},[2484,2488],{"type":45,"tag":2221,"props":2485,"children":2486},{"style":2250},[2487],{"type":50,"value":2270},{"type":45,"tag":2221,"props":2489,"children":2490},{"style":2234},[2491],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2493,"children":2494},{"class":2223,"line":2291},[2495,2499],{"type":45,"tag":2221,"props":2496,"children":2497},{"style":2250},[2498],{"type":50,"value":2284},{"type":45,"tag":2221,"props":2500,"children":2501},{"style":2234},[2502],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2504,"children":2505},{"class":2223,"line":2309},[2506,2510,2514],{"type":45,"tag":2221,"props":2507,"children":2508},{"style":2250},[2509],{"type":50,"value":2297},{"type":45,"tag":2221,"props":2511,"children":2512},{"style":2234},[2513],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2515,"children":2516},{"style":2240},[2517],{"type":50,"value":2306},{"type":45,"tag":2221,"props":2519,"children":2520},{"class":2223,"line":2322},[2521,2525],{"type":45,"tag":2221,"props":2522,"children":2523},{"style":2250},[2524],{"type":50,"value":2315},{"type":45,"tag":2221,"props":2526,"children":2527},{"style":2234},[2528],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2530,"children":2531},{"class":2223,"line":2345},[2532,2536,2540,2544],{"type":45,"tag":2221,"props":2533,"children":2534},{"style":2234},[2535],{"type":50,"value":2328},{"type":45,"tag":2221,"props":2537,"children":2538},{"style":2250},[2539],{"type":50,"value":2333},{"type":45,"tag":2221,"props":2541,"children":2542},{"style":2234},[2543],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2545,"children":2546},{"style":2240},[2547],{"type":50,"value":2342},{"type":45,"tag":2221,"props":2549,"children":2550},{"class":2223,"line":2358},[2551,2555],{"type":45,"tag":2221,"props":2552,"children":2553},{"style":2250},[2554],{"type":50,"value":2351},{"type":45,"tag":2221,"props":2556,"children":2557},{"style":2234},[2558],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2560,"children":2561},{"class":2223,"line":2376},[2562,2567,2571],{"type":45,"tag":2221,"props":2563,"children":2564},{"style":2250},[2565],{"type":50,"value":2566},"          persist-credentials",{"type":45,"tag":2221,"props":2568,"children":2569},{"style":2234},[2570],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2572,"children":2573},{"style":2228},[2574],{"type":50,"value":2575}," false\n",{"type":45,"tag":2221,"props":2577,"children":2578},{"class":2223,"line":2398},[2579,2583,2587,2591],{"type":45,"tag":2221,"props":2580,"children":2581},{"style":2234},[2582],{"type":50,"value":2328},{"type":45,"tag":2221,"props":2584,"children":2585},{"style":2250},[2586],{"type":50,"value":2386},{"type":45,"tag":2221,"props":2588,"children":2589},{"style":2234},[2590],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2592,"children":2593},{"style":2240},[2594],{"type":50,"value":2595}," npm ci\n",{"type":45,"tag":2221,"props":2597,"children":2599},{"class":2223,"line":2598},12,[2600,2604,2608,2612],{"type":45,"tag":2221,"props":2601,"children":2602},{"style":2234},[2603],{"type":50,"value":2328},{"type":45,"tag":2221,"props":2605,"children":2606},{"style":2250},[2607],{"type":50,"value":2386},{"type":45,"tag":2221,"props":2609,"children":2610},{"style":2234},[2611],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2613,"children":2614},{"style":2240},[2615],{"type":50,"value":2416},{"type":45,"tag":46,"props":2617,"children":2618},{},[2619,2621,2626],{"type":50,"value":2620},"Run untrusted code in an unprivileged PR workflow. Use a separate ",{"type":45,"tag":58,"props":2622,"children":2624},{"className":2623},[],[2625],{"type":50,"value":107},{"type":50,"value":2627}," job for trusted reporting, and treat artifacts as untrusted data.",{"type":45,"tag":830,"props":2629,"children":2631},{"id":2630},"pattern-shell-expression-injection",[2632],{"type":50,"value":2633},"Pattern: Shell expression injection",{"type":45,"tag":46,"props":2635,"children":2636},{},[2637],{"type":45,"tag":95,"props":2638,"children":2639},{},[2640],{"type":50,"value":2208},{"type":45,"tag":2210,"props":2642,"children":2644},{"className":2212,"code":2643,"language":2214,"meta":2215,"style":2215},"on: pull_request\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - run: echo \"Checking ${{ github.event.pull_request.title }}\"\n",[2645],{"type":45,"tag":58,"props":2646,"children":2647},{"__ignoreMap":2215},[2648,2663,2674,2686,2701,2712],{"type":45,"tag":2221,"props":2649,"children":2650},{"class":2223,"line":2224},[2651,2655,2659],{"type":45,"tag":2221,"props":2652,"children":2653},{"style":2228},[2654],{"type":50,"value":2231},{"type":45,"tag":2221,"props":2656,"children":2657},{"style":2234},[2658],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2660,"children":2661},{"style":2240},[2662],{"type":50,"value":2452},{"type":45,"tag":2221,"props":2664,"children":2665},{"class":2223,"line":2246},[2666,2670],{"type":45,"tag":2221,"props":2667,"children":2668},{"style":2250},[2669],{"type":50,"value":2270},{"type":45,"tag":2221,"props":2671,"children":2672},{"style":2234},[2673],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2675,"children":2676},{"class":2223,"line":31},[2677,2682],{"type":45,"tag":2221,"props":2678,"children":2679},{"style":2250},[2680],{"type":50,"value":2681},"  lint",{"type":45,"tag":2221,"props":2683,"children":2684},{"style":2234},[2685],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2687,"children":2688},{"class":2223,"line":2278},[2689,2693,2697],{"type":45,"tag":2221,"props":2690,"children":2691},{"style":2250},[2692],{"type":50,"value":2297},{"type":45,"tag":2221,"props":2694,"children":2695},{"style":2234},[2696],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2698,"children":2699},{"style":2240},[2700],{"type":50,"value":2306},{"type":45,"tag":2221,"props":2702,"children":2703},{"class":2223,"line":2291},[2704,2708],{"type":45,"tag":2221,"props":2705,"children":2706},{"style":2250},[2707],{"type":50,"value":2315},{"type":45,"tag":2221,"props":2709,"children":2710},{"style":2234},[2711],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2713,"children":2714},{"class":2223,"line":2309},[2715,2719,2723,2727],{"type":45,"tag":2221,"props":2716,"children":2717},{"style":2234},[2718],{"type":50,"value":2328},{"type":45,"tag":2221,"props":2720,"children":2721},{"style":2250},[2722],{"type":50,"value":2386},{"type":45,"tag":2221,"props":2724,"children":2725},{"style":2234},[2726],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2728,"children":2729},{"style":2240},[2730],{"type":50,"value":2731}," echo \"Checking ${{ github.event.pull_request.title }}\"\n",{"type":45,"tag":46,"props":2733,"children":2734},{},[2735],{"type":50,"value":2736},"A PR title can break out of the shell string.",{"type":45,"tag":46,"props":2738,"children":2739},{},[2740],{"type":45,"tag":95,"props":2741,"children":2742},{},[2743],{"type":50,"value":2429},{"type":45,"tag":2210,"props":2745,"children":2747},{"className":2212,"code":2746,"language":2214,"meta":2215,"style":2215},"on: pull_request\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - env:\n          PR_TITLE: ${{ github.event.pull_request.title }}\n        run: printf '%s\\n' \"$PR_TITLE\"\n",[2748],{"type":45,"tag":58,"props":2749,"children":2750},{"__ignoreMap":2215},[2751,2766,2777,2788,2803,2814,2830,2847],{"type":45,"tag":2221,"props":2752,"children":2753},{"class":2223,"line":2224},[2754,2758,2762],{"type":45,"tag":2221,"props":2755,"children":2756},{"style":2228},[2757],{"type":50,"value":2231},{"type":45,"tag":2221,"props":2759,"children":2760},{"style":2234},[2761],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2763,"children":2764},{"style":2240},[2765],{"type":50,"value":2452},{"type":45,"tag":2221,"props":2767,"children":2768},{"class":2223,"line":2246},[2769,2773],{"type":45,"tag":2221,"props":2770,"children":2771},{"style":2250},[2772],{"type":50,"value":2270},{"type":45,"tag":2221,"props":2774,"children":2775},{"style":2234},[2776],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2778,"children":2779},{"class":2223,"line":31},[2780,2784],{"type":45,"tag":2221,"props":2781,"children":2782},{"style":2250},[2783],{"type":50,"value":2681},{"type":45,"tag":2221,"props":2785,"children":2786},{"style":2234},[2787],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2789,"children":2790},{"class":2223,"line":2278},[2791,2795,2799],{"type":45,"tag":2221,"props":2792,"children":2793},{"style":2250},[2794],{"type":50,"value":2297},{"type":45,"tag":2221,"props":2796,"children":2797},{"style":2234},[2798],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2800,"children":2801},{"style":2240},[2802],{"type":50,"value":2306},{"type":45,"tag":2221,"props":2804,"children":2805},{"class":2223,"line":2291},[2806,2810],{"type":45,"tag":2221,"props":2807,"children":2808},{"style":2250},[2809],{"type":50,"value":2315},{"type":45,"tag":2221,"props":2811,"children":2812},{"style":2234},[2813],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2815,"children":2816},{"class":2223,"line":2309},[2817,2821,2826],{"type":45,"tag":2221,"props":2818,"children":2819},{"style":2234},[2820],{"type":50,"value":2328},{"type":45,"tag":2221,"props":2822,"children":2823},{"style":2250},[2824],{"type":50,"value":2825}," env",{"type":45,"tag":2221,"props":2827,"children":2828},{"style":2234},[2829],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2831,"children":2832},{"class":2223,"line":2322},[2833,2838,2842],{"type":45,"tag":2221,"props":2834,"children":2835},{"style":2250},[2836],{"type":50,"value":2837},"          PR_TITLE",{"type":45,"tag":2221,"props":2839,"children":2840},{"style":2234},[2841],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2843,"children":2844},{"style":2240},[2845],{"type":50,"value":2846}," ${{ github.event.pull_request.title }}\n",{"type":45,"tag":2221,"props":2848,"children":2849},{"class":2223,"line":2345},[2850,2855,2859],{"type":45,"tag":2221,"props":2851,"children":2852},{"style":2250},[2853],{"type":50,"value":2854},"        run",{"type":45,"tag":2221,"props":2856,"children":2857},{"style":2234},[2858],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2860,"children":2861},{"style":2240},[2862],{"type":50,"value":2863}," printf '%s\\n' \"$PR_TITLE\"\n",{"type":45,"tag":46,"props":2865,"children":2866},{},[2867],{"type":50,"value":2868},"Pass untrusted strings through environment variables and quote them in the shell.",{"type":45,"tag":830,"props":2870,"children":2872},{"id":2871},"pattern-manual-workflow-input-command-injection",[2873],{"type":50,"value":2874},"Pattern: Manual workflow input command injection",{"type":45,"tag":46,"props":2876,"children":2877},{},[2878],{"type":45,"tag":95,"props":2879,"children":2880},{},[2881],{"type":50,"value":2208},{"type":45,"tag":2210,"props":2883,"children":2885},{"className":2212,"code":2884,"language":2214,"meta":2215,"style":2215},"on:\n  workflow_dispatch:\n    inputs:\n      bump:\n        type: string\n        required: true\npermissions:\n  contents: write\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - run: |\n          CURRENT=$(node -p \"require('.\u002Fpackage.json').version\")\n          NEW=$(npx semver -i ${{ inputs.bump }} $CURRENT)\n",[2886],{"type":45,"tag":58,"props":2887,"children":2888},{"__ignoreMap":2215},[2889,2900,2912,2924,2936,2953,2970,2981,2997,3008,3020,3035,3046,3068,3077],{"type":45,"tag":2221,"props":2890,"children":2891},{"class":2223,"line":2224},[2892,2896],{"type":45,"tag":2221,"props":2893,"children":2894},{"style":2228},[2895],{"type":50,"value":2231},{"type":45,"tag":2221,"props":2897,"children":2898},{"style":2234},[2899],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2901,"children":2902},{"class":2223,"line":2246},[2903,2908],{"type":45,"tag":2221,"props":2904,"children":2905},{"style":2250},[2906],{"type":50,"value":2907},"  workflow_dispatch",{"type":45,"tag":2221,"props":2909,"children":2910},{"style":2234},[2911],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2913,"children":2914},{"class":2223,"line":31},[2915,2920],{"type":45,"tag":2221,"props":2916,"children":2917},{"style":2250},[2918],{"type":50,"value":2919},"    inputs",{"type":45,"tag":2221,"props":2921,"children":2922},{"style":2234},[2923],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2925,"children":2926},{"class":2223,"line":2278},[2927,2932],{"type":45,"tag":2221,"props":2928,"children":2929},{"style":2250},[2930],{"type":50,"value":2931},"      bump",{"type":45,"tag":2221,"props":2933,"children":2934},{"style":2234},[2935],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2937,"children":2938},{"class":2223,"line":2291},[2939,2944,2948],{"type":45,"tag":2221,"props":2940,"children":2941},{"style":2250},[2942],{"type":50,"value":2943},"        type",{"type":45,"tag":2221,"props":2945,"children":2946},{"style":2234},[2947],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2949,"children":2950},{"style":2240},[2951],{"type":50,"value":2952}," string\n",{"type":45,"tag":2221,"props":2954,"children":2955},{"class":2223,"line":2309},[2956,2961,2965],{"type":45,"tag":2221,"props":2957,"children":2958},{"style":2250},[2959],{"type":50,"value":2960},"        required",{"type":45,"tag":2221,"props":2962,"children":2963},{"style":2234},[2964],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2966,"children":2967},{"style":2228},[2968],{"type":50,"value":2969}," true\n",{"type":45,"tag":2221,"props":2971,"children":2972},{"class":2223,"line":2322},[2973,2977],{"type":45,"tag":2221,"props":2974,"children":2975},{"style":2250},[2976],{"type":50,"value":2253},{"type":45,"tag":2221,"props":2978,"children":2979},{"style":2234},[2980],{"type":50,"value":2275},{"type":45,"tag":2221,"props":2982,"children":2983},{"class":2223,"line":2345},[2984,2988,2992],{"type":45,"tag":2221,"props":2985,"children":2986},{"style":2250},[2987],{"type":50,"value":2471},{"type":45,"tag":2221,"props":2989,"children":2990},{"style":2234},[2991],{"type":50,"value":2237},{"type":45,"tag":2221,"props":2993,"children":2994},{"style":2240},[2995],{"type":50,"value":2996}," write\n",{"type":45,"tag":2221,"props":2998,"children":2999},{"class":2223,"line":2358},[3000,3004],{"type":45,"tag":2221,"props":3001,"children":3002},{"style":2250},[3003],{"type":50,"value":2270},{"type":45,"tag":2221,"props":3005,"children":3006},{"style":2234},[3007],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3009,"children":3010},{"class":2223,"line":2376},[3011,3016],{"type":45,"tag":2221,"props":3012,"children":3013},{"style":2250},[3014],{"type":50,"value":3015},"  release",{"type":45,"tag":2221,"props":3017,"children":3018},{"style":2234},[3019],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3021,"children":3022},{"class":2223,"line":2398},[3023,3027,3031],{"type":45,"tag":2221,"props":3024,"children":3025},{"style":2250},[3026],{"type":50,"value":2297},{"type":45,"tag":2221,"props":3028,"children":3029},{"style":2234},[3030],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3032,"children":3033},{"style":2240},[3034],{"type":50,"value":2306},{"type":45,"tag":2221,"props":3036,"children":3037},{"class":2223,"line":2598},[3038,3042],{"type":45,"tag":2221,"props":3039,"children":3040},{"style":2250},[3041],{"type":50,"value":2315},{"type":45,"tag":2221,"props":3043,"children":3044},{"style":2234},[3045],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3047,"children":3049},{"class":2223,"line":3048},13,[3050,3054,3058,3062],{"type":45,"tag":2221,"props":3051,"children":3052},{"style":2234},[3053],{"type":50,"value":2328},{"type":45,"tag":2221,"props":3055,"children":3056},{"style":2250},[3057],{"type":50,"value":2386},{"type":45,"tag":2221,"props":3059,"children":3060},{"style":2234},[3061],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3063,"children":3065},{"style":3064},"--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic",[3066],{"type":50,"value":3067}," |\n",{"type":45,"tag":2221,"props":3069,"children":3071},{"class":2223,"line":3070},14,[3072],{"type":45,"tag":2221,"props":3073,"children":3074},{"style":2240},[3075],{"type":50,"value":3076},"          CURRENT=$(node -p \"require('.\u002Fpackage.json').version\")\n",{"type":45,"tag":2221,"props":3078,"children":3080},{"class":2223,"line":3079},15,[3081],{"type":45,"tag":2221,"props":3082,"children":3083},{"style":2240},[3084],{"type":50,"value":3085},"          NEW=$(npx semver -i ${{ inputs.bump }} $CURRENT)\n",{"type":45,"tag":46,"props":3087,"children":3088},{},[3089,3091,3097],{"type":50,"value":3090},"The manual caller controls ",{"type":45,"tag":58,"props":3092,"children":3094},{"className":3093},[],[3095],{"type":50,"value":3096},"inputs.bump",{"type":50,"value":3098},"; GitHub expands it into the temporary shell script before execution. In a release job, that is arbitrary command execution under release workflow privileges.",{"type":45,"tag":46,"props":3100,"children":3101},{},[3102],{"type":45,"tag":95,"props":3103,"children":3104},{},[3105],{"type":50,"value":2429},{"type":45,"tag":2210,"props":3107,"children":3109},{"className":2212,"code":3108,"language":2214,"meta":2215,"style":2215},"on:\n  workflow_dispatch:\n    inputs:\n      bump:\n        type: choice\n        required: true\n        options: [major, minor, patch, prerelease]\npermissions:\n  contents: write\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - env:\n          BUMP: ${{ inputs.bump }}\n        run: |\n          case \"$BUMP\" in\n            major|minor|patch|prerelease) ;;\n            *) exit 1 ;;\n          esac\n          CURRENT=$(node -p \"require('.\u002Fpackage.json').version\")\n          NEW=$(npx semver -i \"$BUMP\" \"$CURRENT\")\n",[3110],{"type":45,"tag":58,"props":3111,"children":3112},{"__ignoreMap":2215},[3113,3124,3135,3146,3157,3173,3188,3242,3253,3268,3279,3290,3305,3316,3331,3348,3364,3373,3382,3391,3400,3408],{"type":45,"tag":2221,"props":3114,"children":3115},{"class":2223,"line":2224},[3116,3120],{"type":45,"tag":2221,"props":3117,"children":3118},{"style":2228},[3119],{"type":50,"value":2231},{"type":45,"tag":2221,"props":3121,"children":3122},{"style":2234},[3123],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3125,"children":3126},{"class":2223,"line":2246},[3127,3131],{"type":45,"tag":2221,"props":3128,"children":3129},{"style":2250},[3130],{"type":50,"value":2907},{"type":45,"tag":2221,"props":3132,"children":3133},{"style":2234},[3134],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3136,"children":3137},{"class":2223,"line":31},[3138,3142],{"type":45,"tag":2221,"props":3139,"children":3140},{"style":2250},[3141],{"type":50,"value":2919},{"type":45,"tag":2221,"props":3143,"children":3144},{"style":2234},[3145],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3147,"children":3148},{"class":2223,"line":2278},[3149,3153],{"type":45,"tag":2221,"props":3150,"children":3151},{"style":2250},[3152],{"type":50,"value":2931},{"type":45,"tag":2221,"props":3154,"children":3155},{"style":2234},[3156],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3158,"children":3159},{"class":2223,"line":2291},[3160,3164,3168],{"type":45,"tag":2221,"props":3161,"children":3162},{"style":2250},[3163],{"type":50,"value":2943},{"type":45,"tag":2221,"props":3165,"children":3166},{"style":2234},[3167],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3169,"children":3170},{"style":2240},[3171],{"type":50,"value":3172}," choice\n",{"type":45,"tag":2221,"props":3174,"children":3175},{"class":2223,"line":2309},[3176,3180,3184],{"type":45,"tag":2221,"props":3177,"children":3178},{"style":2250},[3179],{"type":50,"value":2960},{"type":45,"tag":2221,"props":3181,"children":3182},{"style":2234},[3183],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3185,"children":3186},{"style":2228},[3187],{"type":50,"value":2969},{"type":45,"tag":2221,"props":3189,"children":3190},{"class":2223,"line":2322},[3191,3196,3200,3205,3209,3214,3219,3223,3228,3232,3237],{"type":45,"tag":2221,"props":3192,"children":3193},{"style":2250},[3194],{"type":50,"value":3195},"        options",{"type":45,"tag":2221,"props":3197,"children":3198},{"style":2234},[3199],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3201,"children":3202},{"style":2234},[3203],{"type":50,"value":3204}," [",{"type":45,"tag":2221,"props":3206,"children":3207},{"style":2240},[3208],{"type":50,"value":2186},{"type":45,"tag":2221,"props":3210,"children":3211},{"style":2234},[3212],{"type":50,"value":3213},",",{"type":45,"tag":2221,"props":3215,"children":3216},{"style":2240},[3217],{"type":50,"value":3218}," minor",{"type":45,"tag":2221,"props":3220,"children":3221},{"style":2234},[3222],{"type":50,"value":3213},{"type":45,"tag":2221,"props":3224,"children":3225},{"style":2240},[3226],{"type":50,"value":3227}," patch",{"type":45,"tag":2221,"props":3229,"children":3230},{"style":2234},[3231],{"type":50,"value":3213},{"type":45,"tag":2221,"props":3233,"children":3234},{"style":2240},[3235],{"type":50,"value":3236}," prerelease",{"type":45,"tag":2221,"props":3238,"children":3239},{"style":2234},[3240],{"type":50,"value":3241},"]\n",{"type":45,"tag":2221,"props":3243,"children":3244},{"class":2223,"line":2345},[3245,3249],{"type":45,"tag":2221,"props":3246,"children":3247},{"style":2250},[3248],{"type":50,"value":2253},{"type":45,"tag":2221,"props":3250,"children":3251},{"style":2234},[3252],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3254,"children":3255},{"class":2223,"line":2358},[3256,3260,3264],{"type":45,"tag":2221,"props":3257,"children":3258},{"style":2250},[3259],{"type":50,"value":2471},{"type":45,"tag":2221,"props":3261,"children":3262},{"style":2234},[3263],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3265,"children":3266},{"style":2240},[3267],{"type":50,"value":2996},{"type":45,"tag":2221,"props":3269,"children":3270},{"class":2223,"line":2376},[3271,3275],{"type":45,"tag":2221,"props":3272,"children":3273},{"style":2250},[3274],{"type":50,"value":2270},{"type":45,"tag":2221,"props":3276,"children":3277},{"style":2234},[3278],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3280,"children":3281},{"class":2223,"line":2398},[3282,3286],{"type":45,"tag":2221,"props":3283,"children":3284},{"style":2250},[3285],{"type":50,"value":3015},{"type":45,"tag":2221,"props":3287,"children":3288},{"style":2234},[3289],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3291,"children":3292},{"class":2223,"line":2598},[3293,3297,3301],{"type":45,"tag":2221,"props":3294,"children":3295},{"style":2250},[3296],{"type":50,"value":2297},{"type":45,"tag":2221,"props":3298,"children":3299},{"style":2234},[3300],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3302,"children":3303},{"style":2240},[3304],{"type":50,"value":2306},{"type":45,"tag":2221,"props":3306,"children":3307},{"class":2223,"line":3048},[3308,3312],{"type":45,"tag":2221,"props":3309,"children":3310},{"style":2250},[3311],{"type":50,"value":2315},{"type":45,"tag":2221,"props":3313,"children":3314},{"style":2234},[3315],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3317,"children":3318},{"class":2223,"line":3070},[3319,3323,3327],{"type":45,"tag":2221,"props":3320,"children":3321},{"style":2234},[3322],{"type":50,"value":2328},{"type":45,"tag":2221,"props":3324,"children":3325},{"style":2250},[3326],{"type":50,"value":2825},{"type":45,"tag":2221,"props":3328,"children":3329},{"style":2234},[3330],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3332,"children":3333},{"class":2223,"line":3079},[3334,3339,3343],{"type":45,"tag":2221,"props":3335,"children":3336},{"style":2250},[3337],{"type":50,"value":3338},"          BUMP",{"type":45,"tag":2221,"props":3340,"children":3341},{"style":2234},[3342],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3344,"children":3345},{"style":2240},[3346],{"type":50,"value":3347}," ${{ inputs.bump }}\n",{"type":45,"tag":2221,"props":3349,"children":3351},{"class":2223,"line":3350},16,[3352,3356,3360],{"type":45,"tag":2221,"props":3353,"children":3354},{"style":2250},[3355],{"type":50,"value":2854},{"type":45,"tag":2221,"props":3357,"children":3358},{"style":2234},[3359],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3361,"children":3362},{"style":3064},[3363],{"type":50,"value":3067},{"type":45,"tag":2221,"props":3365,"children":3367},{"class":2223,"line":3366},17,[3368],{"type":45,"tag":2221,"props":3369,"children":3370},{"style":2240},[3371],{"type":50,"value":3372},"          case \"$BUMP\" in\n",{"type":45,"tag":2221,"props":3374,"children":3376},{"class":2223,"line":3375},18,[3377],{"type":45,"tag":2221,"props":3378,"children":3379},{"style":2240},[3380],{"type":50,"value":3381},"            major|minor|patch|prerelease) ;;\n",{"type":45,"tag":2221,"props":3383,"children":3385},{"class":2223,"line":3384},19,[3386],{"type":45,"tag":2221,"props":3387,"children":3388},{"style":2240},[3389],{"type":50,"value":3390},"            *) exit 1 ;;\n",{"type":45,"tag":2221,"props":3392,"children":3394},{"class":2223,"line":3393},20,[3395],{"type":45,"tag":2221,"props":3396,"children":3397},{"style":2240},[3398],{"type":50,"value":3399},"          esac\n",{"type":45,"tag":2221,"props":3401,"children":3403},{"class":2223,"line":3402},21,[3404],{"type":45,"tag":2221,"props":3405,"children":3406},{"style":2240},[3407],{"type":50,"value":3076},{"type":45,"tag":2221,"props":3409,"children":3411},{"class":2223,"line":3410},22,[3412],{"type":45,"tag":2221,"props":3413,"children":3414},{"style":2240},[3415],{"type":50,"value":3416},"          NEW=$(npx semver -i \"$BUMP\" \"$CURRENT\")\n",{"type":45,"tag":46,"props":3418,"children":3419},{},[3420,3422,3427],{"type":50,"value":3421},"Constrain the input when the domain is finite, pass it through ",{"type":45,"tag":58,"props":3423,"children":3425},{"className":3424},[],[3426],{"type":50,"value":1769},{"type":50,"value":3428},", and quote it at the shell use site.",{"type":45,"tag":830,"props":3430,"children":3432},{"id":3431},"pattern-unauthorized-comment-command",[3433],{"type":50,"value":3434},"Pattern: Unauthorized comment command",{"type":45,"tag":46,"props":3436,"children":3437},{},[3438],{"type":45,"tag":95,"props":3439,"children":3440},{},[3441],{"type":50,"value":2208},{"type":45,"tag":2210,"props":3443,"children":3445},{"className":2212,"code":3444,"language":2214,"meta":2215,"style":2215},"on: issue_comment\njobs:\n  deploy-preview:\n    if: contains(github.event.comment.body, '\u002Fdeploy')\n    runs-on: ubuntu-latest\n    steps:\n      - run: .\u002Fci\u002Fdeploy-preview.sh \"${{ github.event.comment.body }}\"\n",[3446],{"type":45,"tag":58,"props":3447,"children":3448},{"__ignoreMap":2215},[3449,3465,3476,3488,3505,3520,3531],{"type":45,"tag":2221,"props":3450,"children":3451},{"class":2223,"line":2224},[3452,3456,3460],{"type":45,"tag":2221,"props":3453,"children":3454},{"style":2228},[3455],{"type":50,"value":2231},{"type":45,"tag":2221,"props":3457,"children":3458},{"style":2234},[3459],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3461,"children":3462},{"style":2240},[3463],{"type":50,"value":3464}," issue_comment\n",{"type":45,"tag":2221,"props":3466,"children":3467},{"class":2223,"line":2246},[3468,3472],{"type":45,"tag":2221,"props":3469,"children":3470},{"style":2250},[3471],{"type":50,"value":2270},{"type":45,"tag":2221,"props":3473,"children":3474},{"style":2234},[3475],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3477,"children":3478},{"class":2223,"line":31},[3479,3484],{"type":45,"tag":2221,"props":3480,"children":3481},{"style":2250},[3482],{"type":50,"value":3483},"  deploy-preview",{"type":45,"tag":2221,"props":3485,"children":3486},{"style":2234},[3487],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3489,"children":3490},{"class":2223,"line":2278},[3491,3496,3500],{"type":45,"tag":2221,"props":3492,"children":3493},{"style":2250},[3494],{"type":50,"value":3495},"    if",{"type":45,"tag":2221,"props":3497,"children":3498},{"style":2234},[3499],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3501,"children":3502},{"style":2240},[3503],{"type":50,"value":3504}," contains(github.event.comment.body, '\u002Fdeploy')\n",{"type":45,"tag":2221,"props":3506,"children":3507},{"class":2223,"line":2291},[3508,3512,3516],{"type":45,"tag":2221,"props":3509,"children":3510},{"style":2250},[3511],{"type":50,"value":2297},{"type":45,"tag":2221,"props":3513,"children":3514},{"style":2234},[3515],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3517,"children":3518},{"style":2240},[3519],{"type":50,"value":2306},{"type":45,"tag":2221,"props":3521,"children":3522},{"class":2223,"line":2309},[3523,3527],{"type":45,"tag":2221,"props":3524,"children":3525},{"style":2250},[3526],{"type":50,"value":2315},{"type":45,"tag":2221,"props":3528,"children":3529},{"style":2234},[3530],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3532,"children":3533},{"class":2223,"line":2322},[3534,3538,3542,3546],{"type":45,"tag":2221,"props":3535,"children":3536},{"style":2234},[3537],{"type":50,"value":2328},{"type":45,"tag":2221,"props":3539,"children":3540},{"style":2250},[3541],{"type":50,"value":2386},{"type":45,"tag":2221,"props":3543,"children":3544},{"style":2234},[3545],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3547,"children":3548},{"style":2240},[3549],{"type":50,"value":3550}," .\u002Fci\u002Fdeploy-preview.sh \"${{ github.event.comment.body }}\"\n",{"type":45,"tag":46,"props":3552,"children":3553},{},[3554],{"type":50,"value":3555},"Any commenter can trigger privileged deployment logic.",{"type":45,"tag":46,"props":3557,"children":3558},{},[3559],{"type":45,"tag":95,"props":3560,"children":3561},{},[3562],{"type":50,"value":2429},{"type":45,"tag":2210,"props":3564,"children":3566},{"className":2212,"code":3565,"language":2214,"meta":2215,"style":2215},"on: issue_comment\njobs:\n  deploy-preview:\n    if: >\n      contains(github.event.comment.body, '\u002Fdeploy') &&\n      contains(fromJSON('[\"MEMBER\",\"OWNER\",\"COLLABORATOR\"]'), github.event.comment.author_association)\n    permissions:\n      contents: read\n      pull-requests: write\n    runs-on: ubuntu-latest\n    steps:\n      - env:\n          COMMENT_BODY: ${{ github.event.comment.body }}\n        run: .\u002Fci\u002Fdeploy-preview.sh \"$COMMENT_BODY\"\n",[3567],{"type":45,"tag":58,"props":3568,"children":3569},{"__ignoreMap":2215},[3570,3585,3596,3607,3623,3631,3639,3651,3667,3683,3698,3709,3724,3741],{"type":45,"tag":2221,"props":3571,"children":3572},{"class":2223,"line":2224},[3573,3577,3581],{"type":45,"tag":2221,"props":3574,"children":3575},{"style":2228},[3576],{"type":50,"value":2231},{"type":45,"tag":2221,"props":3578,"children":3579},{"style":2234},[3580],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3582,"children":3583},{"style":2240},[3584],{"type":50,"value":3464},{"type":45,"tag":2221,"props":3586,"children":3587},{"class":2223,"line":2246},[3588,3592],{"type":45,"tag":2221,"props":3589,"children":3590},{"style":2250},[3591],{"type":50,"value":2270},{"type":45,"tag":2221,"props":3593,"children":3594},{"style":2234},[3595],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3597,"children":3598},{"class":2223,"line":31},[3599,3603],{"type":45,"tag":2221,"props":3600,"children":3601},{"style":2250},[3602],{"type":50,"value":3483},{"type":45,"tag":2221,"props":3604,"children":3605},{"style":2234},[3606],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3608,"children":3609},{"class":2223,"line":2278},[3610,3614,3618],{"type":45,"tag":2221,"props":3611,"children":3612},{"style":2250},[3613],{"type":50,"value":3495},{"type":45,"tag":2221,"props":3615,"children":3616},{"style":2234},[3617],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3619,"children":3620},{"style":3064},[3621],{"type":50,"value":3622}," >\n",{"type":45,"tag":2221,"props":3624,"children":3625},{"class":2223,"line":2291},[3626],{"type":45,"tag":2221,"props":3627,"children":3628},{"style":2240},[3629],{"type":50,"value":3630},"      contains(github.event.comment.body, '\u002Fdeploy') &&\n",{"type":45,"tag":2221,"props":3632,"children":3633},{"class":2223,"line":2309},[3634],{"type":45,"tag":2221,"props":3635,"children":3636},{"style":2240},[3637],{"type":50,"value":3638},"      contains(fromJSON('[\"MEMBER\",\"OWNER\",\"COLLABORATOR\"]'), github.event.comment.author_association)\n",{"type":45,"tag":2221,"props":3640,"children":3641},{"class":2223,"line":2322},[3642,3647],{"type":45,"tag":2221,"props":3643,"children":3644},{"style":2250},[3645],{"type":50,"value":3646},"    permissions",{"type":45,"tag":2221,"props":3648,"children":3649},{"style":2234},[3650],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3652,"children":3653},{"class":2223,"line":2345},[3654,3659,3663],{"type":45,"tag":2221,"props":3655,"children":3656},{"style":2250},[3657],{"type":50,"value":3658},"      contents",{"type":45,"tag":2221,"props":3660,"children":3661},{"style":2234},[3662],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3664,"children":3665},{"style":2240},[3666],{"type":50,"value":2480},{"type":45,"tag":2221,"props":3668,"children":3669},{"class":2223,"line":2358},[3670,3675,3679],{"type":45,"tag":2221,"props":3671,"children":3672},{"style":2250},[3673],{"type":50,"value":3674},"      pull-requests",{"type":45,"tag":2221,"props":3676,"children":3677},{"style":2234},[3678],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3680,"children":3681},{"style":2240},[3682],{"type":50,"value":2996},{"type":45,"tag":2221,"props":3684,"children":3685},{"class":2223,"line":2376},[3686,3690,3694],{"type":45,"tag":2221,"props":3687,"children":3688},{"style":2250},[3689],{"type":50,"value":2297},{"type":45,"tag":2221,"props":3691,"children":3692},{"style":2234},[3693],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3695,"children":3696},{"style":2240},[3697],{"type":50,"value":2306},{"type":45,"tag":2221,"props":3699,"children":3700},{"class":2223,"line":2398},[3701,3705],{"type":45,"tag":2221,"props":3702,"children":3703},{"style":2250},[3704],{"type":50,"value":2315},{"type":45,"tag":2221,"props":3706,"children":3707},{"style":2234},[3708],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3710,"children":3711},{"class":2223,"line":2598},[3712,3716,3720],{"type":45,"tag":2221,"props":3713,"children":3714},{"style":2234},[3715],{"type":50,"value":2328},{"type":45,"tag":2221,"props":3717,"children":3718},{"style":2250},[3719],{"type":50,"value":2825},{"type":45,"tag":2221,"props":3721,"children":3722},{"style":2234},[3723],{"type":50,"value":2275},{"type":45,"tag":2221,"props":3725,"children":3726},{"class":2223,"line":3048},[3727,3732,3736],{"type":45,"tag":2221,"props":3728,"children":3729},{"style":2250},[3730],{"type":50,"value":3731},"          COMMENT_BODY",{"type":45,"tag":2221,"props":3733,"children":3734},{"style":2234},[3735],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3737,"children":3738},{"style":2240},[3739],{"type":50,"value":3740}," ${{ github.event.comment.body }}\n",{"type":45,"tag":2221,"props":3742,"children":3743},{"class":2223,"line":3070},[3744,3748,3752],{"type":45,"tag":2221,"props":3745,"children":3746},{"style":2250},[3747],{"type":50,"value":2854},{"type":45,"tag":2221,"props":3749,"children":3750},{"style":2234},[3751],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3753,"children":3754},{"style":2240},[3755],{"type":50,"value":3756}," .\u002Fci\u002Fdeploy-preview.sh \"$COMMENT_BODY\"\n",{"type":45,"tag":46,"props":3758,"children":3759},{},[3760],{"type":50,"value":3761},"Authorization and shell quoting both matter.",{"type":45,"tag":830,"props":3763,"children":3765},{"id":3764},"pattern-python-workflow-script-executes-untrusted-config",[3766],{"type":50,"value":3767},"Pattern: Python workflow script executes untrusted config",{"type":45,"tag":46,"props":3769,"children":3770},{},[3771],{"type":45,"tag":95,"props":3772,"children":3773},{},[3774],{"type":50,"value":3775},"Python - bad:",{"type":45,"tag":2210,"props":3777,"children":3781},{"className":3778,"code":3779,"language":3780,"meta":2215,"style":2215},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import yaml\nfrom pathlib import Path\nfrom subprocess import run\n\nconfig = yaml.safe_load(Path(\"ci.yml\").read_text())\nrun(config[\"post_check\"], shell=True, check=True)\n","python",[3782],{"type":45,"tag":58,"props":3783,"children":3784},{"__ignoreMap":2215},[3785,3793,3801,3809,3818,3826],{"type":45,"tag":2221,"props":3786,"children":3787},{"class":2223,"line":2224},[3788],{"type":45,"tag":2221,"props":3789,"children":3790},{},[3791],{"type":50,"value":3792},"import yaml\n",{"type":45,"tag":2221,"props":3794,"children":3795},{"class":2223,"line":2246},[3796],{"type":45,"tag":2221,"props":3797,"children":3798},{},[3799],{"type":50,"value":3800},"from pathlib import Path\n",{"type":45,"tag":2221,"props":3802,"children":3803},{"class":2223,"line":31},[3804],{"type":45,"tag":2221,"props":3805,"children":3806},{},[3807],{"type":50,"value":3808},"from subprocess import run\n",{"type":45,"tag":2221,"props":3810,"children":3811},{"class":2223,"line":2278},[3812],{"type":45,"tag":2221,"props":3813,"children":3815},{"emptyLinePlaceholder":3814},true,[3816],{"type":50,"value":3817},"\n",{"type":45,"tag":2221,"props":3819,"children":3820},{"class":2223,"line":2291},[3821],{"type":45,"tag":2221,"props":3822,"children":3823},{},[3824],{"type":50,"value":3825},"config = yaml.safe_load(Path(\"ci.yml\").read_text())\n",{"type":45,"tag":2221,"props":3827,"children":3828},{"class":2223,"line":2309},[3829],{"type":45,"tag":2221,"props":3830,"children":3831},{},[3832],{"type":50,"value":3833},"run(config[\"post_check\"], shell=True, check=True)\n",{"type":45,"tag":46,"props":3835,"children":3836},{},[3837,3839,3845],{"type":50,"value":3838},"If ",{"type":45,"tag":58,"props":3840,"children":3842},{"className":3841},[],[3843],{"type":50,"value":3844},"ci.yml",{"type":50,"value":3846}," came from a fork checkout in a privileged workflow, the script is a command-execution sink.",{"type":45,"tag":46,"props":3848,"children":3849},{},[3850],{"type":45,"tag":95,"props":3851,"children":3852},{},[3853],{"type":50,"value":3854},"Python - safe:",{"type":45,"tag":2210,"props":3856,"children":3858},{"className":3778,"code":3857,"language":3780,"meta":2215,"style":2215},"import yaml\nfrom pathlib import Path\nfrom subprocess import run\n\nallowed = {\"lint\": [\"npm\", \"run\", \"lint\"], \"test\": [\"npm\", \"test\"]}\nconfig = yaml.safe_load(Path(\"ci.yml\").read_text())\nrun(allowed[config[\"task\"]], check=True)\n",[3859],{"type":45,"tag":58,"props":3860,"children":3861},{"__ignoreMap":2215},[3862,3869,3876,3883,3890,3898,3905],{"type":45,"tag":2221,"props":3863,"children":3864},{"class":2223,"line":2224},[3865],{"type":45,"tag":2221,"props":3866,"children":3867},{},[3868],{"type":50,"value":3792},{"type":45,"tag":2221,"props":3870,"children":3871},{"class":2223,"line":2246},[3872],{"type":45,"tag":2221,"props":3873,"children":3874},{},[3875],{"type":50,"value":3800},{"type":45,"tag":2221,"props":3877,"children":3878},{"class":2223,"line":31},[3879],{"type":45,"tag":2221,"props":3880,"children":3881},{},[3882],{"type":50,"value":3808},{"type":45,"tag":2221,"props":3884,"children":3885},{"class":2223,"line":2278},[3886],{"type":45,"tag":2221,"props":3887,"children":3888},{"emptyLinePlaceholder":3814},[3889],{"type":50,"value":3817},{"type":45,"tag":2221,"props":3891,"children":3892},{"class":2223,"line":2291},[3893],{"type":45,"tag":2221,"props":3894,"children":3895},{},[3896],{"type":50,"value":3897},"allowed = {\"lint\": [\"npm\", \"run\", \"lint\"], \"test\": [\"npm\", \"test\"]}\n",{"type":45,"tag":2221,"props":3899,"children":3900},{"class":2223,"line":2309},[3901],{"type":45,"tag":2221,"props":3902,"children":3903},{},[3904],{"type":50,"value":3825},{"type":45,"tag":2221,"props":3906,"children":3907},{"class":2223,"line":2322},[3908],{"type":45,"tag":2221,"props":3909,"children":3910},{},[3911],{"type":50,"value":3912},"run(allowed[config[\"task\"]], check=True)\n",{"type":45,"tag":46,"props":3914,"children":3915},{},[3916],{"type":50,"value":3917},"Use an allowlist and argv arrays. Do not execute repo-controlled strings.",{"type":45,"tag":830,"props":3919,"children":3921},{"id":3920},"pattern-artipacked-token-leak-through-artifact-upload",[3922],{"type":50,"value":3923},"Pattern: ArtiPACKED token leak through artifact upload",{"type":45,"tag":46,"props":3925,"children":3926},{},[3927],{"type":45,"tag":95,"props":3928,"children":3929},{},[3930],{"type":50,"value":2208},{"type":45,"tag":2210,"props":3932,"children":3934},{"className":2212,"code":3933,"language":2214,"meta":2215,"style":2215},"- uses: actions\u002Fcheckout@v4\n- run: .\u002Fbuild.sh\n- uses: actions\u002Fupload-artifact@v4\n  with:\n    name: build-output\n    path: .\n",[3935],{"type":45,"tag":58,"props":3936,"children":3937},{"__ignoreMap":2215},[3938,3958,3978,3998,4010,4027],{"type":45,"tag":2221,"props":3939,"children":3940},{"class":2223,"line":2224},[3941,3946,3950,3954],{"type":45,"tag":2221,"props":3942,"children":3943},{"style":2234},[3944],{"type":50,"value":3945},"-",{"type":45,"tag":2221,"props":3947,"children":3948},{"style":2250},[3949],{"type":50,"value":2333},{"type":45,"tag":2221,"props":3951,"children":3952},{"style":2234},[3953],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3955,"children":3956},{"style":2240},[3957],{"type":50,"value":2342},{"type":45,"tag":2221,"props":3959,"children":3960},{"class":2223,"line":2246},[3961,3965,3969,3973],{"type":45,"tag":2221,"props":3962,"children":3963},{"style":2234},[3964],{"type":50,"value":3945},{"type":45,"tag":2221,"props":3966,"children":3967},{"style":2250},[3968],{"type":50,"value":2386},{"type":45,"tag":2221,"props":3970,"children":3971},{"style":2234},[3972],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3974,"children":3975},{"style":2240},[3976],{"type":50,"value":3977}," .\u002Fbuild.sh\n",{"type":45,"tag":2221,"props":3979,"children":3980},{"class":2223,"line":31},[3981,3985,3989,3993],{"type":45,"tag":2221,"props":3982,"children":3983},{"style":2234},[3984],{"type":50,"value":3945},{"type":45,"tag":2221,"props":3986,"children":3987},{"style":2250},[3988],{"type":50,"value":2333},{"type":45,"tag":2221,"props":3990,"children":3991},{"style":2234},[3992],{"type":50,"value":2237},{"type":45,"tag":2221,"props":3994,"children":3995},{"style":2240},[3996],{"type":50,"value":3997}," actions\u002Fupload-artifact@v4\n",{"type":45,"tag":2221,"props":3999,"children":4000},{"class":2223,"line":2278},[4001,4006],{"type":45,"tag":2221,"props":4002,"children":4003},{"style":2250},[4004],{"type":50,"value":4005},"  with",{"type":45,"tag":2221,"props":4007,"children":4008},{"style":2234},[4009],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4011,"children":4012},{"class":2223,"line":2291},[4013,4018,4022],{"type":45,"tag":2221,"props":4014,"children":4015},{"style":2250},[4016],{"type":50,"value":4017},"    name",{"type":45,"tag":2221,"props":4019,"children":4020},{"style":2234},[4021],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4023,"children":4024},{"style":2240},[4025],{"type":50,"value":4026}," build-output\n",{"type":45,"tag":2221,"props":4028,"children":4029},{"class":2223,"line":2309},[4030,4035,4039],{"type":45,"tag":2221,"props":4031,"children":4032},{"style":2250},[4033],{"type":50,"value":4034},"    path",{"type":45,"tag":2221,"props":4036,"children":4037},{"style":2234},[4038],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4040,"children":4042},{"style":4041},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[4043],{"type":50,"value":4044}," .\n",{"type":45,"tag":46,"props":4046,"children":4047},{},[4048,4053,4055,4060,4061,4066],{"type":45,"tag":58,"props":4049,"children":4051},{"className":4050},[],[4052],{"type":50,"value":871},{"type":50,"value":4054}," left ",{"type":45,"tag":58,"props":4056,"children":4058},{"className":4057},[],[4059],{"type":50,"value":1334},{"type":50,"value":1409},{"type":45,"tag":58,"props":4062,"children":4064},{"className":4063},[],[4065],{"type":50,"value":1415},{"type":50,"value":4067},". The workspace-root upload publishes the token in a public-repo artifact.",{"type":45,"tag":46,"props":4069,"children":4070},{},[4071],{"type":45,"tag":95,"props":4072,"children":4073},{},[4074],{"type":50,"value":2429},{"type":45,"tag":2210,"props":4076,"children":4078},{"className":2212,"code":4077,"language":2214,"meta":2215,"style":2215},"- uses: actions\u002Fcheckout@v4\n  with:\n    persist-credentials: false\n- run: .\u002Fbuild.sh\n- uses: actions\u002Fupload-artifact@v4\n  with:\n    name: build-output\n    path: dist\u002F\n",[4079],{"type":45,"tag":58,"props":4080,"children":4081},{"__ignoreMap":2215},[4082,4101,4112,4128,4147,4166,4177,4192],{"type":45,"tag":2221,"props":4083,"children":4084},{"class":2223,"line":2224},[4085,4089,4093,4097],{"type":45,"tag":2221,"props":4086,"children":4087},{"style":2234},[4088],{"type":50,"value":3945},{"type":45,"tag":2221,"props":4090,"children":4091},{"style":2250},[4092],{"type":50,"value":2333},{"type":45,"tag":2221,"props":4094,"children":4095},{"style":2234},[4096],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4098,"children":4099},{"style":2240},[4100],{"type":50,"value":2342},{"type":45,"tag":2221,"props":4102,"children":4103},{"class":2223,"line":2246},[4104,4108],{"type":45,"tag":2221,"props":4105,"children":4106},{"style":2250},[4107],{"type":50,"value":4005},{"type":45,"tag":2221,"props":4109,"children":4110},{"style":2234},[4111],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4113,"children":4114},{"class":2223,"line":31},[4115,4120,4124],{"type":45,"tag":2221,"props":4116,"children":4117},{"style":2250},[4118],{"type":50,"value":4119},"    persist-credentials",{"type":45,"tag":2221,"props":4121,"children":4122},{"style":2234},[4123],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4125,"children":4126},{"style":2228},[4127],{"type":50,"value":2575},{"type":45,"tag":2221,"props":4129,"children":4130},{"class":2223,"line":2278},[4131,4135,4139,4143],{"type":45,"tag":2221,"props":4132,"children":4133},{"style":2234},[4134],{"type":50,"value":3945},{"type":45,"tag":2221,"props":4136,"children":4137},{"style":2250},[4138],{"type":50,"value":2386},{"type":45,"tag":2221,"props":4140,"children":4141},{"style":2234},[4142],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4144,"children":4145},{"style":2240},[4146],{"type":50,"value":3977},{"type":45,"tag":2221,"props":4148,"children":4149},{"class":2223,"line":2291},[4150,4154,4158,4162],{"type":45,"tag":2221,"props":4151,"children":4152},{"style":2234},[4153],{"type":50,"value":3945},{"type":45,"tag":2221,"props":4155,"children":4156},{"style":2250},[4157],{"type":50,"value":2333},{"type":45,"tag":2221,"props":4159,"children":4160},{"style":2234},[4161],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4163,"children":4164},{"style":2240},[4165],{"type":50,"value":3997},{"type":45,"tag":2221,"props":4167,"children":4168},{"class":2223,"line":2309},[4169,4173],{"type":45,"tag":2221,"props":4170,"children":4171},{"style":2250},[4172],{"type":50,"value":4005},{"type":45,"tag":2221,"props":4174,"children":4175},{"style":2234},[4176],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4178,"children":4179},{"class":2223,"line":2322},[4180,4184,4188],{"type":45,"tag":2221,"props":4181,"children":4182},{"style":2250},[4183],{"type":50,"value":4017},{"type":45,"tag":2221,"props":4185,"children":4186},{"style":2234},[4187],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4189,"children":4190},{"style":2240},[4191],{"type":50,"value":4026},{"type":45,"tag":2221,"props":4193,"children":4194},{"class":2223,"line":2345},[4195,4199,4203],{"type":45,"tag":2221,"props":4196,"children":4197},{"style":2250},[4198],{"type":50,"value":4034},{"type":45,"tag":2221,"props":4200,"children":4201},{"style":2234},[4202],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4204,"children":4205},{"style":2240},[4206],{"type":50,"value":4207}," dist\u002F\n",{"type":45,"tag":46,"props":4209,"children":4210},{},[4211],{"type":50,"value":4212},"Disable credential persistence and upload only the directory you mean to publish.",{"type":45,"tag":830,"props":4214,"children":4216},{"id":4215},"pattern-actionsgithub-script-expression-injection",[4217],{"type":50,"value":4218},"Pattern: actions\u002Fgithub-script expression injection",{"type":45,"tag":46,"props":4220,"children":4221},{},[4222],{"type":45,"tag":95,"props":4223,"children":4224},{},[4225],{"type":50,"value":2208},{"type":45,"tag":2210,"props":4227,"children":4229},{"className":2212,"code":4228,"language":2214,"meta":2215,"style":2215},"on: issue_comment\njobs:\n  triage:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fgithub-script@v7\n        with:\n          script: |\n            const title = \"${{ github.event.issue.title }}\";\n            await github.rest.issues.createComment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.issue.number,\n              body: `Triaged: ${title}`,\n            });\n",[4230],{"type":45,"tag":58,"props":4231,"children":4232},{"__ignoreMap":2215},[4233,4248,4259,4271,4286,4297,4317,4328,4344,4352,4360,4368,4376,4384,4392],{"type":45,"tag":2221,"props":4234,"children":4235},{"class":2223,"line":2224},[4236,4240,4244],{"type":45,"tag":2221,"props":4237,"children":4238},{"style":2228},[4239],{"type":50,"value":2231},{"type":45,"tag":2221,"props":4241,"children":4242},{"style":2234},[4243],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4245,"children":4246},{"style":2240},[4247],{"type":50,"value":3464},{"type":45,"tag":2221,"props":4249,"children":4250},{"class":2223,"line":2246},[4251,4255],{"type":45,"tag":2221,"props":4252,"children":4253},{"style":2250},[4254],{"type":50,"value":2270},{"type":45,"tag":2221,"props":4256,"children":4257},{"style":2234},[4258],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4260,"children":4261},{"class":2223,"line":31},[4262,4267],{"type":45,"tag":2221,"props":4263,"children":4264},{"style":2250},[4265],{"type":50,"value":4266},"  triage",{"type":45,"tag":2221,"props":4268,"children":4269},{"style":2234},[4270],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4272,"children":4273},{"class":2223,"line":2278},[4274,4278,4282],{"type":45,"tag":2221,"props":4275,"children":4276},{"style":2250},[4277],{"type":50,"value":2297},{"type":45,"tag":2221,"props":4279,"children":4280},{"style":2234},[4281],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4283,"children":4284},{"style":2240},[4285],{"type":50,"value":2306},{"type":45,"tag":2221,"props":4287,"children":4288},{"class":2223,"line":2291},[4289,4293],{"type":45,"tag":2221,"props":4290,"children":4291},{"style":2250},[4292],{"type":50,"value":2315},{"type":45,"tag":2221,"props":4294,"children":4295},{"style":2234},[4296],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4298,"children":4299},{"class":2223,"line":2309},[4300,4304,4308,4312],{"type":45,"tag":2221,"props":4301,"children":4302},{"style":2234},[4303],{"type":50,"value":2328},{"type":45,"tag":2221,"props":4305,"children":4306},{"style":2250},[4307],{"type":50,"value":2333},{"type":45,"tag":2221,"props":4309,"children":4310},{"style":2234},[4311],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4313,"children":4314},{"style":2240},[4315],{"type":50,"value":4316}," actions\u002Fgithub-script@v7\n",{"type":45,"tag":2221,"props":4318,"children":4319},{"class":2223,"line":2322},[4320,4324],{"type":45,"tag":2221,"props":4321,"children":4322},{"style":2250},[4323],{"type":50,"value":2351},{"type":45,"tag":2221,"props":4325,"children":4326},{"style":2234},[4327],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4329,"children":4330},{"class":2223,"line":2345},[4331,4336,4340],{"type":45,"tag":2221,"props":4332,"children":4333},{"style":2250},[4334],{"type":50,"value":4335},"          script",{"type":45,"tag":2221,"props":4337,"children":4338},{"style":2234},[4339],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4341,"children":4342},{"style":3064},[4343],{"type":50,"value":3067},{"type":45,"tag":2221,"props":4345,"children":4346},{"class":2223,"line":2358},[4347],{"type":45,"tag":2221,"props":4348,"children":4349},{"style":2240},[4350],{"type":50,"value":4351},"            const title = \"${{ github.event.issue.title }}\";\n",{"type":45,"tag":2221,"props":4353,"children":4354},{"class":2223,"line":2376},[4355],{"type":45,"tag":2221,"props":4356,"children":4357},{"style":2240},[4358],{"type":50,"value":4359},"            await github.rest.issues.createComment({\n",{"type":45,"tag":2221,"props":4361,"children":4362},{"class":2223,"line":2398},[4363],{"type":45,"tag":2221,"props":4364,"children":4365},{"style":2240},[4366],{"type":50,"value":4367},"              owner: context.repo.owner,\n",{"type":45,"tag":2221,"props":4369,"children":4370},{"class":2223,"line":2598},[4371],{"type":45,"tag":2221,"props":4372,"children":4373},{"style":2240},[4374],{"type":50,"value":4375},"              repo: context.repo.repo,\n",{"type":45,"tag":2221,"props":4377,"children":4378},{"class":2223,"line":3048},[4379],{"type":45,"tag":2221,"props":4380,"children":4381},{"style":2240},[4382],{"type":50,"value":4383},"              issue_number: context.issue.number,\n",{"type":45,"tag":2221,"props":4385,"children":4386},{"class":2223,"line":3070},[4387],{"type":45,"tag":2221,"props":4388,"children":4389},{"style":2240},[4390],{"type":50,"value":4391},"              body: `Triaged: ${title}`,\n",{"type":45,"tag":2221,"props":4393,"children":4394},{"class":2223,"line":3079},[4395],{"type":45,"tag":2221,"props":4396,"children":4397},{"style":2240},[4398],{"type":50,"value":4399},"            });\n",{"type":45,"tag":46,"props":4401,"children":4402},{},[4403,4405,4411,4413,4419],{"type":50,"value":4404},"The issue title is concatenated into JavaScript source before evaluation. A title containing ",{"type":45,"tag":58,"props":4406,"children":4408},{"className":4407},[],[4409],{"type":50,"value":4410},"\"); maliciousCode(); (\"",{"type":50,"value":4412}," runs in the action's Node context with the ",{"type":45,"tag":58,"props":4414,"children":4416},{"className":4415},[],[4417],{"type":50,"value":4418},"github",{"type":50,"value":4420}," token. CVE-2026-27701 (LiveCode) shipped this exact shape on PR titles.",{"type":45,"tag":46,"props":4422,"children":4423},{},[4424],{"type":45,"tag":95,"props":4425,"children":4426},{},[4427],{"type":50,"value":2429},{"type":45,"tag":2210,"props":4429,"children":4431},{"className":2212,"code":4430,"language":2214,"meta":2215,"style":2215},"on: issue_comment\njobs:\n  triage:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fgithub-script@v7\n        env:\n          ISSUE_TITLE: ${{ github.event.issue.title }}\n        with:\n          script: |\n            const title = process.env.ISSUE_TITLE;\n            await github.rest.issues.createComment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.issue.number,\n              body: `Triaged: ${title}`,\n            });\n",[4432],{"type":45,"tag":58,"props":4433,"children":4434},{"__ignoreMap":2215},[4435,4450,4461,4472,4487,4498,4517,4529,4546,4557,4572,4580,4587,4594,4601,4608,4615],{"type":45,"tag":2221,"props":4436,"children":4437},{"class":2223,"line":2224},[4438,4442,4446],{"type":45,"tag":2221,"props":4439,"children":4440},{"style":2228},[4441],{"type":50,"value":2231},{"type":45,"tag":2221,"props":4443,"children":4444},{"style":2234},[4445],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4447,"children":4448},{"style":2240},[4449],{"type":50,"value":3464},{"type":45,"tag":2221,"props":4451,"children":4452},{"class":2223,"line":2246},[4453,4457],{"type":45,"tag":2221,"props":4454,"children":4455},{"style":2250},[4456],{"type":50,"value":2270},{"type":45,"tag":2221,"props":4458,"children":4459},{"style":2234},[4460],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4462,"children":4463},{"class":2223,"line":31},[4464,4468],{"type":45,"tag":2221,"props":4465,"children":4466},{"style":2250},[4467],{"type":50,"value":4266},{"type":45,"tag":2221,"props":4469,"children":4470},{"style":2234},[4471],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4473,"children":4474},{"class":2223,"line":2278},[4475,4479,4483],{"type":45,"tag":2221,"props":4476,"children":4477},{"style":2250},[4478],{"type":50,"value":2297},{"type":45,"tag":2221,"props":4480,"children":4481},{"style":2234},[4482],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4484,"children":4485},{"style":2240},[4486],{"type":50,"value":2306},{"type":45,"tag":2221,"props":4488,"children":4489},{"class":2223,"line":2291},[4490,4494],{"type":45,"tag":2221,"props":4491,"children":4492},{"style":2250},[4493],{"type":50,"value":2315},{"type":45,"tag":2221,"props":4495,"children":4496},{"style":2234},[4497],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4499,"children":4500},{"class":2223,"line":2309},[4501,4505,4509,4513],{"type":45,"tag":2221,"props":4502,"children":4503},{"style":2234},[4504],{"type":50,"value":2328},{"type":45,"tag":2221,"props":4506,"children":4507},{"style":2250},[4508],{"type":50,"value":2333},{"type":45,"tag":2221,"props":4510,"children":4511},{"style":2234},[4512],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4514,"children":4515},{"style":2240},[4516],{"type":50,"value":4316},{"type":45,"tag":2221,"props":4518,"children":4519},{"class":2223,"line":2322},[4520,4525],{"type":45,"tag":2221,"props":4521,"children":4522},{"style":2250},[4523],{"type":50,"value":4524},"        env",{"type":45,"tag":2221,"props":4526,"children":4527},{"style":2234},[4528],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4530,"children":4531},{"class":2223,"line":2345},[4532,4537,4541],{"type":45,"tag":2221,"props":4533,"children":4534},{"style":2250},[4535],{"type":50,"value":4536},"          ISSUE_TITLE",{"type":45,"tag":2221,"props":4538,"children":4539},{"style":2234},[4540],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4542,"children":4543},{"style":2240},[4544],{"type":50,"value":4545}," ${{ github.event.issue.title }}\n",{"type":45,"tag":2221,"props":4547,"children":4548},{"class":2223,"line":2358},[4549,4553],{"type":45,"tag":2221,"props":4550,"children":4551},{"style":2250},[4552],{"type":50,"value":2351},{"type":45,"tag":2221,"props":4554,"children":4555},{"style":2234},[4556],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4558,"children":4559},{"class":2223,"line":2376},[4560,4564,4568],{"type":45,"tag":2221,"props":4561,"children":4562},{"style":2250},[4563],{"type":50,"value":4335},{"type":45,"tag":2221,"props":4565,"children":4566},{"style":2234},[4567],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4569,"children":4570},{"style":3064},[4571],{"type":50,"value":3067},{"type":45,"tag":2221,"props":4573,"children":4574},{"class":2223,"line":2398},[4575],{"type":45,"tag":2221,"props":4576,"children":4577},{"style":2240},[4578],{"type":50,"value":4579},"            const title = process.env.ISSUE_TITLE;\n",{"type":45,"tag":2221,"props":4581,"children":4582},{"class":2223,"line":2598},[4583],{"type":45,"tag":2221,"props":4584,"children":4585},{"style":2240},[4586],{"type":50,"value":4359},{"type":45,"tag":2221,"props":4588,"children":4589},{"class":2223,"line":3048},[4590],{"type":45,"tag":2221,"props":4591,"children":4592},{"style":2240},[4593],{"type":50,"value":4367},{"type":45,"tag":2221,"props":4595,"children":4596},{"class":2223,"line":3070},[4597],{"type":45,"tag":2221,"props":4598,"children":4599},{"style":2240},[4600],{"type":50,"value":4375},{"type":45,"tag":2221,"props":4602,"children":4603},{"class":2223,"line":3079},[4604],{"type":45,"tag":2221,"props":4605,"children":4606},{"style":2240},[4607],{"type":50,"value":4383},{"type":45,"tag":2221,"props":4609,"children":4610},{"class":2223,"line":3350},[4611],{"type":45,"tag":2221,"props":4612,"children":4613},{"style":2240},[4614],{"type":50,"value":4391},{"type":45,"tag":2221,"props":4616,"children":4617},{"class":2223,"line":3366},[4618],{"type":45,"tag":2221,"props":4619,"children":4620},{"style":2240},[4621],{"type":50,"value":4399},{"type":45,"tag":46,"props":4623,"children":4624},{},[4625,4627,4632,4634,4640],{"type":50,"value":4626},"Pass untrusted strings through ",{"type":45,"tag":58,"props":4628,"children":4630},{"className":4629},[],[4631],{"type":50,"value":1769},{"type":50,"value":4633}," and read them with ",{"type":45,"tag":58,"props":4635,"children":4637},{"className":4636},[],[4638],{"type":50,"value":4639},"process.env",{"type":50,"value":4641},". The expression is no longer evaluated as code.",{"type":45,"tag":830,"props":4643,"children":4645},{"id":4644},"pattern-reusable-workflow-consumes-undeclared-secrets",[4646],{"type":50,"value":4647},"Pattern: Reusable workflow consumes undeclared secrets",{"type":45,"tag":46,"props":4649,"children":4650},{},[4651],{"type":45,"tag":95,"props":4652,"children":4653},{},[4654],{"type":50,"value":2208},{"type":45,"tag":2210,"props":4656,"children":4658},{"className":2212,"code":4657,"language":2214,"meta":2215,"style":2215},"on:\n  workflow_call:\n    inputs:\n      target:\n        type: string\n        required: true\n\njobs:\n  run:\n    runs-on: ubuntu-latest\n    steps:\n      - run: .\u002Fbin\u002Fdeploy \"$TARGET\"\n        env:\n          TARGET: ${{ inputs.target }}\n          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}\n",[4659],{"type":45,"tag":58,"props":4660,"children":4661},{"__ignoreMap":2215},[4662,4673,4685,4696,4708,4723,4738,4745,4756,4768,4783,4794,4814,4825,4842],{"type":45,"tag":2221,"props":4663,"children":4664},{"class":2223,"line":2224},[4665,4669],{"type":45,"tag":2221,"props":4666,"children":4667},{"style":2228},[4668],{"type":50,"value":2231},{"type":45,"tag":2221,"props":4670,"children":4671},{"style":2234},[4672],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4674,"children":4675},{"class":2223,"line":2246},[4676,4681],{"type":45,"tag":2221,"props":4677,"children":4678},{"style":2250},[4679],{"type":50,"value":4680},"  workflow_call",{"type":45,"tag":2221,"props":4682,"children":4683},{"style":2234},[4684],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4686,"children":4687},{"class":2223,"line":31},[4688,4692],{"type":45,"tag":2221,"props":4689,"children":4690},{"style":2250},[4691],{"type":50,"value":2919},{"type":45,"tag":2221,"props":4693,"children":4694},{"style":2234},[4695],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4697,"children":4698},{"class":2223,"line":2278},[4699,4704],{"type":45,"tag":2221,"props":4700,"children":4701},{"style":2250},[4702],{"type":50,"value":4703},"      target",{"type":45,"tag":2221,"props":4705,"children":4706},{"style":2234},[4707],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4709,"children":4710},{"class":2223,"line":2291},[4711,4715,4719],{"type":45,"tag":2221,"props":4712,"children":4713},{"style":2250},[4714],{"type":50,"value":2943},{"type":45,"tag":2221,"props":4716,"children":4717},{"style":2234},[4718],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4720,"children":4721},{"style":2240},[4722],{"type":50,"value":2952},{"type":45,"tag":2221,"props":4724,"children":4725},{"class":2223,"line":2309},[4726,4730,4734],{"type":45,"tag":2221,"props":4727,"children":4728},{"style":2250},[4729],{"type":50,"value":2960},{"type":45,"tag":2221,"props":4731,"children":4732},{"style":2234},[4733],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4735,"children":4736},{"style":2228},[4737],{"type":50,"value":2969},{"type":45,"tag":2221,"props":4739,"children":4740},{"class":2223,"line":2322},[4741],{"type":45,"tag":2221,"props":4742,"children":4743},{"emptyLinePlaceholder":3814},[4744],{"type":50,"value":3817},{"type":45,"tag":2221,"props":4746,"children":4747},{"class":2223,"line":2345},[4748,4752],{"type":45,"tag":2221,"props":4749,"children":4750},{"style":2250},[4751],{"type":50,"value":2270},{"type":45,"tag":2221,"props":4753,"children":4754},{"style":2234},[4755],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4757,"children":4758},{"class":2223,"line":2358},[4759,4764],{"type":45,"tag":2221,"props":4760,"children":4761},{"style":2250},[4762],{"type":50,"value":4763},"  run",{"type":45,"tag":2221,"props":4765,"children":4766},{"style":2234},[4767],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4769,"children":4770},{"class":2223,"line":2376},[4771,4775,4779],{"type":45,"tag":2221,"props":4772,"children":4773},{"style":2250},[4774],{"type":50,"value":2297},{"type":45,"tag":2221,"props":4776,"children":4777},{"style":2234},[4778],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4780,"children":4781},{"style":2240},[4782],{"type":50,"value":2306},{"type":45,"tag":2221,"props":4784,"children":4785},{"class":2223,"line":2398},[4786,4790],{"type":45,"tag":2221,"props":4787,"children":4788},{"style":2250},[4789],{"type":50,"value":2315},{"type":45,"tag":2221,"props":4791,"children":4792},{"style":2234},[4793],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4795,"children":4796},{"class":2223,"line":2598},[4797,4801,4805,4809],{"type":45,"tag":2221,"props":4798,"children":4799},{"style":2234},[4800],{"type":50,"value":2328},{"type":45,"tag":2221,"props":4802,"children":4803},{"style":2250},[4804],{"type":50,"value":2386},{"type":45,"tag":2221,"props":4806,"children":4807},{"style":2234},[4808],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4810,"children":4811},{"style":2240},[4812],{"type":50,"value":4813}," .\u002Fbin\u002Fdeploy \"$TARGET\"\n",{"type":45,"tag":2221,"props":4815,"children":4816},{"class":2223,"line":3048},[4817,4821],{"type":45,"tag":2221,"props":4818,"children":4819},{"style":2250},[4820],{"type":50,"value":4524},{"type":45,"tag":2221,"props":4822,"children":4823},{"style":2234},[4824],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4826,"children":4827},{"class":2223,"line":3070},[4828,4833,4837],{"type":45,"tag":2221,"props":4829,"children":4830},{"style":2250},[4831],{"type":50,"value":4832},"          TARGET",{"type":45,"tag":2221,"props":4834,"children":4835},{"style":2234},[4836],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4838,"children":4839},{"style":2240},[4840],{"type":50,"value":4841}," ${{ inputs.target }}\n",{"type":45,"tag":2221,"props":4843,"children":4844},{"class":2223,"line":3079},[4845,4850,4854],{"type":45,"tag":2221,"props":4846,"children":4847},{"style":2250},[4848],{"type":50,"value":4849},"          DEPLOY_KEY",{"type":45,"tag":2221,"props":4851,"children":4852},{"style":2234},[4853],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4855,"children":4856},{"style":2240},[4857],{"type":50,"value":4858}," ${{ secrets.DEPLOY_KEY }}\n",{"type":45,"tag":46,"props":4860,"children":4861},{},[4862,4864,4870,4872,4878,4880,4885],{"type":50,"value":4863},"The callee uses ",{"type":45,"tag":58,"props":4865,"children":4867},{"className":4866},[],[4868],{"type":50,"value":4869},"secrets.DEPLOY_KEY",{"type":50,"value":4871}," without declaring it under ",{"type":45,"tag":58,"props":4873,"children":4875},{"className":4874},[],[4876],{"type":50,"value":4877},"workflow_call.secrets",{"type":50,"value":4879},". The workflow only runs when the caller writes ",{"type":45,"tag":58,"props":4881,"children":4883},{"className":4882},[],[4884],{"type":50,"value":1541},{"type":50,"value":4886},"; the secret surface is invisible to anyone reading this file.",{"type":45,"tag":46,"props":4888,"children":4889},{},[4890],{"type":45,"tag":95,"props":4891,"children":4892},{},[4893],{"type":50,"value":2429},{"type":45,"tag":2210,"props":4895,"children":4897},{"className":2212,"code":4896,"language":2214,"meta":2215,"style":2215},"on:\n  workflow_call:\n    inputs:\n      target:\n        type: string\n        required: true\n    secrets:\n      DEPLOY_KEY:\n        required: true\n\njobs:\n  run:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    steps:\n      - run: .\u002Fbin\u002Fdeploy \"$TARGET\"\n        env:\n          TARGET: ${{ inputs.target }}\n          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}\n",[4898],{"type":45,"tag":58,"props":4899,"children":4900},{"__ignoreMap":2215},[4901,4912,4923,4934,4945,4960,4975,4987,4999,5014,5021,5032,5043,5058,5069,5084,5095,5114,5125,5140],{"type":45,"tag":2221,"props":4902,"children":4903},{"class":2223,"line":2224},[4904,4908],{"type":45,"tag":2221,"props":4905,"children":4906},{"style":2228},[4907],{"type":50,"value":2231},{"type":45,"tag":2221,"props":4909,"children":4910},{"style":2234},[4911],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4913,"children":4914},{"class":2223,"line":2246},[4915,4919],{"type":45,"tag":2221,"props":4916,"children":4917},{"style":2250},[4918],{"type":50,"value":4680},{"type":45,"tag":2221,"props":4920,"children":4921},{"style":2234},[4922],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4924,"children":4925},{"class":2223,"line":31},[4926,4930],{"type":45,"tag":2221,"props":4927,"children":4928},{"style":2250},[4929],{"type":50,"value":2919},{"type":45,"tag":2221,"props":4931,"children":4932},{"style":2234},[4933],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4935,"children":4936},{"class":2223,"line":2278},[4937,4941],{"type":45,"tag":2221,"props":4938,"children":4939},{"style":2250},[4940],{"type":50,"value":4703},{"type":45,"tag":2221,"props":4942,"children":4943},{"style":2234},[4944],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4946,"children":4947},{"class":2223,"line":2291},[4948,4952,4956],{"type":45,"tag":2221,"props":4949,"children":4950},{"style":2250},[4951],{"type":50,"value":2943},{"type":45,"tag":2221,"props":4953,"children":4954},{"style":2234},[4955],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4957,"children":4958},{"style":2240},[4959],{"type":50,"value":2952},{"type":45,"tag":2221,"props":4961,"children":4962},{"class":2223,"line":2309},[4963,4967,4971],{"type":45,"tag":2221,"props":4964,"children":4965},{"style":2250},[4966],{"type":50,"value":2960},{"type":45,"tag":2221,"props":4968,"children":4969},{"style":2234},[4970],{"type":50,"value":2237},{"type":45,"tag":2221,"props":4972,"children":4973},{"style":2228},[4974],{"type":50,"value":2969},{"type":45,"tag":2221,"props":4976,"children":4977},{"class":2223,"line":2322},[4978,4983],{"type":45,"tag":2221,"props":4979,"children":4980},{"style":2250},[4981],{"type":50,"value":4982},"    secrets",{"type":45,"tag":2221,"props":4984,"children":4985},{"style":2234},[4986],{"type":50,"value":2275},{"type":45,"tag":2221,"props":4988,"children":4989},{"class":2223,"line":2345},[4990,4995],{"type":45,"tag":2221,"props":4991,"children":4992},{"style":2250},[4993],{"type":50,"value":4994},"      DEPLOY_KEY",{"type":45,"tag":2221,"props":4996,"children":4997},{"style":2234},[4998],{"type":50,"value":2275},{"type":45,"tag":2221,"props":5000,"children":5001},{"class":2223,"line":2358},[5002,5006,5010],{"type":45,"tag":2221,"props":5003,"children":5004},{"style":2250},[5005],{"type":50,"value":2960},{"type":45,"tag":2221,"props":5007,"children":5008},{"style":2234},[5009],{"type":50,"value":2237},{"type":45,"tag":2221,"props":5011,"children":5012},{"style":2228},[5013],{"type":50,"value":2969},{"type":45,"tag":2221,"props":5015,"children":5016},{"class":2223,"line":2376},[5017],{"type":45,"tag":2221,"props":5018,"children":5019},{"emptyLinePlaceholder":3814},[5020],{"type":50,"value":3817},{"type":45,"tag":2221,"props":5022,"children":5023},{"class":2223,"line":2398},[5024,5028],{"type":45,"tag":2221,"props":5025,"children":5026},{"style":2250},[5027],{"type":50,"value":2270},{"type":45,"tag":2221,"props":5029,"children":5030},{"style":2234},[5031],{"type":50,"value":2275},{"type":45,"tag":2221,"props":5033,"children":5034},{"class":2223,"line":2598},[5035,5039],{"type":45,"tag":2221,"props":5036,"children":5037},{"style":2250},[5038],{"type":50,"value":4763},{"type":45,"tag":2221,"props":5040,"children":5041},{"style":2234},[5042],{"type":50,"value":2275},{"type":45,"tag":2221,"props":5044,"children":5045},{"class":2223,"line":3048},[5046,5050,5054],{"type":45,"tag":2221,"props":5047,"children":5048},{"style":2250},[5049],{"type":50,"value":2297},{"type":45,"tag":2221,"props":5051,"children":5052},{"style":2234},[5053],{"type":50,"value":2237},{"type":45,"tag":2221,"props":5055,"children":5056},{"style":2240},[5057],{"type":50,"value":2306},{"type":45,"tag":2221,"props":5059,"children":5060},{"class":2223,"line":3070},[5061,5065],{"type":45,"tag":2221,"props":5062,"children":5063},{"style":2250},[5064],{"type":50,"value":3646},{"type":45,"tag":2221,"props":5066,"children":5067},{"style":2234},[5068],{"type":50,"value":2275},{"type":45,"tag":2221,"props":5070,"children":5071},{"class":2223,"line":3079},[5072,5076,5080],{"type":45,"tag":2221,"props":5073,"children":5074},{"style":2250},[5075],{"type":50,"value":3658},{"type":45,"tag":2221,"props":5077,"children":5078},{"style":2234},[5079],{"type":50,"value":2237},{"type":45,"tag":2221,"props":5081,"children":5082},{"style":2240},[5083],{"type":50,"value":2480},{"type":45,"tag":2221,"props":5085,"children":5086},{"class":2223,"line":3350},[5087,5091],{"type":45,"tag":2221,"props":5088,"children":5089},{"style":2250},[5090],{"type":50,"value":2315},{"type":45,"tag":2221,"props":5092,"children":5093},{"style":2234},[5094],{"type":50,"value":2275},{"type":45,"tag":2221,"props":5096,"children":5097},{"class":2223,"line":3366},[5098,5102,5106,5110],{"type":45,"tag":2221,"props":5099,"children":5100},{"style":2234},[5101],{"type":50,"value":2328},{"type":45,"tag":2221,"props":5103,"children":5104},{"style":2250},[5105],{"type":50,"value":2386},{"type":45,"tag":2221,"props":5107,"children":5108},{"style":2234},[5109],{"type":50,"value":2237},{"type":45,"tag":2221,"props":5111,"children":5112},{"style":2240},[5113],{"type":50,"value":4813},{"type":45,"tag":2221,"props":5115,"children":5116},{"class":2223,"line":3375},[5117,5121],{"type":45,"tag":2221,"props":5118,"children":5119},{"style":2250},[5120],{"type":50,"value":4524},{"type":45,"tag":2221,"props":5122,"children":5123},{"style":2234},[5124],{"type":50,"value":2275},{"type":45,"tag":2221,"props":5126,"children":5127},{"class":2223,"line":3384},[5128,5132,5136],{"type":45,"tag":2221,"props":5129,"children":5130},{"style":2250},[5131],{"type":50,"value":4832},{"type":45,"tag":2221,"props":5133,"children":5134},{"style":2234},[5135],{"type":50,"value":2237},{"type":45,"tag":2221,"props":5137,"children":5138},{"style":2240},[5139],{"type":50,"value":4841},{"type":45,"tag":2221,"props":5141,"children":5142},{"class":2223,"line":3393},[5143,5147,5151],{"type":45,"tag":2221,"props":5144,"children":5145},{"style":2250},[5146],{"type":50,"value":4849},{"type":45,"tag":2221,"props":5148,"children":5149},{"style":2234},[5150],{"type":50,"value":2237},{"type":45,"tag":2221,"props":5152,"children":5153},{"style":2240},[5154],{"type":50,"value":4858},{"type":45,"tag":46,"props":5156,"children":5157},{},[5158,5160,5165],{"type":50,"value":5159},"Declare every consumed secret. Pin ",{"type":45,"tag":58,"props":5161,"children":5163},{"className":5162},[],[5164],{"type":50,"value":63},{"type":50,"value":5166}," so the callee does not silently inherit caller scope.",{"type":45,"tag":830,"props":5168,"children":5170},{"id":5169},"pattern-typescript-action-runs-untrusted-input",[5171],{"type":50,"value":5172},"Pattern: TypeScript action runs untrusted input",{"type":45,"tag":46,"props":5174,"children":5175},{},[5176],{"type":45,"tag":95,"props":5177,"children":5178},{},[5179],{"type":50,"value":5180},"TypeScript - bad:",{"type":45,"tag":2210,"props":5182,"children":5186},{"className":5183,"code":5184,"language":5185,"meta":2215,"style":2215},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import * as core from '@actions\u002Fcore';\nimport {execSync} from 'node:child_process';\n\nconst target = core.getInput('target');\nexecSync(`make ${target}`, {stdio: 'inherit'});\n","ts",[5187],{"type":45,"tag":58,"props":5188,"children":5189},{"__ignoreMap":2215},[5190,5239,5283,5290,5350],{"type":45,"tag":2221,"props":5191,"children":5192},{"class":2223,"line":2224},[5193,5198,5203,5208,5214,5219,5224,5229,5234],{"type":45,"tag":2221,"props":5194,"children":5195},{"style":3064},[5196],{"type":50,"value":5197},"import",{"type":45,"tag":2221,"props":5199,"children":5200},{"style":2234},[5201],{"type":50,"value":5202}," *",{"type":45,"tag":2221,"props":5204,"children":5205},{"style":3064},[5206],{"type":50,"value":5207}," as",{"type":45,"tag":2221,"props":5209,"children":5211},{"style":5210},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[5212],{"type":50,"value":5213}," core ",{"type":45,"tag":2221,"props":5215,"children":5216},{"style":3064},[5217],{"type":50,"value":5218},"from",{"type":45,"tag":2221,"props":5220,"children":5221},{"style":2234},[5222],{"type":50,"value":5223}," '",{"type":45,"tag":2221,"props":5225,"children":5226},{"style":2240},[5227],{"type":50,"value":5228},"@actions\u002Fcore",{"type":45,"tag":2221,"props":5230,"children":5231},{"style":2234},[5232],{"type":50,"value":5233},"'",{"type":45,"tag":2221,"props":5235,"children":5236},{"style":2234},[5237],{"type":50,"value":5238},";\n",{"type":45,"tag":2221,"props":5240,"children":5241},{"class":2223,"line":2246},[5242,5246,5251,5256,5261,5266,5270,5275,5279],{"type":45,"tag":2221,"props":5243,"children":5244},{"style":3064},[5245],{"type":50,"value":5197},{"type":45,"tag":2221,"props":5247,"children":5248},{"style":2234},[5249],{"type":50,"value":5250}," {",{"type":45,"tag":2221,"props":5252,"children":5253},{"style":5210},[5254],{"type":50,"value":5255},"execSync",{"type":45,"tag":2221,"props":5257,"children":5258},{"style":2234},[5259],{"type":50,"value":5260},"}",{"type":45,"tag":2221,"props":5262,"children":5263},{"style":3064},[5264],{"type":50,"value":5265}," from",{"type":45,"tag":2221,"props":5267,"children":5268},{"style":2234},[5269],{"type":50,"value":5223},{"type":45,"tag":2221,"props":5271,"children":5272},{"style":2240},[5273],{"type":50,"value":5274},"node:child_process",{"type":45,"tag":2221,"props":5276,"children":5277},{"style":2234},[5278],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5280,"children":5281},{"style":2234},[5282],{"type":50,"value":5238},{"type":45,"tag":2221,"props":5284,"children":5285},{"class":2223,"line":31},[5286],{"type":45,"tag":2221,"props":5287,"children":5288},{"emptyLinePlaceholder":3814},[5289],{"type":50,"value":3817},{"type":45,"tag":2221,"props":5291,"children":5292},{"class":2223,"line":2278},[5293,5299,5304,5309,5314,5318,5324,5329,5333,5338,5342,5346],{"type":45,"tag":2221,"props":5294,"children":5296},{"style":5295},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[5297],{"type":50,"value":5298},"const",{"type":45,"tag":2221,"props":5300,"children":5301},{"style":5210},[5302],{"type":50,"value":5303}," target ",{"type":45,"tag":2221,"props":5305,"children":5306},{"style":2234},[5307],{"type":50,"value":5308},"=",{"type":45,"tag":2221,"props":5310,"children":5311},{"style":5210},[5312],{"type":50,"value":5313}," core",{"type":45,"tag":2221,"props":5315,"children":5316},{"style":2234},[5317],{"type":50,"value":957},{"type":45,"tag":2221,"props":5319,"children":5321},{"style":5320},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[5322],{"type":50,"value":5323},"getInput",{"type":45,"tag":2221,"props":5325,"children":5326},{"style":5210},[5327],{"type":50,"value":5328},"(",{"type":45,"tag":2221,"props":5330,"children":5331},{"style":2234},[5332],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5334,"children":5335},{"style":2240},[5336],{"type":50,"value":5337},"target",{"type":45,"tag":2221,"props":5339,"children":5340},{"style":2234},[5341],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5343,"children":5344},{"style":5210},[5345],{"type":50,"value":1198},{"type":45,"tag":2221,"props":5347,"children":5348},{"style":2234},[5349],{"type":50,"value":5238},{"type":45,"tag":2221,"props":5351,"children":5352},{"class":2223,"line":2291},[5353,5357,5361,5366,5371,5376,5380,5385,5389,5393,5398,5402,5406,5410,5414,5418,5422],{"type":45,"tag":2221,"props":5354,"children":5355},{"style":5320},[5356],{"type":50,"value":5255},{"type":45,"tag":2221,"props":5358,"children":5359},{"style":5210},[5360],{"type":50,"value":5328},{"type":45,"tag":2221,"props":5362,"children":5363},{"style":2234},[5364],{"type":50,"value":5365},"`",{"type":45,"tag":2221,"props":5367,"children":5368},{"style":2240},[5369],{"type":50,"value":5370},"make ",{"type":45,"tag":2221,"props":5372,"children":5373},{"style":2234},[5374],{"type":50,"value":5375},"${",{"type":45,"tag":2221,"props":5377,"children":5378},{"style":5210},[5379],{"type":50,"value":5337},{"type":45,"tag":2221,"props":5381,"children":5382},{"style":2234},[5383],{"type":50,"value":5384},"}`",{"type":45,"tag":2221,"props":5386,"children":5387},{"style":2234},[5388],{"type":50,"value":3213},{"type":45,"tag":2221,"props":5390,"children":5391},{"style":2234},[5392],{"type":50,"value":5250},{"type":45,"tag":2221,"props":5394,"children":5395},{"style":2250},[5396],{"type":50,"value":5397},"stdio",{"type":45,"tag":2221,"props":5399,"children":5400},{"style":2234},[5401],{"type":50,"value":2237},{"type":45,"tag":2221,"props":5403,"children":5404},{"style":2234},[5405],{"type":50,"value":5223},{"type":45,"tag":2221,"props":5407,"children":5408},{"style":2240},[5409],{"type":50,"value":2081},{"type":45,"tag":2221,"props":5411,"children":5412},{"style":2234},[5413],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5415,"children":5416},{"style":2234},[5417],{"type":50,"value":5260},{"type":45,"tag":2221,"props":5419,"children":5420},{"style":5210},[5421],{"type":50,"value":1198},{"type":45,"tag":2221,"props":5423,"children":5424},{"style":2234},[5425],{"type":50,"value":5238},{"type":45,"tag":46,"props":5427,"children":5428},{},[5429,5431,5436],{"type":50,"value":5430},"If a workflow passes PR-controlled text into ",{"type":45,"tag":58,"props":5432,"children":5434},{"className":5433},[],[5435],{"type":50,"value":5337},{"type":50,"value":5437},", the composite or JavaScript action becomes the shell sink.",{"type":45,"tag":46,"props":5439,"children":5440},{},[5441],{"type":45,"tag":95,"props":5442,"children":5443},{},[5444],{"type":50,"value":5445},"TypeScript - safe:",{"type":45,"tag":2210,"props":5447,"children":5449},{"className":5183,"code":5448,"language":5185,"meta":2215,"style":2215},"import * as core from '@actions\u002Fcore';\nimport {execFileSync} from 'node:child_process';\n\nconst target = core.getInput('target');\nif (!\u002F^[a-z0-9_-]+$\u002Fi.test(target)) {\n  throw new Error('invalid target');\n}\nexecFileSync('make', [target], {stdio: 'inherit'});\n",[5450],{"type":45,"tag":58,"props":5451,"children":5452},{"__ignoreMap":2215},[5453,5492,5532,5539,5590,5666,5709,5717],{"type":45,"tag":2221,"props":5454,"children":5455},{"class":2223,"line":2224},[5456,5460,5464,5468,5472,5476,5480,5484,5488],{"type":45,"tag":2221,"props":5457,"children":5458},{"style":3064},[5459],{"type":50,"value":5197},{"type":45,"tag":2221,"props":5461,"children":5462},{"style":2234},[5463],{"type":50,"value":5202},{"type":45,"tag":2221,"props":5465,"children":5466},{"style":3064},[5467],{"type":50,"value":5207},{"type":45,"tag":2221,"props":5469,"children":5470},{"style":5210},[5471],{"type":50,"value":5213},{"type":45,"tag":2221,"props":5473,"children":5474},{"style":3064},[5475],{"type":50,"value":5218},{"type":45,"tag":2221,"props":5477,"children":5478},{"style":2234},[5479],{"type":50,"value":5223},{"type":45,"tag":2221,"props":5481,"children":5482},{"style":2240},[5483],{"type":50,"value":5228},{"type":45,"tag":2221,"props":5485,"children":5486},{"style":2234},[5487],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5489,"children":5490},{"style":2234},[5491],{"type":50,"value":5238},{"type":45,"tag":2221,"props":5493,"children":5494},{"class":2223,"line":2246},[5495,5499,5503,5508,5512,5516,5520,5524,5528],{"type":45,"tag":2221,"props":5496,"children":5497},{"style":3064},[5498],{"type":50,"value":5197},{"type":45,"tag":2221,"props":5500,"children":5501},{"style":2234},[5502],{"type":50,"value":5250},{"type":45,"tag":2221,"props":5504,"children":5505},{"style":5210},[5506],{"type":50,"value":5507},"execFileSync",{"type":45,"tag":2221,"props":5509,"children":5510},{"style":2234},[5511],{"type":50,"value":5260},{"type":45,"tag":2221,"props":5513,"children":5514},{"style":3064},[5515],{"type":50,"value":5265},{"type":45,"tag":2221,"props":5517,"children":5518},{"style":2234},[5519],{"type":50,"value":5223},{"type":45,"tag":2221,"props":5521,"children":5522},{"style":2240},[5523],{"type":50,"value":5274},{"type":45,"tag":2221,"props":5525,"children":5526},{"style":2234},[5527],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5529,"children":5530},{"style":2234},[5531],{"type":50,"value":5238},{"type":45,"tag":2221,"props":5533,"children":5534},{"class":2223,"line":31},[5535],{"type":45,"tag":2221,"props":5536,"children":5537},{"emptyLinePlaceholder":3814},[5538],{"type":50,"value":3817},{"type":45,"tag":2221,"props":5540,"children":5541},{"class":2223,"line":2278},[5542,5546,5550,5554,5558,5562,5566,5570,5574,5578,5582,5586],{"type":45,"tag":2221,"props":5543,"children":5544},{"style":5295},[5545],{"type":50,"value":5298},{"type":45,"tag":2221,"props":5547,"children":5548},{"style":5210},[5549],{"type":50,"value":5303},{"type":45,"tag":2221,"props":5551,"children":5552},{"style":2234},[5553],{"type":50,"value":5308},{"type":45,"tag":2221,"props":5555,"children":5556},{"style":5210},[5557],{"type":50,"value":5313},{"type":45,"tag":2221,"props":5559,"children":5560},{"style":2234},[5561],{"type":50,"value":957},{"type":45,"tag":2221,"props":5563,"children":5564},{"style":5320},[5565],{"type":50,"value":5323},{"type":45,"tag":2221,"props":5567,"children":5568},{"style":5210},[5569],{"type":50,"value":5328},{"type":45,"tag":2221,"props":5571,"children":5572},{"style":2234},[5573],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5575,"children":5576},{"style":2240},[5577],{"type":50,"value":5337},{"type":45,"tag":2221,"props":5579,"children":5580},{"style":2234},[5581],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5583,"children":5584},{"style":5210},[5585],{"type":50,"value":1198},{"type":45,"tag":2221,"props":5587,"children":5588},{"style":2234},[5589],{"type":50,"value":5238},{"type":45,"tag":2221,"props":5591,"children":5592},{"class":2223,"line":2291},[5593,5598,5603,5608,5613,5618,5623,5628,5633,5638,5642,5647,5651,5656,5661],{"type":45,"tag":2221,"props":5594,"children":5595},{"style":3064},[5596],{"type":50,"value":5597},"if",{"type":45,"tag":2221,"props":5599,"children":5600},{"style":5210},[5601],{"type":50,"value":5602}," (",{"type":45,"tag":2221,"props":5604,"children":5605},{"style":2234},[5606],{"type":50,"value":5607},"!",{"type":45,"tag":2221,"props":5609,"children":5610},{"style":2234},[5611],{"type":50,"value":5612},"\u002F",{"type":45,"tag":2221,"props":5614,"children":5615},{"style":3064},[5616],{"type":50,"value":5617},"^",{"type":45,"tag":2221,"props":5619,"children":5620},{"style":2234},[5621],{"type":50,"value":5622},"[",{"type":45,"tag":2221,"props":5624,"children":5625},{"style":2240},[5626],{"type":50,"value":5627},"a-z0-9_-",{"type":45,"tag":2221,"props":5629,"children":5630},{"style":2234},[5631],{"type":50,"value":5632},"]+",{"type":45,"tag":2221,"props":5634,"children":5635},{"style":3064},[5636],{"type":50,"value":5637},"$",{"type":45,"tag":2221,"props":5639,"children":5640},{"style":2234},[5641],{"type":50,"value":5612},{"type":45,"tag":2221,"props":5643,"children":5644},{"style":4041},[5645],{"type":50,"value":5646},"i",{"type":45,"tag":2221,"props":5648,"children":5649},{"style":2234},[5650],{"type":50,"value":957},{"type":45,"tag":2221,"props":5652,"children":5653},{"style":5320},[5654],{"type":50,"value":5655},"test",{"type":45,"tag":2221,"props":5657,"children":5658},{"style":5210},[5659],{"type":50,"value":5660},"(target)) ",{"type":45,"tag":2221,"props":5662,"children":5663},{"style":2234},[5664],{"type":50,"value":5665},"{\n",{"type":45,"tag":2221,"props":5667,"children":5668},{"class":2223,"line":2309},[5669,5674,5679,5684,5688,5692,5697,5701,5705],{"type":45,"tag":2221,"props":5670,"children":5671},{"style":3064},[5672],{"type":50,"value":5673},"  throw",{"type":45,"tag":2221,"props":5675,"children":5676},{"style":2234},[5677],{"type":50,"value":5678}," new",{"type":45,"tag":2221,"props":5680,"children":5681},{"style":5320},[5682],{"type":50,"value":5683}," Error",{"type":45,"tag":2221,"props":5685,"children":5686},{"style":2250},[5687],{"type":50,"value":5328},{"type":45,"tag":2221,"props":5689,"children":5690},{"style":2234},[5691],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5693,"children":5694},{"style":2240},[5695],{"type":50,"value":5696},"invalid target",{"type":45,"tag":2221,"props":5698,"children":5699},{"style":2234},[5700],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5702,"children":5703},{"style":2250},[5704],{"type":50,"value":1198},{"type":45,"tag":2221,"props":5706,"children":5707},{"style":2234},[5708],{"type":50,"value":5238},{"type":45,"tag":2221,"props":5710,"children":5711},{"class":2223,"line":2322},[5712],{"type":45,"tag":2221,"props":5713,"children":5714},{"style":2234},[5715],{"type":50,"value":5716},"}\n",{"type":45,"tag":2221,"props":5718,"children":5719},{"class":2223,"line":2345},[5720,5724,5728,5732,5736,5740,5744,5749,5753,5757,5761,5765,5769,5773,5777,5781,5785],{"type":45,"tag":2221,"props":5721,"children":5722},{"style":5320},[5723],{"type":50,"value":5507},{"type":45,"tag":2221,"props":5725,"children":5726},{"style":5210},[5727],{"type":50,"value":5328},{"type":45,"tag":2221,"props":5729,"children":5730},{"style":2234},[5731],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5733,"children":5734},{"style":2240},[5735],{"type":50,"value":927},{"type":45,"tag":2221,"props":5737,"children":5738},{"style":2234},[5739],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5741,"children":5742},{"style":2234},[5743],{"type":50,"value":3213},{"type":45,"tag":2221,"props":5745,"children":5746},{"style":5210},[5747],{"type":50,"value":5748}," [target]",{"type":45,"tag":2221,"props":5750,"children":5751},{"style":2234},[5752],{"type":50,"value":3213},{"type":45,"tag":2221,"props":5754,"children":5755},{"style":2234},[5756],{"type":50,"value":5250},{"type":45,"tag":2221,"props":5758,"children":5759},{"style":2250},[5760],{"type":50,"value":5397},{"type":45,"tag":2221,"props":5762,"children":5763},{"style":2234},[5764],{"type":50,"value":2237},{"type":45,"tag":2221,"props":5766,"children":5767},{"style":2234},[5768],{"type":50,"value":5223},{"type":45,"tag":2221,"props":5770,"children":5771},{"style":2240},[5772],{"type":50,"value":2081},{"type":45,"tag":2221,"props":5774,"children":5775},{"style":2234},[5776],{"type":50,"value":5233},{"type":45,"tag":2221,"props":5778,"children":5779},{"style":2234},[5780],{"type":50,"value":5260},{"type":45,"tag":2221,"props":5782,"children":5783},{"style":5210},[5784],{"type":50,"value":1198},{"type":45,"tag":2221,"props":5786,"children":5787},{"style":2234},[5788],{"type":50,"value":5238},{"type":45,"tag":46,"props":5790,"children":5791},{},[5792],{"type":50,"value":5793},"Validate action inputs and avoid shell interpolation.",{"type":45,"tag":67,"props":5795,"children":5797},{"id":5796},"output-requirements",[5798],{"type":50,"value":5799},"Output Requirements",{"type":45,"tag":46,"props":5801,"children":5802},{},[5803],{"type":50,"value":5804},"For every finding, include:",{"type":45,"tag":87,"props":5806,"children":5807},{},[5808,5818,5828,5852,5862,5872,5882,5892],{"type":45,"tag":91,"props":5809,"children":5810},{},[5811,5816],{"type":45,"tag":95,"props":5812,"children":5813},{},[5814],{"type":50,"value":5815},"File and line",{"type":50,"value":5817},": exact workflow, action, script, or config location",{"type":45,"tag":91,"props":5819,"children":5820},{},[5821,5826],{"type":45,"tag":95,"props":5822,"children":5823},{},[5824],{"type":50,"value":5825},"Entry point",{"type":50,"value":5827},": how the external attacker reaches the workflow, or which manual\u002Freusable caller can supply inputs",{"type":45,"tag":91,"props":5829,"children":5830},{},[5831,5836,5838,5843,5845,5850],{"type":45,"tag":95,"props":5832,"children":5833},{},[5834],{"type":50,"value":5835},"Controlled input",{"type":50,"value":5837},": PR ref, artifact, cache, comment, branch, title, file, config, ",{"type":45,"tag":58,"props":5839,"children":5841},{"className":5840},[],[5842],{"type":50,"value":115},{"type":50,"value":5844}," input, or ",{"type":45,"tag":58,"props":5846,"children":5848},{"className":5847},[],[5849],{"type":50,"value":123},{"type":50,"value":5851}," input",{"type":45,"tag":91,"props":5853,"children":5854},{},[5855,5860],{"type":45,"tag":95,"props":5856,"children":5857},{},[5858],{"type":50,"value":5859},"Execution mechanism",{"type":50,"value":5861},": checkout, shell expression, script, package lifecycle, local action, artifact restore, or runner",{"type":45,"tag":91,"props":5863,"children":5864},{},[5865,5870],{"type":45,"tag":95,"props":5866,"children":5867},{},[5868],{"type":50,"value":5869},"Privileges exposed",{"type":50,"value":5871},": secrets, token scopes, OIDC, package publishing, runner access, or repository write",{"type":45,"tag":91,"props":5873,"children":5874},{},[5875,5880],{"type":45,"tag":95,"props":5876,"children":5877},{},[5878],{"type":50,"value":5879},"Impact",{"type":50,"value":5881},": what the attacker or caller can do",{"type":45,"tag":91,"props":5883,"children":5884},{},[5885,5890],{"type":45,"tag":95,"props":5886,"children":5887},{},[5888],{"type":50,"value":5889},"Confidence",{"type":50,"value":5891},": high or medium, with the reason",{"type":45,"tag":91,"props":5893,"children":5894},{},[5895,5900],{"type":45,"tag":95,"props":5896,"children":5897},{},[5898],{"type":50,"value":5899},"Fix",{"type":50,"value":5901},": concrete change, preferably a minimal workflow patch",{"type":45,"tag":46,"props":5903,"children":5904},{},[5905],{"type":50,"value":5906},"If there are no findings, say that no exploitable GitHub Actions workflow vulnerabilities were identified and list the workflows or paths reviewed.",{"type":45,"tag":5908,"props":5909,"children":5910},"style",{},[5911],{"type":50,"value":5912},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":5914,"total":6087},[5915,5940,5954,5969,5983,6000,6014,6028,6036,6047,6057,6074],{"slug":5916,"name":5916,"fn":5917,"description":5918,"org":5919,"tags":5920,"stars":5937,"repoUrl":5938,"updatedAt":5939},"xcodebuildmcp","build and test Apple apps with XcodeBuildMCP","Official skill for XcodeBuildMCP. Use when doing iOS\u002FmacOS\u002FwatchOS\u002FtvOS\u002FvisionOS work (build, test, run, debug, log, UI automation).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[5921,5924,5927,5930,5931,5934],{"name":5922,"slug":5923,"type":16},"Debugging","debugging",{"name":5925,"slug":5926,"type":16},"iOS","ios",{"name":5928,"slug":5929,"type":16},"macOS","macos",{"name":9,"slug":8,"type":16},{"name":5932,"slug":5933,"type":16},"Testing","testing",{"name":5935,"slug":5936,"type":16},"Xcode","xcode",6176,"https:\u002F\u002Fgithub.com\u002Fgetsentry\u002FXcodeBuildMCP","2026-04-06T18:13:34.8719",{"slug":5941,"name":5941,"fn":5942,"description":5943,"org":5944,"tags":5945,"stars":5937,"repoUrl":5938,"updatedAt":5953},"xcodebuildmcp-cli","build and test Apple apps via CLI","Official skill for the XcodeBuildMCP CLI. Use when doing iOS\u002FmacOS\u002FwatchOS\u002FtvOS\u002FvisionOS work (build, test, run, debug, log, UI automation).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[5946,5949,5950,5951,5952],{"name":5947,"slug":5948,"type":16},"CLI","cli",{"name":5925,"slug":5926,"type":16},{"name":5928,"slug":5929,"type":16},{"name":5932,"slug":5933,"type":16},{"name":5935,"slug":5936,"type":16},"2026-04-06T18:13:36.13414",{"slug":5955,"name":5955,"fn":5956,"description":5957,"org":5958,"tags":5959,"stars":5966,"repoUrl":5967,"updatedAt":5968},"agents-md","maintain project instruction files","Creates and maintains concise AGENTS.md and CLAUDE.md project instruction files. Use when asked to create AGENTS.md, update AGENTS.md, maintain agent docs, set up CLAUDE.md, document repository agent conventions, or keep coding-agent instructions minimal and reference-backed.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[5960,5963],{"name":5961,"slug":5962,"type":16},"Documentation","documentation",{"name":5964,"slug":5965,"type":16},"Engineering","engineering",861,"https:\u002F\u002Fgithub.com\u002Fgetsentry\u002Fskills","2026-05-15T06:16:29.695991",{"slug":5970,"name":5970,"fn":5971,"description":5972,"org":5973,"tags":5974,"stars":5966,"repoUrl":5967,"updatedAt":5982},"blog-writing-guide","write and review engineering blog posts","Write, review, and improve blog posts for the Sentry engineering blog following Sentry's specific writing standards, voice, and quality bar. Use this skill whenever someone asks to write a blog post, draft a technical article, review blog content, improve a draft, write a product announcement, create an engineering deep-dive, or produce any written content destined for the Sentry blog or developer audience. Also trigger when the user mentions \"blog post,\" \"blog draft,\" \"write-up,\" \"announcement post,\" \"engineering post,\" \"deep dive,\" \"postmortem,\" or asks for help with technical writing for Sentry. Even if the user just says \"help me write about [feature\u002Ftopic]\" — if it sounds like it could become a Sentry blog post, use this skill.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[5975,5978,5979],{"name":5976,"slug":5977,"type":16},"Communications","communications",{"name":9,"slug":8,"type":16},{"name":5980,"slug":5981,"type":16},"Technical Writing","technical-writing","2026-05-15T06:16:33.38217",{"slug":5984,"name":5984,"fn":5985,"description":5986,"org":5987,"tags":5988,"stars":5966,"repoUrl":5967,"updatedAt":5999},"brand-guidelines","write copy following Sentry brand guidelines","Write copy following Sentry brand guidelines. Use when writing UI text, error messages, empty states, onboarding flows, 404 pages, documentation, marketing copy, or any user-facing content. Covers both Plain Speech (default) and Sentry Voice tones.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[5989,5992,5995,5996],{"name":5990,"slug":5991,"type":16},"Branding","branding",{"name":5993,"slug":5994,"type":16},"Content Creation","content-creation",{"name":9,"slug":8,"type":16},{"name":5997,"slug":5998,"type":16},"UX Copy","ux-copy","2026-05-15T06:16:22.395707",{"slug":6001,"name":6001,"fn":6002,"description":6003,"org":6004,"tags":6005,"stars":5966,"repoUrl":5967,"updatedAt":6013},"claude-settings-audit","generate Claude Code settings permissions","Analyze a repository to generate recommended Claude Code settings.json permissions. Use when setting up a new project, auditing existing settings, or determining which read-only bash commands to allow. Detects tech stack, build tools, and monorepo structure.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6006,6009,6012],{"name":6007,"slug":6008,"type":16},"Claude Code","claude-code",{"name":6010,"slug":6011,"type":16},"Configuration","configuration",{"name":14,"slug":15,"type":16},"2026-05-15T06:16:44.335977",{"slug":6015,"name":6015,"fn":6016,"description":6017,"org":6018,"tags":6019,"stars":5966,"repoUrl":5967,"updatedAt":6027},"code-review","perform code reviews for Sentry projects","Perform code reviews following Sentry engineering practices. Use when reviewing pull requests, examining code changes, or providing feedback on code quality. Covers security, performance, testing, and design review.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6020,6022,6023,6026],{"name":6021,"slug":6015,"type":16},"Code Review",{"name":5964,"slug":5965,"type":16},{"name":6024,"slug":6025,"type":16},"Performance","performance",{"name":14,"slug":15,"type":16},"2026-05-15T06:16:35.824864",{"slug":6029,"name":6029,"fn":6030,"description":6031,"org":6032,"tags":6033,"stars":5966,"repoUrl":5967,"updatedAt":6035},"code-simplifier","simplify and refine source code","Simplifies and refines code for clarity, consistency, and maintainability while preserving all functionality. Use when asked to \"simplify code\", \"clean up code\", \"refactor for clarity\", \"improve readability\", or review recently modified code for elegance. Focuses on project-specific best practices.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6034],{"name":25,"slug":26,"type":16},"2026-05-15T06:16:32.127981",{"slug":6037,"name":6037,"fn":6038,"description":6039,"org":6040,"tags":6041,"stars":5966,"repoUrl":5967,"updatedAt":6046},"commit","create commits with Sentry conventions","Use for every request to commit changes or draft a commit message. Creates Sentry-style conventional commits with issue references.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6042,6045],{"name":6043,"slug":6044,"type":16},"Git","git",{"name":9,"slug":8,"type":16},"2026-07-18T05:15:10.723937",{"slug":6048,"name":6048,"fn":6049,"description":6050,"org":6051,"tags":6052,"stars":5966,"repoUrl":5967,"updatedAt":6056},"create-branch","create git branches for Sentry workflows","Create a git branch following Sentry naming conventions. Use when asked to \"create a branch\", \"new branch\", \"start a branch\", \"make a branch\", \"switch to a new branch\", or when starting new work on the default branch.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6053,6054,6055],{"name":5964,"slug":5965,"type":16},{"name":6043,"slug":6044,"type":16},{"name":9,"slug":8,"type":16},"2026-05-15T06:16:39.458431",{"slug":6058,"name":6058,"fn":6059,"description":6060,"org":6061,"tags":6062,"stars":5966,"repoUrl":5967,"updatedAt":6073},"django-access-review","review Django access control and IDOR","Django access control and IDOR security review. Use when reviewing Django views, DRF viewsets, ORM queries, or any Python\u002FDjango code handling user authorization. Trigger keywords: \"IDOR\", \"access control\", \"authorization\", \"Django permissions\", \"object permissions\", \"tenant isolation\", \"broken access\".",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6063,6066,6067,6070,6072],{"name":6064,"slug":6065,"type":16},"Access Control","access-control",{"name":25,"slug":26,"type":16},{"name":6068,"slug":6069,"type":16},"Django","django",{"name":6071,"slug":3780,"type":16},"Python",{"name":14,"slug":15,"type":16},"2026-05-15T06:16:43.098698",{"slug":6075,"name":6075,"fn":6076,"description":6077,"org":6078,"tags":6079,"stars":5966,"repoUrl":5967,"updatedAt":6086},"django-perf-review","review and optimize Django performance","Django performance code review. Use when asked to \"review Django performance\", \"find N+1 queries\", \"optimize Django\", \"check queryset performance\", \"database performance\", \"Django ORM issues\", or audit Django code for performance problems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6080,6081,6084,6085],{"name":6021,"slug":6015,"type":16},{"name":6082,"slug":6083,"type":16},"Database","database",{"name":6068,"slug":6069,"type":16},{"name":6024,"slug":6025,"type":16},"2026-05-15T06:16:24.832813",88,{"items":6089,"total":2322},[6090,6105,6119,6133,6144,6155,6163],{"slug":6091,"name":6091,"fn":6092,"description":6093,"org":6094,"tags":6095,"stars":27,"repoUrl":28,"updatedAt":6104},"vercel-deepsec","scan web applications for security vulnerabilities","Detects broad web application security vulnerabilities using the Vercel DeepSec benchmark prompt. Use when benchmarking security review coverage or running an open-ended appsec scan for auth bypass, missing auth, XSS, RCE, SQL injection, SSRF, path traversal, secrets, weak crypto, unsafe redirects, webhook verification, Next.js Server Actions, Lua\u002FOpenResty, Go, cache poisoning, or header trust bugs.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6096,6099,6100,6101],{"name":6097,"slug":6098,"type":16},"Audit","audit",{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":6102,"slug":6103,"type":16},"Vercel","vercel","2026-05-05T05:29:23.090902",{"slug":6106,"name":6106,"fn":6107,"description":6108,"org":6109,"tags":6110,"stars":27,"repoUrl":28,"updatedAt":6118},"wrdn-authz","detect authorization and IDOR flaws","Detects authorization flaws: IDOR, missing ownership or tenant scoping, role checks that fail open, privilege escalation, unauthenticated admin actions, mass assignment, and token\u002Fsession claims trusted for permission decisions. Use when asked to review route handlers, middleware, decorators, resolvers, RBAC\u002FACL logic, serializers, ORM queries, token-derived scopes, or admin surfaces.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6111,6112,6115,6116,6117],{"name":6064,"slug":6065,"type":16},{"name":6113,"slug":6114,"type":16},"Auth","auth",{"name":25,"slug":26,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},"2026-04-29T05:41:41.218677",{"slug":6120,"name":6120,"fn":6121,"description":6122,"org":6123,"tags":6124,"stars":27,"repoUrl":28,"updatedAt":6132},"wrdn-code-execution","detect code and command execution bugs","Detects bugs where untrusted input reaches a sink that produces code or command execution on the server. Covers command\u002Fshell injection, unsafe deserialization, server-side template injection, eval\u002FFunction\u002Fvm reached by user data, XXE-to-RCE gadgets, and prototype pollution that lands on a code-executing sink. Run on any diff touching subprocess\u002Fexec calls, template rendering, deserialization of bytes, XML parsing, or deep-merge of user-controlled objects.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6125,6128,6129,6130,6131],{"name":6126,"slug":6127,"type":16},"Backend","backend",{"name":25,"slug":26,"type":16},{"name":5922,"slug":5923,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},"2026-04-29T05:41:39.861655",{"slug":6134,"name":6134,"fn":6135,"description":6136,"org":6137,"tags":6138,"stars":27,"repoUrl":28,"updatedAt":6143},"wrdn-data-exfil","detect data exfiltration and SSRF bugs","Detects bugs where untrusted input reaches a sink that leaks data beyond its intended scope. Covers SSRF (including cloud metadata, internal services, image proxies), path traversal and archive zip-slip, SQL\u002FNoSQL injection enabling bulk reads, XXE file read, response serializers over-exposing internal fields, verbose error pages, logs capturing secrets, and CSV\u002Fformula injection in exports. Run on any diff touching HTTP clients with user URLs, file I\u002FO with user paths, raw queries, XML parsing, response serializers, error handlers, or export pipelines.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6139,6140,6141,6142],{"name":6126,"slug":6127,"type":16},{"name":25,"slug":26,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},"2026-04-29T05:41:42.567486",{"slug":6145,"name":6145,"fn":6146,"description":6147,"org":6148,"tags":6149,"stars":27,"repoUrl":28,"updatedAt":6154},"wrdn-dos-review","identify denial-of-service vulnerabilities in code","Finds availability \u002F denial-of-service bugs reachable from untrusted input — unbounded allocation, uncontrolled recursion, non-terminating loops, decompression bombs, panic\u002Fresource-leak, super-linear output amplification, algorithmic-complexity \u002F ReDoS catastrophic regex backtracking, and bounds that are present but ineffective (wrong dimension, applied too late, under-counting cost, or defaulted off). Use for DoS and resource-exhaustion audits, CPU-complexity and cost-limit \u002F quota-accuracy review, parser\u002Fdecoder\u002Fdeserialization hardening, and crash-safety review of code that processes attacker-controlled bytes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6150,6151,6152,6153],{"name":25,"slug":26,"type":16},{"name":5922,"slug":5923,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},"2026-07-18T05:47:48.104703",{"slug":4,"name":4,"fn":5,"description":6,"org":6156,"tags":6157,"stars":27,"repoUrl":28,"updatedAt":29},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6158,6159,6160,6161,6162],{"name":21,"slug":22,"type":16},{"name":25,"slug":26,"type":16},{"name":18,"slug":19,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"slug":6164,"name":6164,"fn":6165,"description":6166,"org":6167,"tags":6168,"stars":27,"repoUrl":28,"updatedAt":6178},"wrdn-pii","detect PII and confidential data in code","Detects real personally identifiable information, customer identifiers, and customer-confidential business data in code changes. Use when asked to find PII, customer IPs, real email addresses, revenue data, billing data, personal data, privacy leaks, customer info in logs, PII in URLs, or accidental production data in tests, fixtures, comments, docs, config, telemetry, or API responses.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[6169,6170,6173,6176,6177],{"name":25,"slug":26,"type":16},{"name":6171,"slug":6172,"type":16},"Compliance","compliance",{"name":6174,"slug":6175,"type":16},"Privacy","privacy",{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},"2026-04-29T05:41:38.512082"]