diff --git a/action.yml b/action.yml index 2e3388c25..b6e909a5e 100644 --- a/action.yml +++ b/action.yml @@ -233,6 +233,14 @@ runs: mkdir -p "$GITHUB_ACTION_PATH/bin" cp "$(command -v bun)" "$GITHUB_ACTION_PATH/bin/bun" + - name: Prepend system bin dirs to PATH + if: ${{ inputs.allowed_non_write_users != '' && runner.os != 'Windows' }} + continue-on-error: true + shell: /bin/bash --noprofile --norc -e -o pipefail {0} + run: | + echo "/usr/bin" >> "$GITHUB_PATH" + echo "/bin" >> "$GITHUB_PATH" + - name: Run Claude Code Action id: run shell: bash @@ -342,6 +350,32 @@ runs: OTEL_LOGS_EXPORT_INTERVAL: ${{ env.OTEL_LOGS_EXPORT_INTERVAL }} OTEL_RESOURCE_ATTRIBUTES: ${{ env.OTEL_RESOURCE_ATTRIBUTES }} + - name: Re-prepend system bin dirs to PATH + if: ${{ always() && inputs.allowed_non_write_users != '' && runner.os != 'Windows' }} + continue-on-error: true + shell: /bin/bash --noprofile --norc -e -o pipefail {0} + env: + BASH_ENV: "" + LD_PRELOAD: "" + LD_LIBRARY_PATH: "" + NODE_OPTIONS: "" + DYLD_INSERT_LIBRARIES: "" + DYLD_PRELOAD: "" + DYLD_LIBRARY_PATH: "" + DYLD_FRAMEWORK_PATH: "" + run: | + echo "/usr/bin" >> "$GITHUB_PATH" + echo "/bin" >> "$GITHUB_PATH" + { + echo "BASH_ENV=" + echo "LD_PRELOAD=" + echo "LD_LIBRARY_PATH=" + echo "DYLD_INSERT_LIBRARIES=" + echo "DYLD_PRELOAD=" + echo "DYLD_LIBRARY_PATH=" + echo "DYLD_FRAMEWORK_PATH=" + } >> "$GITHUB_ENV" + - name: Cleanup SSH signing key if: always() && inputs.ssh_signing_key != '' shell: bash diff --git a/docs/security.md b/docs/security.md index 7b1963ae3..3346655ab 100644 --- a/docs/security.md +++ b/docs/security.md @@ -15,7 +15,7 @@ - Is designed for automation workflows where user permissions are already restricted by the workflow's permission scope - When set, Claude does a best-effort scrub of Anthropic, cloud, and GitHub Actions secrets from subprocess environments. On Linux runners with bubblewrap available, subprocesses additionally run with PID-namespace isolation. This reduces but does not eliminate prompt injection risk — keep workflow permissions minimal and validate all outputs. Set `CLAUDE_CODE_SUBPROCESS_ENV_SCRUB: 0` in your workflow or job `env:` block to opt out. - Optionally set `CLAUDE_CODE_SCRIPT_CAPS` in your workflow `env:` block to limit how many times Claude can call specific scripts per run. Value is JSON: `{"script-name.sh": maxCalls}`. Example: `CLAUDE_CODE_SCRIPT_CAPS: '{"edit-issue-labels.sh":2}'` allows at most 2 calls to `edit-issue-labels.sh`. Useful for write-capable helper scripts. - - When using `allowed_non_write_users`, always pass `github_token: ${{ secrets.GITHUB_TOKEN }}`. The auto-generated workflow token is scoped to the job's declared permissions and expires automatically, which limits blast radius. Personal access tokens are not recommended for untrusted-input workflows. + - When using `allowed_non_write_users`, always pass `github_token: ${{ secrets.GITHUB_TOKEN }}`. The auto-generated workflow token is scoped to the job's declared permissions and expires when the job completes. **Do not use a personal access token** — a static token does not rotate between runs, and depending on the tools allowed via `claude_args`, the model could be used to recover part or all of it. We recommend restricting allowed tools (e.g. `claude_args: '--allowedTools "Bash(gh issue view:*)"'`) to the minimum required when using `allowed_non_write_users`. - **Token Permissions**: The GitHub app receives only a short-lived token scoped specifically to the repository it's operating in - **No Cross-Repository Access**: Each action invocation is limited to the repository where it was triggered - **Limited Scope**: The token cannot access other repositories or perform actions beyond the configured permissions