-
Notifications
You must be signed in to change notification settings - Fork 296
Description
Weekly security red team scan completed on 2026-02-22 (Sunday full scan). 1 confirmed finding requiring action: an incomplete security fix in upload_assets.cjs. 2 low-risk mitigated patterns and 1 test-only accepted-risk pattern also documented.
Scan Summary
| Metric | Value |
|---|---|
| Scan Mode | WEEKLY FULL (Sunday) |
| Technique | full-comprehensive (all 6 techniques) |
| Files Analyzed | 250 (216 .cjs + 34 .sh) |
| Confirmed Findings | 1 (Medium) |
| Mitigated/Low Risk | 2 |
| Accepted Risk | 1 (test-only) |
| Malicious Patterns | 0 |
| Secret Exfiltration | 0 |
| Backdoors | 0 |
Finding 1 — INCOMPLETE SECURITY FIX (Medium)
Location: actions/setup/js/upload_assets.cjs:156
Description: The security fix commit d07e64c3 ("fix: supply chain and shell injection security findings", Feb 20 2026) converted all template-string exec.exec() calls in upload_assets.cjs to the safe array form — except line 156, which still uses a template string with an unsanitized value:
// Line 156 — NOT fixed by d07e64c3
await exec.exec(`git add "\$\{targetFileName}"`);All other exec.exec calls in the same file were correctly updated:
await exec.exec("git", ["rev-parse", "--verify", `origin/\$\{normalizedBranchName}`]);
await exec.exec("git", ["checkout", "-B", normalizedBranchName, ...]);
await exec.exec("git", ["push", "origin", normalizedBranchName]);targetFileName is sourced from agent output JSON (loadAgentOutput() → result.items → asset.targetFileName) with no path or character sanitization applied before the exec call. A targetFileName containing " could break out of quoting; one containing ;, &&, or backticks could permit command injection.
Forensics Analysis:
- Line 156 introduced in commit
17ca20b8by Copilot on 2025-12-23 ("Remove inline mode and externalize all scripts via setup action") - Partial fix attempted in commit
d07e64c3by Copilot on 2026-02-20 ("fix: supply chain and shell injection security findings") — but this line was missed - No further fix commits since then
Remediation Task:
- Task 1 — Convert line 156 of
actions/setup/js/upload_assets.cjsto use the safe array form:This is consistent with the existing pattern used in the rest of the file after commit// Change from: await exec.exec(`git add "\$\{targetFileName}"`); // Change to: await exec.exec("git", ["add", targetFileName]);
d07e64c3.
Finding 2 — DYNAMIC EXEC (Low / Mitigated)
Location: actions/setup/js/push_to_pull_request_branch.cjs:312 and actions/setup/js/create_pull_request.cjs:568
Description: exec.exec(\git am ${patchFilePath}`)uses template string interpolation. However,patchFilePathis **internally generated** ingenerate_git_patch.cjs` via:
function getPatchPath(branchName) {
const sanitized = sanitizeBranchNameForPatch(branchName);
return `/tmp/gh-aw/aw-\$\{sanitized}.patch`;
}
// sanitizeBranchNameForPatch removes: / \ : * ? " < > |
// Result is always: /tmp/gh-aw/aw-(alphanumeric-dash-chars).patchThe sanitization constrains the path to characters safe for shell interpolation. No actionable fix required, but converting to array form would be defensive best practice.
Forensics: Introduced in commit b58fd691 by Copilot on 2026-02-21.
Recommendation (non-urgent):
- Consider converting to
exec.exec("git", ["am", patchFilePath])for consistency with the safe pattern used elsewhere in the codebase.
Finding 3 — SHELL EVAL IN TEST HELPER (Negligible / Accepted Risk)
Location: actions/setup/sh/clean_git_credentials_test.sh:34
Description: eval "\$\{condition}" is used in a test-only assert() helper function. All current callers pass hard-coded string literals. No external input reaches this eval.
Forensics: Introduced in commit 45f92f64 by Copilot on 2026-02-19 ("Recursively clean git credentials from all checkouts in workspace and /tmp/").
Recommendation: Low priority. Could be refactored to use a safer assertion mechanism if the test file evolves.
Techniques Executed (Full Comprehensive)
Technique Results Detail
| Technique | Status | Notes |
|---|---|---|
| Pattern Analysis | Complete | 1 confirmed finding (upload_assets), 2 mitigated |
| AST Inspection | No findings | No suspicious function names, no unusual exports |
| Entropy Analysis | No findings | No obfuscated/encoded strings |
| Network Analysis | No findings | validate_secrets.cjs makes expected API validation calls; all other URLs are docs refs or GitHub domains |
| Behavioral Analysis | No findings | Date logic is timestamps/expiry guards only; no time bombs; no persistence |
| Dependency Audit | No findings | No path traversal in require(); no known-compromised packages |
False Positives Investigated and Dismissed
- validate_secrets.cjs API calls — Legitimate diagnostic tool (maintenance workflow); calls api.anthropic.com, api.openai.com, api.search.brave.com, api.notion.com only to validate status codes of configured secrets. Only HTTP status codes are returned; key values are never logged or exfiltrated.
- Buffer.from(..., "base64") — Decodes GitHub API file contents (standard API pattern).
- String.fromCharCode() — Unicode normalization in
sanitize_content_core.cjs, not obfuscation. - IP 172.30.0.1 — Documented internal Docker network gateway in
convert_gateway_config_codex.sh. - patchFilePath template exec — Internally generated sanitized path
/tmp/gh-aw/aw-*.patch.
Next Steps
@pelikhan
- Fix: Apply remediation for Finding 1 — convert
upload_assets.cjs:156to the safe array form (1-line change) - Optional: Harden
push_to_pull_request_branch.cjs:312andcreate_pull_request.cjs:568by converting to array form for defensive consistency - Monitor: No new backdoors, secret exfiltration, or destructive code detected in this full scan
References:
- §22279189887
- Security fix commit:
d07e64c3("fix: supply chain and shell injection security findings", 2026-02-20)
Generated by Daily Security Red Team Agent