Commit e956733
[patch] [bugfix]: Harden AI auto-reply against prompt injection; fix Swift grounding
Addresses PR review feedback.
SECURITY (review: Severity High -- injection could exfiltrate GITHUB_TOKEN).
The prompt embeds issue and comment text written by anyone on the internet,
and --yolo (== --allow-all) auto-approved Copilot's shell and file tools.
Verified locally that this was genuinely exploitable: the model ran 'cat' on a
canary file and returned its contents. Also verified that '--available-tools ""'
does NOT restrict anything -- it is treated as unset and leaves every tool
enabled -- so an allowlist would have been a false sense of safety.
Three independent controls, most important first:
1. Split into gate / generate / post jobs with per-job permissions. The
generate job -- the only one that feeds untrusted text to the model -- has
no issues permission, so even a full escape yields a token that cannot
comment or label. Enforced by GitHub, not by the CLI.
2. Drop --yolo and deny every tool by name. Verified: the CLI reports
"Permission to run this tool was denied" and logs its disabled tool list,
so upstream drift is visible in the run log.
3. --secret-env-vars strips GITHUB_TOKEN from tool environments and redacts
it from output.
Workflow-level permissions are now {} with each job opting in; backfill
re-declares issues:write so labeling still works.
STDOUT vs FILE (review: ai_reply.md may never be written).
With every tool denied Copilot cannot write a file, so this no longer depends
on a side effect. The prompt goes in on argv -- safe, since bash does not
re-scan command-substitution output -- and the reply is read back from
--output-format json, selecting the last assistant.message via jq. That is a
typed field rather than scraped human-readable stdout, and 'fromjson? // empty'
skips any non-JSON line so a stray write cannot abort the parse.
SWIFT GROUNDING (review: strip_and_cap is Obj-C shaped).
Confirmed: it scanned for the first ^#import, ^NS_ASSUME_NONNULL_BEGIN or ^@
line, so on Swift it only stopped because @objc sits at column 0, and it
swallowed the /// doc comment between 'import Foundation' and the declaration.
A Swift file whose first declaration had no leading @ would have stripped to
nothing. Now matches the MIT block itself, which is identical in both
languages, and drops 'import' lines too. Verified across all 31 manifest
files: no license leakage, no empty extracts, and Swift doc comments survive.
CHANGELOG: not updated -- this is CI tooling only, with no partner-visible
or user-visible change to the MSAL library.
Adds a temporary injection smoke test, deleted before merge.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>1 parent 6edbc65 commit e956733
2 files changed
Lines changed: 325 additions & 89 deletions
0 commit comments