AI review reads content submitted by whoever opened the pull request. On a public repository, that is anybody.
This is not a reason to avoid it. It is a reason to understand what it can be relied on for. The short version: an AI review is a signal, not a control, and a repository that treats it as a control has a gap where it thinks it has a gate.
The short answer
Section titled “The short answer”Three properties to hold in mind:
- Review instructions come from the pull request head branch. A contributor can change the criteria their own change is reviewed against, in the same pull request.
- A diff is untrusted input. Text in a code comment can attempt to influence the review that reads it.
- A review comments; it does not block. Merge gates are branch protection and rulesets, and they do not care what the review said.
Every control in this lesson follows from taking those three seriously rather than working around them.
Head-branch instruction reading
Section titled “Head-branch instruction reading”The property that surprises people most, and the one with real consequences.
Copilot code review reads .github/copilot-instructions.md and path-specific instruction files from
the head branch of the pull request — the branch containing the proposed change, not the base branch
the change targets.
Why it is designed that way: you can add or adjust review criteria and see the effect in the same pull request, without merging first. That is genuinely useful, and it is the same behaviour that makes instruction files iterable.
What it means for untrusted contributions: a fork pull request can include a modification to the instruction file. The review of that pull request applies the modified criteria.
A contributor could, for example, add to the instruction file a line telling the review not to comment on a particular directory, and the review of that same pull request would apply it.
What this does not do. It does not grant access to secrets, write to the base branch, alter branch protection, or produce an approval that satisfies a required review. The consequence is confined to what the review says.
Why that still matters. If your process treats “clean Copilot review” as meaningful signal on external contributions, that signal is attacker-influenceable. Not attacker-controlled — the reviewer is still reading the actual diff — but influenceable enough that it should not be load-bearing.
The controls that hold
Section titled “The controls that hold”The head-branch property is fine as long as your enforcement does not depend on the review.
Require human approval. Branch protection or a ruleset requiring at least one approving review from somebody with write access. Copilot’s review does not satisfy this, and that is the correct design.
Require status checks. CI runs from workflow definitions on the base branch when configured correctly, and its results are not editable from a fork pull request. This is where enforcement actually sits. See Workflow security.
Use CODEOWNERS. Changes to .github/** should require an owner’s approval. That covers workflow
files, instruction files and everything else that shapes how the repository evaluates its own changes.
Treat instruction-file changes as sensitive. They are a review-standards change. Same scrutiny as a CI configuration change, for the same reason.
Do not gate merges on AI review outcome. Not through automation, and not culturally. “Copilot found nothing so it is fine” is the failure mode, and it does not require an attacker to be harmful.
The pattern is the one running through this entire pillar: instructions shape, rulesets enforce. Everything an attacker can influence in this area sits on the shaping side.
Prompt injection through a diff
Section titled “Prompt injection through a diff”A model reads the changed code. Code contains comments. Comments contain text. Text can attempt to instruct.
An attempt looks roughly like a comment addressed to the reviewer rather than to a human — text telling the review to ignore certain criteria, to treat a section as already approved, or to report no findings.
We are describing the shape rather than providing working phrasings, deliberately. The defensive value is in recognising the pattern; the offensive value of a tuned payload is not something this site provides.
What defends against it:
Architecture, not detection. Filters help and are not a boundary. The reliable defence is that the review has no authority to begin with — it cannot approve, merge, or dismiss a required check, so influencing it changes a comment rather than an outcome.
Human approval on the merge path. A person reading the diff sees the injected comment, which is usually more conspicuous to a human than to a filter.
Read the diff, not just the review. If your process is “read Copilot’s comments, then approve”, the review is your only reader and influencing it influences you. If a human reads the change, the attempt is visible.
Deterministic checks carry the security weight. CodeQL, secret scanning and dependency review do not read comments as instructions. They are pattern and dataflow analysis, and text in a comment does not change their behaviour. This is the strongest single argument for keeping the deterministic layer healthy: it is the part of your pipeline that cannot be talked to.
Notice the attempt as a signal. A pull request containing text addressed to an automated reviewer is worth treating as suspicious in itself, independently of whether the attempt succeeded. It tells you something about the submission.
Fork pull requests specifically
Section titled “Fork pull requests specifically”The highest-risk surface, and the one where the distinction between review and CI matters most.
What a fork pull request can do: propose any change to any file, including workflows, instruction files and dependency manifests. The proposal is visible in the diff.
What it cannot do without a maintainer: run privileged workflows with repository secrets, write to the base branch, or merge. GitHub’s defaults for fork pull requests are conservative here, and those defaults are the control.
Where teams break it: using pull_request_target to run workflows with secrets against fork
content, then checking out the fork’s head. That combination hands repository secrets to arbitrary
submitted code, and it has nothing to do with AI review — it is the classic Actions misconfiguration,
covered fully in Workflow security.
The AI-specific addition: on fork pull requests, treat the review’s output as a reading aid, not as evidence. It is reading a diff you have not read, against criteria the author may have edited.
A worked threat model
Section titled “A worked threat model”Walking one repository through the analysis makes the abstractions concrete. Take a public open-source project accepting fork pull requests, with Copilot code review enabled automatically.
Asset: the integrity of what merges into main, and the repository’s secrets.
Adversary: anybody who can open a pull request, which is everybody.
What the adversary controls:
- The full content of the diff, including code, comments, documentation and configuration.
- The contents of
.github/copilot-instructions.mdand.github/instructions/**on their head branch. - The pull request title and description.
- Any files added, including workflow files (as a proposal, not as an execution).
What the adversary does not control:
- Whether a maintainer approves.
- What the base branch’s required status checks are, or their results.
- Whether branch protection permits the merge.
- The behaviour of CodeQL, secret scanning or dependency review.
Attack paths worth walking:
Path one: influence the review, get a weaker signal. Achievable. The result is that a maintainer reading only the review comments sees fewer findings than they should. Mitigated by requiring a human to read the diff, and by not treating review silence as evidence.
Path two: modify the instruction file so the review ignores the interesting directory. Achievable, and
visible in the diff — the modification is itself a change under review. Mitigated by CODEOWNERS on
.github/** and by treating instruction changes as policy changes.
Path three: get the review to approve the pull request. Not available. The review comments; it does not produce an approval that satisfies branch protection.
Path four: reach repository secrets. Not available through the review at all. Available through a
pull_request_target misconfiguration, which is an Actions problem that exists independently of whether
AI review is enabled.
The conclusion for this repository: enabling AI review on untrusted pull requests is acceptable,
because every path it opens terminates in “a comment was misleading” rather than “something merged” or
“a secret leaked”. The controls that make that true — human approval, base-branch status checks,
CODEOWNERS — are ones the repository needed regardless.
That is the analysis to run for your own repository. If any path terminates somewhere worse than a misleading comment, the problem is in the enforcement layer, not in the review.
Reviewing changes to review configuration
Section titled “Reviewing changes to review configuration”A small process rule with disproportionate value.
Any pull request that touches these deserves explicit attention before the code:
| Path | Why |
|---|---|
.github/copilot-instructions.md | Repository-wide review criteria |
.github/instructions/** | Path-scoped review criteria |
.github/agents/** | Custom agent definitions and their tool access |
.github/workflows/** | What runs, with what permissions |
CODEOWNERS | Who must approve |
| Ruleset or branch protection changes | The enforcement layer itself |
The rule to apply: a change to how the repository evaluates changes is a policy change. It should be reviewed by somebody who owns the policy, and it should not be buried in a pull request whose stated purpose is something else.
CODEOWNERS entries for .github/** implement most of this automatically, and it is a five-minute
change that closes a category of problem.
What AI review is and is not for, security-wise
Section titled “What AI review is and is not for, security-wise”Reasonable to expect: noticing an obviously missing authorisation check, flagging a hardcoded-looking credential, spotting an unvalidated input path — where the problem is visible in the diff and the review was told to look.
Not reasonable to expect: exhaustive vulnerability detection, dataflow analysis across files, knowing which inputs are attacker-controlled in your architecture, or catching a subtle logic flaw that requires understanding the threat model.
What actually does the security work: CodeQL for dataflow, secret scanning with push protection for credentials, dependency review for vulnerable packages, and human review by somebody who knows the system.
An AI review that reports no security findings has reported that it found none. GitHub’s own documentation states plainly that Copilot code review is not guaranteed to spot all problems. Treating its silence as a security assertion is the mistake this entire lesson exists to prevent.
Reviewing agent-authored pull requests
Section titled “Reviewing agent-authored pull requests”An increasingly common case with its own properties: the pull request was opened by a coding agent rather than a person.
The trust boundary has moved, not disappeared. The agent ran with an identity and a set of permissions somebody granted. What it produced is bounded by those permissions, which is a much stronger statement than anything true of a fork pull request — but it is only as strong as the permission configuration.
The agent read untrusted content too. An agent that worked from an issue description read text somebody else wrote. An agent that read a dependency’s source read a third party’s code. The injection surface is upstream of the pull request rather than in it, and the resulting diff looks entirely normal.
AI reviewing AI is a weak check. A change produced with a model’s conventions tends to satisfy a model’s mechanical criteria. The review will be clean more often, and that cleanliness carries less information than it does for human-authored code.
What to actually check on an agent pull request:
| Check | Why |
|---|---|
| Does the change match the task it was given? | Scope drift is the common agent failure |
| Were dependencies added? | An agent adding a package is a supply-chain event |
Did it touch .github/** or CI configuration? | Almost never legitimate for a feature task |
| Do the tests test the behaviour, or assert the implementation? | Agent-written tests often mirror the code |
| Is there a human who will own this after merge? | The accountability question |
The accountability rule. Somebody with write access owns every merged change. “The agent wrote it” is not a review, and a repository where agent pull requests merge on an agent’s own review has removed the judgement layer entirely. See reviewing agent pull requests for the full treatment.
Private and internal repositories
Section titled “Private and internal repositories”The threat model changes but does not disappear.
Head-branch instruction reading still applies. Anybody with write access can adjust review criteria in their own pull request. In an internal repository that is usually fine — they could also just approve each other’s code — but it is worth knowing when you are reasoning about what a clean review means.
The insider case is different from the attacker case. The realistic concern is not malice; it is somebody weakening a criterion because it was inconvenient, and nobody noticing because instruction changes get less scrutiny than code changes.
Dependencies are still external. A vendored library or a generated file can contain text that a review reads. The authority argument still does the defensive work.
Data handling is a separate question. What a review reads and where it is processed is governed by your plan’s data terms and your organisation’s policy settings, not by anything in this lesson. Check your own agreement rather than assuming.
An audit you can run today
Section titled “An audit you can run today”Ten minutes, and it tells you whether the review layer is sitting on top of enforcement that holds.
-
Does branch protection require at least one approving human review on the default branch? If not, nothing else in this lesson matters — the review layer is decorative and so is everything else.
-
Are required status checks defined, and do they include the checks that matter? A protection rule with no required checks blocks nothing.
-
Does
CODEOWNERScover.github/**? If not, add it. Workflow files, instruction files and agent definitions all live there. -
Is
pull_request_targetused anywhere? Search the workflow directory. Every occurrence needs justifying, and any occurrence that checks out the pull request head is a finding. -
Can anybody dismiss stale reviews or bypass protection? Check the bypass list on the ruleset. A long bypass list is a protection rule that describes an intention rather than a control.
-
Are secret scanning push protection and dependency review enabled? These carry security weight that the review layer does not.
-
Ask your team what a clean Copilot review means to them. If anybody answers “the code is fine”, that is the finding, and it is a conversation rather than a configuration change.
The first six are configuration and take minutes. The seventh is the one that determines whether the other six get respected, and it is the only one that has to be repeated.
Common mistakes
Section titled “Common mistakes”Treating a clean review as a security gate. It reports what it found. Enforcement is elsewhere.
Not reviewing instruction-file changes. The head-branch property makes them a review-standards change made by the author of the change being reviewed.
Relying on filtering to stop injection. Best-effort by design. Bounded authority is the control.
Skipping the diff because the review looked clean. On fork pull requests especially, that makes the review your only reader.
Using pull_request_target with fork checkout. Unrelated to AI, still the most damaging thing in this
area.
Expecting AI review to replace security scanning. Different tools, different guarantees. CodeQL does dataflow; a review reads a diff.
Assuming private repositories have no trust boundary. Write access is a wide boundary in most organisations.
Mental model
Section titled “Mental model”A review is a reader, not a gate.
Everything follows. A reader can be misled, and the cost of misleading it is a misleading comment. A gate that can be misled is a breach. Keeping the review firmly on the reader side of that line is what makes its untrusted-input exposure acceptable.
The corollary is that the security of this arrangement is a property of your branch protection and CI configuration, not of the review’s behaviour. If those are right, an influenced review is an annoyance. If they are wrong, you had a problem before you enabled AI review.
What you learned
Section titled “What you learned”- Review instructions are read from the pull request head branch, so a contributor can edit the criteria applied to their own change
- The consequence is confined to review output — not secrets, not merge, not required approvals
- A diff is untrusted input; the defence against injection is bounded authority, not filtering
- Enforcement lives in branch protection, rulesets and status checks, none of which the review affects
CODEOWNERSon.github/**closes most of the configuration-change gap- Deterministic scanners carry the security weight; the review is a reading aid
Exercise
Section titled “Exercise”Use a disposable repository. No production credentials, no real secrets.
-
Add
.github/copilot-instructions.mdwith a distinctive criterion. Confirm a review applies it. -
Open a pull request that modifies that file and also violates the original criterion. Predict: which version of the criteria does the review apply?
-
Add a branch protection rule requiring one approving review. With only a Copilot review present, predict: does the merge unblock?
-
Add a
CODEOWNERSentry requiring an owner’s approval for.github/**. Open a pull request touching an instruction file. Predict: who is requested? -
Add a code comment containing text addressed to a reviewer rather than to a human — do not craft an evasion, just observe. Note whether the review’s output changes, and note that no merge gate moved either way.
-
Confirm your required status checks are defined on the base branch and cannot be altered by a pull request.
-
Delete the repository.