Skip to content

fix(security): validate remote URL and escape commit messages in generate-release.ps1#673

Open
xiaolai wants to merge 2 commits intoIvanMurzak:mainfrom
xiaolai:fix/nlpm-release-content-injection
Open

fix(security): validate remote URL and escape commit messages in generate-release.ps1#673
xiaolai wants to merge 2 commits intoIvanMurzak:mainfrom
xiaolai:fix/nlpm-release-content-injection

Conversation

@xiaolai
Copy link
Copy Markdown
Contributor

@xiaolai xiaolai commented Apr 21, 2026

Automated audit: This PR was generated by NLPM, a natural language programming linter, running via claude-code-action. Please evaluate the diff on its merits.

Security Issues (Medium)

commands/generate-release.ps1 has two related content-injection risks:

1. Untrusted origin remote URL

The script calls git remote get-url origin and derives $repoPath from the result, which it then passes directly to gh api "repos/$repoPath/commits/$sha". If an attacker can modify the origin remote (e.g. via git remote set-url origin), the script will make GitHub API calls for an attacker-controlled repo and embed that repo's data into the release notes.

2. Unsanitized commit message in markdown output

Commit subjects (git log --pretty=format:'%s') are written verbatim into the release notes file:

Add-Content -Path $filename -Value "- [``$shortSha``]($repoUrl/commit/$sha) — $message by @$username"

A commit subject like [evil link](https://attacker.example) or <script>alert(1)</script> would be rendered as-is if the markdown file is published or displayed in a web context.

Fix

Remote URL validation — added a regex guard immediately after parsing $repoUrl. If the URL does not match the expected https://github.com/owner/repo pattern, the script aborts before making any API call:

if ($repoUrl -notmatch '^https://github\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$') {
    Write-Error "Unexpected remote URL '$repoUrl' — aborting to prevent unintended GitHub API calls."
    Pop-Location
    exit 1
}

Commit message escaping — markdown brackets and HTML angle brackets are escaped before writing to the output file:

$safemessage = $message -replace '\[', '\[' -replace '\]', '\]' -replace '<', '&lt;' -replace '>', '&gt;'
Add-Content -Path $filename -Value "- [``$shortSha``]($repoUrl/commit/$sha) — $safemessage by @$username"

Both changes are additive — no existing functionality is affected.

…rate-release.ps1

Two content-injection fixes:
1. Validate that $repoUrl matches the expected GitHub URL pattern before
   making any gh api calls. A tampered git remote (e.g. via
   `git remote set-url`) could otherwise direct API calls to an
   attacker-controlled repo.
2. Escape markdown metacharacters ([, ], <, >) in commit messages before
   writing them to the release notes file. Raw commit subjects are
   attacker-controlled strings that could inject markdown links or HTML
   if the release file is later rendered.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the commands/generate-release.ps1 helper script against content injection by validating the origin remote URL before using it in GitHub API requests, and by escaping commit subjects before emitting them into release-note markdown.

Changes:

  • Added a guard to reject unexpected origin remote URL formats before calling gh api.
  • Escaped certain markdown/HTML characters in commit subjects before writing release notes.

Comment on lines +20 to +22
# Validate remote URL is a standard GitHub repo path (guard against tampered remotes)
if ($repoUrl -notmatch '^https://github\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$') {
Write-Error "Unexpected remote URL '$repoUrl' — aborting to prevent unintended GitHub API calls."
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The remote URL validation only checks that the URL is on github.com and has an owner/repo shape, but it still allows origin to point to a different GitHub repository. That means a tampered remote can still cause gh api repos/$repoPath/... to fetch and embed data from an attacker-controlled repo. Consider sourcing the repo identity from a trusted channel when available (e.g., $env:GITHUB_REPOSITORY in CI) and/or adding an explicit -RepoPath/-RepoUrl parameter, and then validating that the remote-derived value matches it before continuing.

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +25
# Validate remote URL is a standard GitHub repo path (guard against tampered remotes)
if ($repoUrl -notmatch '^https://github\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$') {
Write-Error "Unexpected remote URL '$repoUrl' — aborting to prevent unintended GitHub API calls."
Pop-Location
exit 1
}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL regex is very strict and will reject common valid git remote formats like ssh://git@github.com/owner/repo(.git) or a trailing slash. If contributors use those remote URL styles, the script will now fail even though the repo is legitimate. Consider normalizing additional git remote URL formats to the canonical https URL before validation, or extending the validation to accept those equivalent forms.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +79
# Escape markdown special characters in commit message to prevent content injection
$safemessage = $message -replace '\[', '\[' -replace '\]', '\]' -replace '<', '&lt;' -replace '>', '&gt;'
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Escaping </> without escaping & first can be bypassed by a commit subject containing pre-escaped entities like &lt;script&gt;.... Consider performing proper HTML escaping (escape & before </>, or use a built-in HTML encoder) before writing the message into markdown.

Suggested change
# Escape markdown special characters in commit message to prevent content injection
$safemessage = $message -replace '\[', '\[' -replace '\]', '\]' -replace '<', '&lt;' -replace '>', '&gt;'
# Escape HTML first, then escape markdown link delimiters in the commit message to prevent content injection
$safemessage = [System.Net.WebUtility]::HtmlEncode($message) -replace '\[', '\[' -replace '\]', '\]'

Copilot uses AI. Check for mistakes.
Comment on lines +79 to +82
$safemessage = $message -replace '\[', '\[' -replace '\]', '\]' -replace '<', '&lt;' -replace '>', '&gt;'

# Add commit line to release.md
Add-Content -Path $filename -Value "- [``$shortSha``]($repoUrl/commit/$sha) — $message by @$username"
Add-Content -Path $filename -Value "- [``$shortSha``]($repoUrl/commit/$sha) — $safemessage by @$username"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable name $safemessage is inconsistent with the casing used elsewhere in this script (e.g., $repoUrl, $shortSha). Consider renaming to $safeMessage for readability and consistency.

Copilot uses AI. Check for mistakes.
IvanMurzak

This comment was marked as outdated.

Copy link
Copy Markdown
Owner

@IvanMurzak IvanMurzak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are critical issues were detected by Copilot

@github-actions
Copy link
Copy Markdown
Contributor

Test Results

   12 files    468 suites   40m 37s ⏱️
  799 tests   799 ✅ 0 💤 0 ❌
4 794 runs  4 794 ✅ 0 💤 0 ❌

Results for commit 03cea9a.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants