Skip to content

security: harden CI pipeline against untrusted input (#41, #44, #45)#60

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
security/ci-pipeline-hardening
Jul 7, 2026
Merged

security: harden CI pipeline against untrusted input (#41, #44, #45)#60
Jose-Gael-Cruz-Lopez merged 1 commit into
mainfrom
security/ci-pipeline-hardening

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Collaborator

Closes #41, closes #44, closes #45.

First of a stacked series addressing the audit issues (merge bottom-up: this → #43#46/#47#48#51#54).

#41 (Critical) — Actions command/script injection

  • Untrusted/derived step outputs (commit_message, error_message, changes) now flow through env: and are referenced as quoted shell vars, never interpolated as ${{ }} inside run: bodies — auto_extract.yml, update_readmes.yml, closing_soon.yml. (contribution_approved.yml was already env-hardened in fix(ci): repair invalid contribution_approved workflow + harden untrusted inputs #55; this PR only pins its actions.)
  • contributor_email is validated (strict regex) and host/title are sanitized in Python before reaching git config / commit messages.

#44 (Security) — auto_extract.py untrusted input

  • TLS: removed the verify=False fallback — SSL errors now fail closed.
  • SSRF: safe_get() allows only http(s), resolves the host and rejects private/loopback/link-local/reserved IPs, and re-validates on every redirect hop.
  • Crashes: null model fields are coalesced (extracted.get(x) or ""), dedup uses listing.get(), and main() is wrapped so unexpected errors become a clean util.fail.

#45 (Security) — config hardening

  • permissions: contents: write added to update_readmes.yml.
  • All actions pinned to commit SHAs (checkout v4.3.1, setup-python v5.6.0, github-script v7.1.0); Python deps installed from a pinned requirements.txt.
  • "/' escaped in generated markup (util.format_link, generate_gallery.esc).
  • dangerouslyAllowSVG paired with a strict CSP + attachment disposition in next.config.ts.

Verification

  • ✅ All scripts py_compile
  • ✅ 17 unit checks pass for the new sanitize / email / SSRF / escape helpers (loopback, 169.254.169.254, RFC1918, file:// all rejected; public https allowed)
  • ✅ All 6 workflows parse as valid YAML
  • next build succeeds

Notes / not included

🤖 Generated with Claude Code

Closes #41, #44, #45.

#41 (Critical) — Actions command/script injection:
- Pass derived step outputs (commit_message, error_message, changes) through
  env: and reference them as quoted shell vars instead of interpolating
  ${{ }} directly into run: bodies (auto_extract.yml, update_readmes.yml,
  closing_soon.yml). contribution_approved.yml was already env-hardened in #55.
- Validate contributor_email and sanitize host/title in Python before they
  reach git config / commit messages (contribution_approved.py, auto_extract.py).

#44 (Security) — auto_extract.py untrusted input:
- Remove the verify=False TLS-bypass fallback (fail closed on SSL errors).
- Add SSRF guard: only http(s), resolve host and reject private/loopback/
  link-local/reserved ranges, re-check on every redirect hop (safe_get).
- Coalesce null model fields ((extracted.get(x) or "")) and use listing.get()
  in the dedup loop so null/missing fields don't crash the run.
- Wrap main() so unexpected errors become a clean util.fail.

#45 (Security) — config hardening:
- Add permissions: contents: write to update_readmes.yml.
- Pin all actions to commit SHAs (checkout v4.3.1, setup-python v5.6.0,
  github-script v7.1.0) and install Python deps from a pinned requirements.txt.
- Escape " and ' in generated markup (util.format_link, generate_gallery.esc).
- Pair dangerouslyAllowSVG with a strict CSP + attachment disposition in
  next.config.ts.

Verified: all scripts compile; 17 unit checks pass for the new sanitize/email/
SSRF/escape helpers; all 6 workflows parse; web build succeeds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment