Skip to content

🚨 [SECURITY] Security Red Team Findings - 2026-02-20 #17182

@github-actions

Description

@github-actions

Daily security red team scan completed for 2026-02-20. Two medium-priority security findings were identified in actions/setup/sh and actions/setup/js using the pattern-analysis technique (daily incremental scan, 437 files analyzed).

Overview

The scan identified no backdoors, secret exfiltration, or malicious obfuscation. All hardcoded credential patterns were confirmed as test fixtures. The two flagged issues are legitimate supply chain and shell injection risk patterns that should be remediated for defense-in-depth.


Finding 1: Supply Chain Risk — Unverified External Installer Execution

Severity: Medium
Location: actions/setup/sh/install_copilot_cli.sh:43,76

The script downloads a shell installer from https://raw.githubusercontent.com/github/copilot-cli/main/install.sh and executes it directly as root (sudo bash) with no SHA256 checksum verification. If the upstream URL is ever compromised or the CDN is intercepted, arbitrary code would run with root privileges on the runner.

Contrast: install_awf_binary.sh correctly downloads a checksums.txt and verifies SHA256 before execution — the same pattern should be applied here.

Forensics:

Relevant code (lines 40–76)
if curl -fsSL "$INSTALLER_URL" -o "$INSTALLER_TEMP" 2>&1; then
  echo "Successfully downloaded installer"
  return 0
fi
...
sudo VERSION="$VERSION" bash "$INSTALLER_TEMP"
# OR
sudo bash "$INSTALLER_TEMP"

Finding 2: Shell Injection Risk — exec() with Template String Branch Name

Severity: Low–Medium
Location: actions/setup/js/upload_assets.cjs:98–99,114,174

exec.exec() is called with template string arguments that interpolate normalizedBranchName directly into shell commands:

await exec.exec(`git rev-parse --verify origin/\$\{normalizedBranchName}`);
await exec.exec(`git checkout -B \$\{normalizedBranchName} origin/\$\{normalizedBranchName}`);
await exec.exec(`git checkout --orphan \$\{normalizedBranchName}`);
await exec.exec(`git push origin \$\{normalizedBranchName}`);

While normalizeBranchName() sanitizes via allowlist regex (/[^a-zA-Z0-9\-_/.]+/g), passing a single string to exec.exec() invokes the shell interpreter. The @actions/exec package supports an argument array form that bypasses shell parsing entirely and is safer.

Forensics:


Remediation Tasks

  • Task 1 (install_copilot_cli.sh): Add SHA256 checksum verification before executing the downloaded installer, following the pattern in install_awf_binary.sh. Pin to a specific commit SHA or release tag rather than main to eliminate TOCTOU risk.

    • If the upstream Copilot CLI installer does not publish checksums, consider vendoring the installer or pinning to a release artifact.
    • @pelikhan please review and confirm whether checksum verification is feasible for this installer.
  • Task 2 (upload_assets.cjs): Convert exec.exec() calls that use template strings to the array argument form:

    // Before (shell-interpreted):
    await exec.exec(`git checkout -B \$\{normalizedBranchName} origin/\$\{normalizedBranchName}`);
    // After (no shell, safer):
    await exec.exec("git", ["checkout", "-B", normalizedBranchName, `origin/\$\{normalizedBranchName}`]);

    Apply this pattern to all four call sites (lines 98, 99, 114, 174).


Confirmed Clean

View items confirmed non-malicious
Pattern Files Assessment
eval() usage render_template.test.cjs, interpolate_prompt.test.cjs, update_activation_comment.test.cjs Test harness only — standard Vitest pattern for loading CJS scripts
Hardcoded credentials redact_secrets.test.cjs (4 instances) Official placeholder values (AWS AKIA example, Google AIzaSy example) used to test redaction logic
Buffer.from(..., 'base64') Multiple files Legitimate GitHub Contents API response decoding
String.fromCharCode sanitize_content_core.cjs:663 Unicode full-width → half-width normalization, not obfuscation
rm -rf clean_git_credentials_test.sh, install_awf_binary.sh Scoped temp directories only
fs.unlinkSync safe_inputs_bootstrap.cjs:70, safe_outputs_bootstrap.cjs:62, mcp_handler_shell.cjs:77,115 Deleting own temp/config files with fully-qualified os.tmpdir() or hardcoded config paths
Suspicious keywords clean_git_credentials.sh, substitute_placeholders.test.cjs, create_pull_request.test.cjs Appear in comments explaining prevention, or in test strings for sanitization validation
Suspicious network domains All files No .ru, .cn, .tk, .xyz or other suspicious TLDs found
http.request to localhost safe_inputs_mcp_server_http.test.cjs Integration test against local port 4100 only

Scan Metadata

Field Value
Scan date 2026-02-20
Scan mode Daily Incremental
Technique Pattern Analysis
Files analyzed 437
True positives 2
False positives 25 (dismissed after review)
Run §22228465574
Cache /tmp/gh-aw/cache-memory/security-red-team

References:

Generated by Daily Security Red Team Agent

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions