Repository navigation
fix(security): close 45 open vulnerability alerts #3583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 60 commits
Commits
Show all changes
71 commits
Select commit
Hold shift + click to select a range
c20414b
fix(security): close 43 open vulnerability alerts
ogabasseyy 57d4963
fix(security): narrow SARIF filter to the audited checkout finding
ogabasseyy dabcd16
fix(security): harden SARIF filter, drop unused firebase-admin
ogabasseyy b07103e
fix(security): spoof-proof SARIF filter matching
ogabasseyy d6e047d
fix(security): tidy release-age exemptions
ogabasseyy e91adae
fix(security): pin SARIF exemption by computed region
ogabasseyy e99a498
fix(security): positional SARIF tripwire, exact path match
ogabasseyy b1d07b6
fix(security): remove head-copy fallback, bind tripwire to resolution
ogabasseyy 6e3e610
fix(security): structural tripwire for resolver and agent
ogabasseyy 2327ef4
fix(security): job-scope SARIF guard, no-checkout no-op
ogabasseyy 75230d5
fix(security): exact dir path, guard conjunct validation
ogabasseyy a05594d
fix(security): exact trusted ref, assert trusted credentials
ogabasseyy 81c3782
fix(security): exact SARIF span end + survivor warning for shape drift
ogabasseyy 3975fd9
fix(security): pin trusted checkout action/repo; bind script consumer…
ogabasseyy a58e672
fix(security): audit all resolver output writes, scope muse flags, pi…
ogabasseyy db25fde
fix(security): always-audit on empty scans, token/installer/rebind gu…
ogabasseyy 04dad73
fix(security): exact installer checksums + structural URL validation
ogabasseyy cd7f4ba
fix(security): per-step argv0 allowlists, flag-parsing operand rule
ogabasseyy 130581a
refactor(security): extract SARIF auditor to tested modules
ogabasseyy 56bfb7d
fix(security): close Codex-18 P1s and Muse round lows in SARIF auditor
ogabasseyy 59a9bc1
fix(security): close Codex-19 P1s (trusted-write, helper audit, chang…
ogabasseyy 8ed3aab
fix(security): close Codex-6-P1 + Muse findings on the SARIF auditor
ogabasseyy 739733f
fix(security): anchor auditor to GITHUB_WORKSPACE, widen selftest cov…
ogabasseyy d67dcf7
fix(security): close Codex round-23 auditor evasions (5 P1s)
ogabasseyy 8edb87f
fix(security): gate new install module in base-filter existence check
ogabasseyy db63cd1
fix(security): close Codex d67dcf7b evasions (heredoc, scalar boundary)
ogabasseyy f5ca446
fix(security): close 6 code P1s (copy-dest, poison, deferred, perl, w…
ogabasseyy 7a2ba86
fix(security): close Codex P1s on f5ca446e (loaders, toctou, staging,…
ogabasseyy 84eeb5c
fix(security): close Codex 9-P1 round on 7a2ba86341 (aliases, indirec…
ogabasseyy db274fc
fix(security): hono 4.13.7 + node-forge CVE-2026-85393 backport
ogabasseyy bdd6574
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy 8dbf2b6
fix(security): close Codex 5-P1 round on bdd6574b8e (cmdfiles, alias/…
ogabasseyy 9df9f9d
fix(security): use Codex exact P1 mutations as regression cases
ogabasseyy c25b335
fix(security): close Codex 5-P1 round on 9df9f9d67f (traversal, enabl…
ogabasseyy b19339c
fix(security): close Codex 7-P1 round on c25b335b5 (hash, peel, escap…
ogabasseyy 7a658a3
fix(security): close Codex 2-P1 round on b19339c9 (alt shells, enviro…
ogabasseyy 388d470
fix(security): close Codex 5-P1 round on 7a658a32d6 (awk-alias, procf…
ogabasseyy 46adfc3
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy 8f1db1b
fix(security): close 7 Codex P1 + 3 CodeRabbit round (wrappers, @P, j…
ogabasseyy e5ad8c1
fix(security): close 5 Codex P1 + lows (sqlite3, install-shadow, exit…
ogabasseyy ed41a4d
Merge branch 'main' into fix/security-43-vulns
ogabasseyy 773f806
Merge branch 'main' into fix/security-43-vulns
ogabasseyy 6f013a0
fix(security): close 4 Codex P1 on 773f80652 (gcc, escapes, subscript…
ogabasseyy e060d4e
fix(security): close 10 missed Codex P1s + split auditor under 300-li…
ogabasseyy f146b44
fix(security): close 5 Codex P1s (jshell, ssh-keygen, pwsh, container…
ogabasseyy 81350d1
merge: update fix/security-43-vulns with main (PDP/mcp refactors #360…
ogabasseyy 95a5207
fix(security): close 15 Codex P1s on e060d4ea/f146b44/81350d13
ogabasseyy 51c468e
fix(security-audit): close 11 Codex P1s on 95a52076 + 2 CodeRabbit fi…
ogabasseyy 8e92245
fix(security-audit): close 3 new Codex findings on 51c468ec73 (rpm/m4…
ogabasseyy 4e88324
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy 0cfdb93
fix(security-audit): close 3 CodeRabbit findings on 4e88324c (arith-h…
ogabasseyy 95a2590
fix(security-audit): close 2 Codex P1s on 0cfdb9336f (binutils plugin…
ogabasseyy c9d7987
fix(security-audit): close 3 Codex P1s on 95a2590d7e (7z, hg, julia)
ogabasseyy 87f37da
fix(security-audit): close 2 Codex P1s on c9d79877ca (lldb, anchor-flow)
ogabasseyy 31e3ad0
fix(security-audit): close 2 Codex P1s on 87f37da731 (dotnet, bash-func)
ogabasseyy 44e6962
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy cd810d2
chore(web): refresh storefront-edge inventory snapshot for main #3617
ogabasseyy c3aa7da
fix(security-audit): close 9 Codex P1s on cd810d2cc5 (round 15)
ogabasseyy ca34d36
fix(security-audit): close 3 cursor + 3 Codex P1s on c3aa7daa71 (roun…
ogabasseyy 80bdde4
fix(security): close 4 round-17 Codex P1s (varmap ops, gfortran -B, g…
ogabasseyy 7a9af75
test(security): exact-mutation regressions for round-17 P1s
ogabasseyy 2695ed9
fix(security): reject brace expansion in exec paths (cursor High)
ogabasseyy a8804a2
fix(security): close 3 round-18 Codex P1s (runghc, ${BASH}, proc task)
ogabasseyy 566bd79
fix(security): close 12 round-19 Codex P1s + symlink low
ogabasseyy 1484b8f
fix(security): close 5 round-20 Codex P1s + CODEOWNERS medium
ogabasseyy 8beea96
fix(security): close 4 round-21 Codex P1s + notes medium
ogabasseyy 945533a
fix(security): close 4 round-22 Codex P1s
ogabasseyy f8a9a2f
fix(security): close 5 round-23 Codex P1s
ogabasseyy 06b8fbd
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy ebe61cc
fix(security-audit): round-24 Codex findings - bison loader, glob arg…
ogabasseyy 357110d
fix(security-audit): round-25 Codex findings - jar/upx destinations, …
ogabasseyy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # Muse Code PR reviewer (advisory only, never blocks merges) | ||
|
|
||
| Runs automatically on every same-repo pull request. It collects the PR diff, | ||
| runs `muse exec` headless with the repo checked out, and posts the result as | ||
| a PR review comment. Workflow: `.github/workflows/muse-code-review.yml`. | ||
|
|
||
| ## Billing | ||
|
|
||
| Whatever credential is stored in the META_API_KEY secret. That can be the | ||
| subscription-linked key from `muse login` onboarding (flat monthly rate, | ||
| subject to plan prompt limits) or a pay-as-you-go Meta Model API key. The | ||
| workflow cannot tell the difference; verify billing on dev.meta.ai. | ||
|
|
||
| ## Key hygiene | ||
|
|
||
| The agent holds this key with web tools on (see `run.sh` in | ||
| `.github/scripts/muse-review/`): | ||
|
|
||
| - minimum scope: a key that can only run model prompts, nothing else. | ||
| - rotation trigger: rotate immediately if any posted review looks tampered | ||
| with, exfiltrated, or off-mission; treat odd output as compromise. | ||
| - spending cap: set plan/prompt limits or spend alerts on dev.meta.ai so one | ||
| malicious same-repo PR cannot silently burn quota. | ||
|
|
||
| ## Recency | ||
|
|
||
| Web tools are ON so every review verifies against current official docs | ||
| instead of training memory. The agent determines the repo's stack/versions | ||
| from manifests, checks for deprecated APIs and better modern alternatives, | ||
| and cites sources. A redaction step scrubs common secret patterns from the | ||
| review body before posting (defense in depth, since web access widens | ||
| prompt-injection exfil options). | ||
|
|
||
| ## Quota safety | ||
|
|
||
| Subscription plans cap prompts per rolling window, so this workflow stays | ||
| cheap and advisory: | ||
|
|
||
| - concurrency cancel-in-progress: only the latest push per PR is reviewed | ||
| - bounded prompt (diff + repo guidance; the agent reads full files itself) | ||
| - --max-model-steps cap + job timeout | ||
| - never fails the build and never posts a commit status gate, EXCEPT the | ||
| trusted-scripts resolver: a missing default-branch scripts checkout exits | ||
| 1 (fail closed) rather than silently running PR-controlled scripts with | ||
| tokens. This workflow must stay out of required branch-protection checks | ||
| so that red X degrades the advisory review without blocking merges. | ||
|
|
||
| Forks skipped by the job `if` (head repo check) — load-bearing under | ||
| pull_request_target, which WOULD expose secrets to forks otherwise. | ||
|
|
||
| ## Layout | ||
|
|
||
| The workflow file only orchestrates steps; every shell program lives in | ||
| `.github/scripts/muse-review/` (each file under 300 lines per repo rules): | ||
|
|
||
| - lib.sh: shared pure helpers (redact, truncate, dedupe, neutralize) | ||
| - collect.sh: PR metadata, changed files, manifest, inter-phase vars | ||
| - diff.sh: unified diff + removed-lines supplement | ||
| - guidance.sh: repo guidance (trusted base first, head labeled UNTRUSTED) | ||
| - prompt.sh: prompt assembly + pre-run dedupe check | ||
| - guard.sh: pre-invocation head-freshness check (owns the GitHub token) | ||
| - install.sh: pinned Muse CLI install with SHA256 verification | ||
| - run.sh: headless agent invocation (no GitHub token in env) | ||
| - post.sh: staleness re-check, render, inline threads, post | ||
| - ranges.pl: diff-range extractor (JSON, escape-safe) | ||
| - clean.jq / validate.jq / dedupe.jq / fallback.jq: finding/dedupe filters | ||
| - schema.json: agent output contract | ||
| - test.sh: regression suite (runs in muse-review-selftest.yml) | ||
|
|
||
| ## Prerequisites per repo | ||
|
|
||
| - Secret META_API_KEY (repo Settings -> Secrets and variables -> Actions) | ||
| - Optional repo variables: MUSE_MODEL, MUSE_REASONING_EFFORT |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| #!/usr/bin/env python3 | ||
| """Drop one audited checkout finding from Semgrep SARIF output. | ||
|
|
||
| Semgrep honors nosemgrep for its exit code but still emits suppressed | ||
| findings into --sarif output with suppressions:[{kind:inSource}], and | ||
| GitHub code scanning ignores that flag -- the finding stays open as a | ||
| phantom alert. This filter repairs the transport for exactly one | ||
| audited finding (the reviewed pull_request_target checkout) after a | ||
| fail-closed drift audit of the hardening the exemption rests on. | ||
| Any drift keeps the SARIF unfiltered and fails the job. | ||
| """ | ||
| import json | ||
| import os | ||
| import posixpath | ||
| import sys | ||
| from types import SimpleNamespace | ||
| from semgrep_sarif_audit import (audit_flow_with, | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| audit_pr_checkout, | ||
| audit_trusted_checkout, find_pr_refs, | ||
| load_workflow) | ||
| from semgrep_sarif_bashfunc import audit_reviewer_env_block | ||
| from semgrep_sarif_consumer import (audit_helpers, | ||
| audit_invocations, | ||
| audit_path_literals, | ||
| audit_resolver, | ||
| audit_run_hygiene, | ||
| audit_script_dir) | ||
| from semgrep_sarif_container import audit_container_image | ||
| from semgrep_sarif_order import audit_checkout_order | ||
| from semgrep_sarif_helpertree import audit_trusted_changed | ||
| from semgrep_sarif_pins import AUDITED_PATH, AUDITED_RULE_ID | ||
| from semgrep_sarif_agent import audit_agent_runner | ||
| from semgrep_sarif_runner import audit_installer | ||
| from semgrep_sarif_agentenv import audit_agent_env | ||
| from semgrep_sarif_steps import audit_step_commands | ||
|
|
||
| def main(): | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| drift = [] | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| # Resolve all file reads against the workspace root, not the | ||
| # process CWD: a future working-directory default would | ||
| # otherwise make the audit read the wrong tree (or report an | ||
| # "empty scan" exit 0) instead of failing closed. | ||
| root = os.environ.get("GITHUB_WORKSPACE") or os.getcwd() | ||
| try: | ||
| os.chdir(root) | ||
| except OSError as exc: | ||
| print(f"::error::Cannot enter workspace {root} ({exc}).") | ||
| return 1 | ||
| code, workflow, raw = load_workflow(AUDITED_PATH) | ||
| ctx = SimpleNamespace(code_lines=code, workflow_lines=workflow, | ||
| workflow_raw=raw, pr_refs=[], span=(0, 0), | ||
| trusted=[], resolve=[], joined=[]) | ||
| ctx.pr_refs = find_pr_refs(ctx, drift) | ||
| # The change signal gates even the no-checkout exit: a trusted- | ||
| # tree edit that also removes the checkout still needs eyes. | ||
| # So does the with: shape: a flow/alias value hides the PR | ||
| # ref that pr_refs looks for, which must fail the run | ||
| # instead of taking the removed-checkout early return. | ||
| audit_trusted_changed(drift) | ||
| audit_flow_with(ctx, drift) | ||
| if not ctx.pr_refs: | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| # No PR-controlled checkout left to exempt (e.g. removed in | ||
| # favor of API-fetched diffs): nothing to filter, and failing | ||
| # here would punish the safest possible change — unless drift | ||
| # was recorded (trusted-tree change, hidden flow/alias ref), | ||
| # which always needs review. Labels print (like the main | ||
| # drift exit) so the message names the actual cause. | ||
| if drift: | ||
| print("::error::No PR-controlled checkout left in " | ||
| + AUDITED_PATH + " but drift was recorded (" | ||
| + ", ".join(drift) + "); needs human review.") | ||
| return 1 | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| print("::notice::No PR-controlled checkout in " + AUDITED_PATH | ||
| + "; exemption inactive.") | ||
| return 0 | ||
| audit_pr_checkout(ctx, drift) | ||
| audit_trusted_checkout(ctx, drift) | ||
| audit_resolver(ctx, drift) | ||
| audit_path_literals(ctx, drift) | ||
| audit_checkout_order(ctx, drift) | ||
| audit_container_image(ctx, drift) | ||
| audit_invocations(ctx, drift) | ||
| audit_script_dir(ctx, drift) | ||
| audit_run_hygiene(ctx, drift) | ||
| audit_reviewer_env_block(ctx.workflow_lines, drift) | ||
| audit_step_commands(ctx, drift) | ||
| audit_agent_env(ctx, drift) | ||
| audit_agent_runner(drift) | ||
| audit_installer(drift) | ||
| audit_helpers(ctx, drift) | ||
| if drift: | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| print(f"::error::muse-code-review.yml hardening drifted " | ||
| f"({', '.join(drift)}); keeping SARIF unfiltered.") | ||
| return 1 | ||
|
|
||
| def is_audited_checkout(result): | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| suppressions = result.get("suppressions") or [] | ||
| if not suppressions or not all( | ||
| s.get("kind") == "inSource" for s in suppressions): | ||
| return False | ||
| if result.get("ruleId") != AUDITED_RULE_ID: | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| return False | ||
| locations = result.get("locations", []) | ||
| if not locations: | ||
| return False | ||
| for loc in locations: | ||
| physical = loc.get("physicalLocation", {}) | ||
| uri = (physical.get("artifactLocation", {}).get("uri", "") | ||
| or "").replace("\\", "/").strip() | ||
| # Exact normalized match: a suffix test would also accept | ||
| # a nested lookalike (e.g. archive/.github/workflows/...). | ||
| if posixpath.normpath(uri) != AUDITED_PATH: | ||
| return False | ||
| # Pin the exact audited finding by region, not just the | ||
| # file: a second suppressed checkout elsewhere in the | ||
| # workflow must stay visible. The span is computed from | ||
| # the workflow itself (no hardcoded lines, no snippet | ||
| # dependency); anything unlocatable fails closed. | ||
| start_line = physical.get("region", {}).get("startLine") | ||
| if not isinstance(start_line, int): | ||
| return False | ||
| if not ctx.span[0] or not (ctx.span[0] | ||
| <= start_line <= ctx.span[1]): | ||
| return False | ||
| return True | ||
|
|
||
| if not (os.path.isfile("semgrep.sarif") | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| and os.path.getsize("semgrep.sarif") > 0): | ||
| # Empty scan (e.g. a runner-only PR): the audit above still | ||
| # ran and passed; there is just nothing to filter. | ||
| print("::notice::Drift audit passed with no SARIF to filter " | ||
| "(empty scan); exemption inactive.") | ||
| return 0 | ||
| try: | ||
| with open("semgrep.sarif") as fh: | ||
| sarif = json.load(fh) | ||
| except (json.JSONDecodeError, OSError) as exc: | ||
| # A truncated/unreadable scan artifact must fail loudly with | ||
| # cause, not with a raw traceback. | ||
| print(f"::error::SARIF parse failed ({exc}); keeping " | ||
| f"semgrep.sarif unfiltered.") | ||
| return 1 | ||
| for run in sarif.get("runs", []): | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| kept = [] | ||
| for result in run.get("results", []): | ||
| if is_audited_checkout(result): | ||
| continue | ||
| kept.append(result) | ||
| # Shape/suppression drift is fail-closed (the alert | ||
| # re-opens) but otherwise silent: surface it so the | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| # cause (emitter shape change vs removed nosemgrep) is | ||
| # investigated instead of the filter being blamed. | ||
| for loc in result.get("locations", []): | ||
| physical = loc.get("physicalLocation", {}) | ||
| uri = (physical.get("artifactLocation", {}) | ||
| .get("uri", "") or "").replace("\\", "/").strip() | ||
| if result.get("ruleId") == AUDITED_RULE_ID \ | ||
| and posixpath.normpath(uri) == AUDITED_PATH: | ||
| print("::warning::Audited checkout finding present " | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| "but not filtered (suppressions removed or " | ||
| "SARIF shape changed?); alert 1498 may " | ||
| "re-open. Audit: " + AUDITED_PATH + ".") | ||
| break | ||
| run["results"] = kept | ||
| # Atomic replace: a truncate-then-write crash (disk-full, | ||
| # preemption) would leave an empty/truncated report and | ||
| # lose unrelated findings, so stage aside and rename. | ||
| with open("semgrep.sarif.tmp", "w") as fh: | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| json.dump(sarif, fh) | ||
|
ogabasseyy marked this conversation as resolved.
Resolved
|
||
| fh.flush() | ||
| os.fsync(fh.fileno()) | ||
| os.replace("semgrep.sarif.tmp", "semgrep.sarif") | ||
| return 0 | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| sys.exit(main()) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.