Skip to content
Merged
Show file tree
Hide file tree
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 Oct 1, 2026
57d4963
fix(security): narrow SARIF filter to the audited checkout finding
ogabasseyy Oct 1, 2026
dabcd16
fix(security): harden SARIF filter, drop unused firebase-admin
ogabasseyy Oct 1, 2026
b07103e
fix(security): spoof-proof SARIF filter matching
ogabasseyy Oct 1, 2026
d6e047d
fix(security): tidy release-age exemptions
ogabasseyy Oct 1, 2026
e91adae
fix(security): pin SARIF exemption by computed region
ogabasseyy Oct 1, 2026
e99a498
fix(security): positional SARIF tripwire, exact path match
ogabasseyy Oct 1, 2026
b1d07b6
fix(security): remove head-copy fallback, bind tripwire to resolution
ogabasseyy Oct 1, 2026
6e3e610
fix(security): structural tripwire for resolver and agent
ogabasseyy Oct 1, 2026
2327ef4
fix(security): job-scope SARIF guard, no-checkout no-op
ogabasseyy Oct 1, 2026
75230d5
fix(security): exact dir path, guard conjunct validation
ogabasseyy Oct 1, 2026
a05594d
fix(security): exact trusted ref, assert trusted credentials
ogabasseyy Oct 1, 2026
81c3782
fix(security): exact SARIF span end + survivor warning for shape drift
ogabasseyy Oct 1, 2026
3975fd9
fix(security): pin trusted checkout action/repo; bind script consumer…
ogabasseyy Oct 1, 2026
a58e672
fix(security): audit all resolver output writes, scope muse flags, pi…
ogabasseyy Oct 1, 2026
db25fde
fix(security): always-audit on empty scans, token/installer/rebind gu…
ogabasseyy Oct 1, 2026
04dad73
fix(security): exact installer checksums + structural URL validation
ogabasseyy Oct 1, 2026
cd7f4ba
fix(security): per-step argv0 allowlists, flag-parsing operand rule
ogabasseyy Oct 1, 2026
130581a
refactor(security): extract SARIF auditor to tested modules
ogabasseyy Oct 1, 2026
56bfb7d
fix(security): close Codex-18 P1s and Muse round lows in SARIF auditor
ogabasseyy Oct 1, 2026
59a9bc1
fix(security): close Codex-19 P1s (trusted-write, helper audit, chang…
ogabasseyy Oct 1, 2026
8ed3aab
fix(security): close Codex-6-P1 + Muse findings on the SARIF auditor
ogabasseyy Oct 1, 2026
739733f
fix(security): anchor auditor to GITHUB_WORKSPACE, widen selftest cov…
ogabasseyy Oct 1, 2026
d67dcf7
fix(security): close Codex round-23 auditor evasions (5 P1s)
ogabasseyy Oct 1, 2026
8edb87f
fix(security): gate new install module in base-filter existence check
ogabasseyy Oct 1, 2026
db63cd1
fix(security): close Codex d67dcf7b evasions (heredoc, scalar boundary)
ogabasseyy Oct 1, 2026
f5ca446
fix(security): close 6 code P1s (copy-dest, poison, deferred, perl, w…
ogabasseyy Oct 1, 2026
7a2ba86
fix(security): close Codex P1s on f5ca446e (loaders, toctou, staging,…
ogabasseyy Oct 2, 2026
84eeb5c
fix(security): close Codex 9-P1 round on 7a2ba86341 (aliases, indirec…
ogabasseyy Oct 2, 2026
db274fc
fix(security): hono 4.13.7 + node-forge CVE-2026-85393 backport
ogabasseyy Oct 2, 2026
bdd6574
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy Oct 2, 2026
8dbf2b6
fix(security): close Codex 5-P1 round on bdd6574b8e (cmdfiles, alias/…
ogabasseyy Oct 2, 2026
9df9f9d
fix(security): use Codex exact P1 mutations as regression cases
ogabasseyy Oct 2, 2026
c25b335
fix(security): close Codex 5-P1 round on 9df9f9d67f (traversal, enabl…
ogabasseyy Oct 2, 2026
b19339c
fix(security): close Codex 7-P1 round on c25b335b5 (hash, peel, escap…
ogabasseyy Oct 2, 2026
7a658a3
fix(security): close Codex 2-P1 round on b19339c9 (alt shells, enviro…
ogabasseyy Oct 2, 2026
388d470
fix(security): close Codex 5-P1 round on 7a658a32d6 (awk-alias, procf…
ogabasseyy Oct 2, 2026
46adfc3
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy Oct 2, 2026
8f1db1b
fix(security): close 7 Codex P1 + 3 CodeRabbit round (wrappers, @P, j…
ogabasseyy Oct 2, 2026
e5ad8c1
fix(security): close 5 Codex P1 + lows (sqlite3, install-shadow, exit…
ogabasseyy Oct 3, 2026
ed41a4d
Merge branch 'main' into fix/security-43-vulns
ogabasseyy Oct 3, 2026
773f806
Merge branch 'main' into fix/security-43-vulns
ogabasseyy Oct 3, 2026
6f013a0
fix(security): close 4 Codex P1 on 773f80652 (gcc, escapes, subscript…
ogabasseyy Oct 3, 2026
e060d4e
fix(security): close 10 missed Codex P1s + split auditor under 300-li…
ogabasseyy Oct 3, 2026
f146b44
fix(security): close 5 Codex P1s (jshell, ssh-keygen, pwsh, container…
ogabasseyy Oct 3, 2026
81350d1
merge: update fix/security-43-vulns with main (PDP/mcp refactors #360…
ogabasseyy Oct 3, 2026
95a5207
fix(security): close 15 Codex P1s on e060d4ea/f146b44/81350d13
ogabasseyy Oct 4, 2026
51c468e
fix(security-audit): close 11 Codex P1s on 95a52076 + 2 CodeRabbit fi…
ogabasseyy Oct 4, 2026
8e92245
fix(security-audit): close 3 new Codex findings on 51c468ec73 (rpm/m4…
ogabasseyy Oct 4, 2026
4e88324
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy Oct 4, 2026
0cfdb93
fix(security-audit): close 3 CodeRabbit findings on 4e88324c (arith-h…
ogabasseyy Oct 4, 2026
95a2590
fix(security-audit): close 2 Codex P1s on 0cfdb9336f (binutils plugin…
ogabasseyy Oct 4, 2026
c9d7987
fix(security-audit): close 3 Codex P1s on 95a2590d7e (7z, hg, julia)
ogabasseyy Oct 4, 2026
87f37da
fix(security-audit): close 2 Codex P1s on c9d79877ca (lldb, anchor-flow)
ogabasseyy Oct 4, 2026
31e3ad0
fix(security-audit): close 2 Codex P1s on 87f37da731 (dotnet, bash-func)
ogabasseyy Oct 4, 2026
44e6962
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy Oct 4, 2026
cd810d2
chore(web): refresh storefront-edge inventory snapshot for main #3617
ogabasseyy Oct 4, 2026
c3aa7da
fix(security-audit): close 9 Codex P1s on cd810d2cc5 (round 15)
ogabasseyy Oct 4, 2026
ca34d36
fix(security-audit): close 3 cursor + 3 Codex P1s on c3aa7daa71 (roun…
ogabasseyy Oct 4, 2026
80bdde4
fix(security): close 4 round-17 Codex P1s (varmap ops, gfortran -B, g…
ogabasseyy Oct 4, 2026
7a9af75
test(security): exact-mutation regressions for round-17 P1s
ogabasseyy Oct 4, 2026
2695ed9
fix(security): reject brace expansion in exec paths (cursor High)
ogabasseyy Oct 4, 2026
a8804a2
fix(security): close 3 round-18 Codex P1s (runghc, ${BASH}, proc task)
ogabasseyy Oct 4, 2026
566bd79
fix(security): close 12 round-19 Codex P1s + symlink low
ogabasseyy Oct 4, 2026
1484b8f
fix(security): close 5 round-20 Codex P1s + CODEOWNERS medium
ogabasseyy Oct 4, 2026
8beea96
fix(security): close 4 round-21 Codex P1s + notes medium
ogabasseyy Oct 4, 2026
945533a
fix(security): close 4 round-22 Codex P1s
ogabasseyy Oct 4, 2026
f8a9a2f
fix(security): close 5 round-23 Codex P1s
ogabasseyy Oct 4, 2026
06b8fbd
Merge remote-tracking branch 'origin/main' into fix/security-43-vulns
ogabasseyy Oct 4, 2026
ebe61cc
fix(security-audit): round-24 Codex findings - bison loader, glob arg…
ogabasseyy Oct 4, 2026
357110d
fix(security-audit): round-25 Codex findings - jar/upx destinations, …
ogabasseyy Oct 4, 2026
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
73 changes: 73 additions & 0 deletions .github/muse-code-review.md
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
7 changes: 5 additions & 2 deletions .github/scripts/muse-review/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ fi

tmp_bin="$(mktemp)"
trap 'rm -f "${tmp_bin}"' EXIT
# --proto '=https' forbids redirect downgrades; --retry rides out flakes.
curl --proto '=https' --tlsv1.2 --retry 3 --retry-all-errors \
# --disable first: curl reads $CURL_HOME/.curlrc or $HOME/.curlrc unless
# disabled as the first parameter; --proto '=https' forbids redirect
# downgrades; --retry rides out flakes. No -K/--config: a config file
# imports arguments as if typed on the command line.
curl --disable --proto '=https' --tlsv1.2 --retry 3 --retry-all-errors \
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
--connect-timeout 15 --max-time 600 -fsSL -o "${tmp_bin}" \
"https://lookaside.facebook.com/lookaside/muse/download/?channel=muse&version=${MUSE_VERSION}&file=${artifact}"

Expand Down
7 changes: 6 additions & 1 deletion .github/scripts/muse-review/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,12 @@ assert_eq "redact-ghr" "[REDACTED]" "$(redact 'tok ghr_faketoken1 y' | awk '{pri
assert_eq "redact-xoxr" "[REDACTED]" "$(redact 'tok xoxr-fake1 y' | awk '{print $2}')"
assert_eq "redact-xoxo" "[REDACTED]" "$(redact 'tok xoxo-fake2 y' | awk '{print $2}')"
assert_eq "redact-xoxe" "[REDACTED]" "$(redact 'tok xoxe-fake3 y' | awk '{print $2}')"
assert_eq "redact-aiza" "[REDACTED]" "$(redact 'key AIza0123456789AbCdEfGhIjKlMnOpQrStUvWXY end' | awk '{print $2}')"
# Assembled at runtime so no single literal matches the Google API key
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
# shape (secret scanning flags the 39-char AIza literal even in fixtures).
_aiza_fixture="AIza"
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
_aiza_fixture+="0123456789AbCdEfGhIjKlMnOpQrStUvWXY"
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
assert_eq "redact-aiza" "[REDACTED]" "$(redact "key ${_aiza_fixture} end" | awk '{print $2}')"
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
unset _aiza_fixture
assert_eq "redact-aiza-short" "AIzaShort" "$(redact 'tok AIzaShort y' | awk '{print $2}')"
assert_eq "redact-meta-assign" "META_API_KEY=[REDACTED]!" "$(redact 'leak META_API_KEY=hunter2hunter2hunter2!' | awk '{print $2}')"

Expand Down
177 changes: 177 additions & 0 deletions .github/scripts/semgrep-sarif-filter.py
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,
Comment thread
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():
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
drift = []
Comment thread
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:
Comment thread
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
Comment thread
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:
Comment thread
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):
Comment thread
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:
Comment thread
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")
Comment thread
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", []):
Comment thread
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
Comment thread
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 "
Comment thread
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:
Comment thread
ogabasseyy marked this conversation as resolved.
Resolved
json.dump(sarif, fh)
Comment thread
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())
Loading
Loading