Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/build-and-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ jobs:
shell: bash
run: rm -rf dist/.man dist/nfpm.yaml

- name: Derive the numeric MSI version
if: inputs.platform == 'windows'
id: msi_version
shell: bash
# MSI ProductVersion accepts only numeric major.minor.build, so the
# windows-package action rejects pre-release identifiers such as
# 0.1.0-beta1. The suffix is stripped for the installer alone; every
# other artefact keeps the full crate version.
run: |
version="${{ inputs.version }}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' 'Reusable workflow and callers:'
rg -n -C 10 \
  'build-and-package\.yml|needs\.metadata\.outputs\.version|outputs:|version:|cargo metadata|semver|validate.*version|version.*validate' \
  .github/workflows

printf '%s\n' 'Relevant workflow sections:'
sed -n '130,190p' .github/workflows/build-and-package.yml
sed -n '1,130p' .github/workflows/release.yml

Repository: leynos/netsuke

Length of output: 31304


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' 'Cargo version action files:'
git ls-files '.github/actions/ensure-cargo-version' '.github/actions/export-cargo-metadata'
find .github/actions -maxdepth 2 -type f \( -iname '*cargo*version*' -o -iname '*cargo*metadata*' \) -print

printf '%s\n' 'Version extraction and validation references:'
rg -n -C 8 \
  'ensure-cargo-version|crate-version|export-cargo-metadata|cargo metadata|semver|version.*valid|validate.*version|check-tag' \
  .github/actions .github/workflows

Repository: leynos/shared-actions

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' 'ensure-cargo-version action:'
cat -n .github/actions/ensure-cargo-version/action.yml
printf '%s\n' 'ensure_cargo_version.py:'
cat -n .github/actions/ensure-cargo-version/scripts/ensure_cargo_version.py
printf '%s\n' 'export-cargo-metadata action:'
cat -n .github/actions/export-cargo-metadata/action.yml
printf '%s\n' 'read_manifest.py:'
cat -n .github/actions/export-cargo-metadata/scripts/read_manifest.py

Repository: leynos/shared-actions

Length of output: 22928


🏁 Script executed on selected repositories:

#!/bin/bash
set -euo pipefail

printf '%s\n' 'Release-mode decision and callers:'
rg -n -C 12 \
  'determine-release-modes|should-publish|workflow_call|release\.yml|netsuke.*release|uses:.*release' \
  .github/actions .github/workflows README.md 2>/dev/null || true

printf '%s\n' 'Exact release-mode action:'
find .github/actions -maxdepth 3 -type f -path '*determine-release-modes*' -print

Repositories: leynos/netsuke, leynos/shared-actions

Length of output: 63879


🏁 Script executed (no clone):

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import os
import subprocess

payload = '0.1.0"; printf "INJECTED\\n"; #'
unsafe_script = f'version="{payload}"\nprintf "version=%s\\n" "$version"\n'
safe_script = 'version="$INPUT_VERSION"\nprintf "version=%s\\n" "$version"\n'

unsafe = subprocess.run(
    ["bash", "-c", unsafe_script],
    text=True,
    capture_output=True,
    check=False,
)
safe = subprocess.run(
    ["bash", "-c", safe_script],
    env={**os.environ, "INPUT_VERSION": payload},
    text=True,
    capture_output=True,
    check=False,
)

print("unsafe_returncode:", unsafe.returncode)
print("unsafe_stdout:", repr(unsafe.stdout))
print("safe_returncode:", safe.returncode)
print("safe_stdout:", repr(safe.stdout))

assert "INJECTED" in unsafe.stdout
assert "INJECTED" not in safe.stdout
assert payload in safe.stdout
PY

Length of output: 354


Injection (CWE-78): Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Reachability: External · Exploitability: Trivial

Pass inputs.version through an environment variable before Bash parses the script.

The reusable workflow accepts version from callers. Shell syntax in this value can execute commands on the Windows runner. Read version="$INPUT_VERSION" and validate strict SemVer before writing GITHUB_OUTPUT.

🧰 Tools
🪛 zizmor (1.29.0)

[error] 165-165: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-and-package.yml at line 165, Update the workflow
step around the version assignment to pass the caller-provided version through
an environment variable before Bash evaluates it, then read it from
INPUT_VERSION. Validate the value against strict SemVer and only write
GITHUB_OUTPUT after validation succeeds.

Source: Linters/SAST tools

echo "value=${version%%-*}" >> "$GITHUB_OUTPUT"

- name: Build Windows installer package
if: inputs.platform == 'windows'
id: package_windows
Expand All @@ -164,7 +176,7 @@ jobs:
application-path: ${{ steps.stage_paths.outputs.binary_path }}
license-rtf-path: ${{ steps.stage_paths.outputs.license_path }}
architecture: ${{ inputs['msi-arch'] }}
version: ${{ inputs.version }}
version: ${{ steps.msi_version.outputs.value }}
output-basename: ${{ inputs['bin-name'] }}
output-directory: dist
license-plaintext-path: LICENSE
Expand Down
Loading