The security outcome does not change. The same coding standard applies, the same merge gate applies, and a vulnerability is not less of a vulnerability because a model wrote it. What changes is the pressure on a review process that was calibrated for a different rate of production — and four specific checks that a pipeline built for human authorship was never asked to perform.
One definition of secure, not two. The single most expensive decision here is writing a separate, softer standard for assisted code. The moment two standards exist, the weaker one becomes the default for anything anyone is willing to label as assisted — and you have created the exception rather than managed the risk.
Governance guidance · 2017 TSC with revised 2022 points of focus · ISO/IEC 42001:2023 · Vendor terms and model behaviour change — verify current documentation · Last reviewed August 2026
AI-generated code needs the same security review as human-written code, held to the same standard and passing through the same gate — but four things about it are genuinely different, and a pipeline that ignores them will pass its own checks while admitting defects it was never designed to see. Those four are volume against fixed review capacity, defects that recur systematically rather than randomly, dependencies that may not exist at all, and licensed material arriving without a manifest entry to declare it. None of them is a reason to write a second, gentler standard. Each of them is a reason to add a specific check, and to be able to show that the check operated.
The framing that survives contact with an auditor and with a buyer’s security team is simple: the change-management control you already have is the control. In a SOC 2 examination — an attestation under AT-C 205 performed by a licensed CPA firm, never a certification — generated code is examined through CC8.1 change management and the logical-access criteria that decide who may merge. There is no AI criterion to satisfy and no AI module to bolt on. Under ISO/IEC 42001:2023, which is a certifiable AI management system standard, the coding assistant is an AI system you use, and it inherits the inventory, risk-assessment, operational-control and monitoring machinery of the management system. What follows is what to add, what to measure, what an assessor asks for, and where reasonable people disagree.
Key Takeaways
- The security standard does not change with authorship. Write one coding standard and one merge gate, and state explicitly that origin does not alter the bar — a separate, softer standard for assisted code creates the exception rather than managing the risk.
- The pull-request model works: the agent opens the change, a human merges it. It works only while the review gate is meaningful, and the thing that hollows it out is not carelessness but volume arriving against a review capacity that did not grow.
- Model defects cluster where human defects scatter. The same prompt shape reproduces the same weak construction across developers who never spoke to each other, so every confirmed finding in generated code should be treated as a class and remediated with a scanner rule plus a sweep, not a single fix.
- Dependencies are the sharpest new edge. Published research found 19.7% of packages recommended across sixteen tested models did not exist, and 43% of those invented names recurred in all ten re-runs of the same prompt — which is exactly what makes pre-registering them a viable attack.
- Add four things to the pipeline: dependency existence and identity verification before the lockfile changes, static analysis carrying rules for the classes you actually observe, secret scanning with push protection, and licence and provenance scanning that reads source rather than only manifests.
- Approval latency that stays flat while merged volume doubles is the clearest evidence that a review gate has become a formality — and it is a number you already have, split by author class, before any incident makes the point for you.
What does not change
Start with the part that has to hold, because most of the bad decisions in this area come from letting it move. A SQL injection is a SQL injection. A hardcoded credential is a hardcoded credential. A missing authorisation check on an object identifier is the same defect with the same blast radius whether a senior engineer wrote it on a Friday afternoon or a model produced it in half a second. Severity is a property of the defect and of the system it sits in. Authorship is not an input to that calculation, and the moment it becomes one your severity scale has stopped describing risk.
The same applies to the gate. A change reaches the protected branch through a pull request approved by somebody who is not its author, with the bypass path closed. That rule is indifferent to how the diff was produced. It is also the rule an examination actually tests: a point of focus under CC8.1 speaks to deploying system changes “with consideration of segregation of responsibilities (for example, restricting unilateral code development or testing and implementation by a single user) to prevent or detect unauthorized changes.” Nothing in that sentence requires interpretation for a new authorship model. The single user it restricts is a single user whether they typed the change or accepted it.
This is why the separate AI coding policy is usually a mistake. It feels responsible and it produces a document, but it creates two standards, and two standards resolve in one direction. Anything a team wants to move faster gets labelled assisted, and the softer path becomes the default path. Worse, from an assurance perspective, you have now written down a second set of commitments you can be tested against, having gained nothing you could not have achieved with three sentences in the standard you already had. Say in that standard that the bar does not vary with origin, then spend the effort on the checks that actually differ.
One more invariant: accountability. A named human is accountable for every change that reaches production, and that accountability is not shared with a tool, diluted by a model version, or transferred to a vendor. Every serious governance framework lands in the same place here — the useful consequence is that your change record needs to name a person, and increasingly needs to name two: the one who prompted and the one who approved. Where the agent holds credentials of its own, that is a delegated-authority question in its own right.
Seven dimensions, read across
The middle column is where the argument usually happens, and the right-hand column is what you can actually go and do this quarter. Note how little sits in the middle column for the first two rows: the standard and the gate barely move, which is precisely why the effort belongs further down.
| Dimension | What stays identical | What genuinely differs | What you add |
|---|---|---|---|
| The definition of secure | Identical. The same threat model, the same coding standard, the same severity thresholds, the same acceptance criteria. Authorship is not a property of a vulnerability. | Nothing. This is the line that must not move, because the moment there are two definitions the weaker one becomes the default for everything anyone is willing to label as assisted. | Nothing. Resist the separate AI coding standard — write one standard and note in it that origin does not change the bar. |
| The merge gate | Identical. A change reaches the protected branch through a pull request approved by someone who is not its author, with the bypass path closed for administrators. | The author may now be a service identity rather than a person, so the non-author rule needs a definition of author that covers both. | A rule that an agent identity can open and push to a branch but can never approve, and never holds a bypass permission. |
| Volume against review capacity | The gate is the same gate. | This is the substantive change. Generation capacity rises without review capacity rising, and the queue absorbs the difference until approval becomes acknowledgement. | A diff-size ceiling, a stated review-hours budget, and a metric on approval latency per hundred lines changed so the failure is visible before an incident makes it visible. |
| How defects are distributed | The defect classes are the ordinary ones — injection, weak cryptography, missing authorisation, unsafe deserialisation, path traversal. | Human error is spread across a team and across time. Model error clusters: the same prompt shape produces the same weak construction repeatedly, including across different developers who never spoke to each other. | Treat every confirmed finding in generated code as a class, not an instance. The remediation is a rule in the scanner or the linter, plus a sweep of the existing codebase for siblings. |
| Third-party dependencies | Same registries, same known-vulnerability scanning, same upgrade discipline. | A suggested package may not exist at all, or may exist because somebody registered the name after watching models invent it. The failure is at resolution time, before any scanner has an advisory to match against. | Verification that every newly added dependency exists, is the package intended, and was requested by a named person — before it enters the lockfile. |
| Provenance and licensing | Your obligations under the licences you already depend on are unchanged, and so is the need for an inventory of them. | A new route by which licensed material can enter the codebase without an import statement, a package manifest or a commit that names its source. | A configured setting on the assistant for handling code that matches public repositories, evidence that the setting is on, and a licence scan that reads source files rather than only manifests. |
| Accountability for the change | A named human is accountable for every change that reaches production. This does not become shared with a tool. | The record now has three roles where it used to have two: who prompted, who approved, and which identity pushed the commits. | Attribution in the change record — the assistant and version used, the human who prompted, and the human who approved — so the population can be split when someone asks. |
The agent opens the pull request. A human merges it.
The pull-request model is the right architecture for coding agents, and it is worth saying why rather than treating it as obvious. It keeps the agent inside a boundary that already exists, so you inherit a decade of tooling and a control an auditor already knows how to test. It produces a durable artefact for every change. It puts a human decision between generation and production without putting a human between generation and iteration, which is where the productivity actually lives. And it fails safe: an agent with push rights to a feature branch and no approval rights cannot reach production by any path that does not involve a person, provided the bypass is genuinely closed. Whether that agent should also hold deployment credentials is a separate decision, covered in coding agents and production access.
The model works only on one condition: that the merge is a decision rather than an acknowledgement. This is where honesty is more useful than encouragement. Code review was already the weakest link in most pipelines before any of this — under-resourced, unrewarded, and performed at the end of the day by someone with their own deadline. Assisted development does not create that weakness. It loads it. Generation capacity can rise several-fold in a quarter, while review capacity is the same people with the same hours and the same attention span. The queue absorbs the difference, and the way a queue absorbs pressure is by lowering the standard of what passes.
Industry research points the same way. DORA’s 2025 State of AI-assisted Software Development report, published early in 2026 from a survey of several thousand technology professionals, found AI adoption associated with higher throughput while continuing to show a negative relationship with software delivery stability — and framed the effect as AI being “an amplifier, magnifying an organization’s existing strengths and weaknesses.” Read that as a statement about your review process specifically. If it was strong, more volume tests it. If it was ceremonial, more volume exposes it.
Review fatigue is a capacity problem, so treat it with capacity levers rather than exhortation. A ceiling on changed lines, above which a pull request must be split or must take two reviewers, is the single most effective one, because attention degrades sharply with diff size and everyone knows it. Requiring the author to state the intent and the alternatives considered in their own words gives the reviewer somewhere to start and quietly detects the change nobody understood. Moving whole defect classes out of the human’s job — into scanners, type systems, linters and policy-as-code — is the only lever that actually creates review capacity rather than rationing it. And a stated review budget in hours per reviewer per week converts an invisible overload into a planning conversation, which is the only form in which it ever gets solved.
One structural point for organisations running several agents: an agent that opens pull requests is a producer of review demand, and adding another agent adds demand to a fixed supply. Capacity planning for reviewers belongs in the decision to deploy the agent, not in the retrospective after the first escaped defect. The wider version of that argument is in the ten questions that govern any AI agent.
Systematic, not random
This is the most consequential difference on the page, and the one most explainers miss because it is a statement about distribution rather than about rate. Human error is idiosyncratic. Two engineers on the same team make different mistakes, at different times, for different reasons, and the mistakes are spread thinly across a codebase. Model error is not distributed that way. A given prompt shape draws on the same learned patterns and produces the same construction — including the same weak construction — repeatedly, and across different developers who never coordinated. The defect arrives in a cluster that nobody in the organisation planned.
The cleanest published demonstration of that persistence comes from package hallucination research rather than from vulnerability research, because package names are easy to check against a registry. In the USENIX Security 2025 study by Spracklen and colleagues, five hundred prompts that had produced a hallucinated package name were each re-run ten times. Forty-three per cent of the invented names came back in all ten runs, and fifty-eight per cent recurred more than once. Thirty-nine per cent never recurred at all — the phenomenon is bimodal, not uniform. But a defect that reappears every single time you ask is not an error in the usual sense. It is a property of the generator.
On vulnerability rates specifically, be careful with the headline numbers, because they age fast. The frequently cited finding that around forty per cent of generated programs contained a vulnerability comes from the 2021 study Asleep at the Keyboard? by Pearce and colleagues, which produced 1,689 programs across 89 scenarios drawn from common weakness categories and was published at IEEE Security and Privacy in 2022. Models have changed several generations since. Treat the rate as historical, and treat the structural finding — that certain scenario shapes reliably elicit certain weaknesses — as the durable part, because it is the part every subsequent study has reproduced in some form.
If a review finds one instance of a weak construction in generated code, you have not found an instance. You have found a class, and the rest of the class is already in the repository.
That rule changes what remediation means. Fixing the four instances you found is not closing the finding. It is closing four tickets while the generator upstream continues to produce the fifth. The remediation that actually holds has three parts: a detection rule added to the scanner or the linter so the construction cannot merge again, a sweep of the existing tree for siblings, and — where the tooling supports it — a repository-level instruction or rule file that steers the assistant away from the pattern in the first place. Make the rule a required condition for closing the ticket and the discipline survives the person who introduced it.
There is an assurance consequence too, and it is worth understanding before an examination rather than during one. Sampling logic assumes that deviations are distributed in a way that makes a sample informative about a population. When defects cluster by prompt shape, a sample can miss a cluster entirely or land in one and overstate it. Neither the criteria nor the attestation standards prescribe sample sizes — AT-C 205 requires sufficient appropriate evidence and leaves the quantity to professional judgement — but the practical implication is that scanning coverage across the whole population is doing more work here than sampling ever will. Full-population automated checks are not a nice-to-have in an assisted codebase. They are the part of the control set that actually addresses the risk.
Packages that do not exist yet
Every organisation already scans dependencies for known vulnerabilities. That control answers a question about packages that exist and have advisories. Assisted development introduces a failure one step earlier, at resolution: the assistant suggests an import for a package that does not exist, and the name is plausible enough that nobody questions it. In the ordinary case the build fails and a developer loses ten minutes. In the adversarial case somebody registered that name first, and the build succeeds.
The scale is documented. The USENIX Security 2025 study analysed 576,000 generated code samples across sixteen models in two languages and found that 19.7% of recommended packages did not exist, with rates of at least 5.2% for the commercial models tested and 21.7% for the open-source ones, yielding 205,474 unique invented names. Combine that with the persistence figures above and the attack writes itself: watch what models invent, register the names that recur, wait. The practice has acquired a name — slopsquatting — precisely because it is cheap and predictable in a way that traditional typosquatting is not.
Rates on newer models are lower, and it is worth being accurate about that rather than alarmist. An independent 2026 replication testing five frontier models released between October 2025 and March 2026 reported hallucination rates between roughly 4.6% and 6.1% — a substantial improvement on the open-source cohort of the earlier study. The same work identified 127 package names that all five models invented identically, of which around fifty remained registrable after existing registry defences. The rate fell, but the predictability did not. A shared invented name across every major model is a more attractive target than a rare one, not a less attractive one.
The control that addresses this is not another scanner. It is a decision point at the moment a dependency is added. Resolve builds through an internal registry proxy or allowlist so an unknown name fails rather than reaching a public registry. Fail the build when the lockfile gains an entry that no reviewer has named. Surface package age, maintainer count, repository presence and download history in the pull request, because those four facts distinguish a real library from a name registered last Tuesday. And keep a bill of materials generated from the resolved dependency graph rather than from the manifest, so what you inventory is what you actually shipped. This sits squarely in the supply-chain entry of the OWASP Top 10 for LLM Applications — LLM04:2026, in the edition published in August 2026, which renumbered most of the 2025 list, so cite the entry by name and confirm the identifier against the current release before quoting it in a policy.
For teams that want a framework reference rather than a vendor one, NIST’s Secure Software Development Framework, SP 800-218, is the applicable baseline for building software with these tools. SP 800-218A extends it as a community profile for organisations developing generative AI models and systems themselves, which is a different population. Getting that distinction right in a policy saves an argument with an assessor who knows both documents.
Licensed material with no manifest entry
Software licence compliance has always relied on a declaration. You import a library, the manifest records it, a scanner reads the manifest, and the obligations attached to that licence become visible. Generated code can bypass that chain entirely. Where output resembles material in the training corpus closely enough to matter, it arrives as source in your repository with no import statement, no manifest line and no commit message naming a source. Nothing in the conventional tooling is looking at it.
How much legal exposure that creates is genuinely unsettled, and a page like this should say so rather than pretend otherwise. The long-running US class action over a code assistant and open-source licence terms has narrowed considerably — claims under the copyright-management-information provisions of the DMCA were dismissed at the district court on the basis that outputs were modifications rather than identical copies, while open-source licence and breach-of-contract claims survived — and the identical-copy question was argued before the Ninth Circuit in February 2026. Do not build a control set on a prediction of that outcome, and do not let a vendor questionnaire push you into giving a legal opinion.
The governance answer is available now and does not depend on the litigation. Confirm what your assistants are configured to do about suggestions that match public repositories — several major tools offer a filter of this kind, availability and behaviour vary by product and plan, and the setting is the evidence, so capture it rather than describing it. Scan source files for licence indicators, not only manifests. Define what happens when a match is found, before one is. Know what your customer contracts say about intellectual property indemnity, because that is the question a procurement lawyer will actually ask. And be more careful in code you publish — open-source contributions and customer-facing SDKs carry the exposure outward, where you cannot quietly remediate it. The full treatment is in AI code provenance and licensing.
One adjacent risk belongs here because it travels the same route. Assistants complete configuration and test fixtures with credentials, and a session with an environment file open in context can produce a real one in a suggestion. Detection after the fact is a rotation exercise, while prevention at push time is a control. See coding agents, environment files and secrets for the handling rules.
What to add to the pipeline
Eight additions, in rough order of how much risk each removes per hour of work. Every one of them is a required check on the protected branch or a fact recorded before a merge — none of them is a document. The right-hand column is where each lands when someone asks which criterion it addresses.
| Addition | What it is actually for | The setting and the artefact | Criteria |
|---|---|---|---|
| Dependency existence and identity verification | Catches the failure that no vulnerability scanner is built to catch: a package that does not exist yet, or one that exists only because an attacker registered a name that models reliably invent. | An internal registry proxy or allowlist so the build resolves only from a curated mirror. A CI step that fails when the lockfile gains an entry absent from the previous lockfile without an approving reviewer. Package age, maintainer history and download-count heuristics surfaced in the pull request. | CC8.1 · CC9.2 · CC7.1 |
| Static analysis carrying rules for the classes you actually see | Generated code reads as idiomatic, so it passes review on appearance. A ruleset tuned on the defects your organisation has historically written will not fire on the constructions a model favours. | The ruleset under version control, a documented process for adding a rule whenever a finding is confirmed in generated code, the scan configured as a required check on the protected branch, and severity thresholds that block a merge rather than filing a ticket. | CC7.1 · CC8.1 · CC4.1 |
| Secret scanning with push protection | Assistants complete configuration blocks and test fixtures with plausible-looking credentials, and sometimes with real ones drawn from an open file in the same session. Detection after the fact is a rotation exercise, while prevention at push time is a control. | The push-protection setting captured at more than one date inside the period, the alert list with dispositions, and the rotation record for anything that reached a branch. Confirm availability on your plan tier rather than assuming it. | CC6.1 · CC6.3 · CC7.2 |
| Licence and provenance scanning of source, not only manifests | A manifest scan finds what you declared. It cannot find a function that resembles a copyleft-licensed implementation and arrived without a manifest entry. | The assistant setting governing suggestions that match public code, evidence it is enabled organisation-wide, scan output over the source tree, and a documented disposition path for a match. | CC9.2 · risk register — see note below |
| Infrastructure-as-code and configuration scanning | Assistants are fluent in Terraform and Kubernetes manifests and generate permissive defaults confidently — a wide security group, a public bucket, a role with a wildcard action. | Policy-as-code checks on the same protected branch, the policy set under version control, and the exception register for anything merged with a waiver, including who granted it and when it expires. | CC6.1 · CC6.6 · CC8.1 |
| A test-quality gate on changed lines | The same assistant that wrote the code will happily write tests that assert the behaviour it produced, including the wrong behaviour. Coverage rises while assurance does not. | Coverage delta measured on changed lines rather than repository-wide, a stated threshold, and a rule that security-relevant changes carry a test written against the requirement rather than against the implementation. | CC8.1 · CC4.1 |
| Attribution on the change record | Without it you cannot split any population by author class, which means you cannot answer a buyer question, tune a scanner, or measure whether your review gate behaves differently on agent-authored work. | A label or trailer applied by the assistant integration, a distinct service identity for agent-pushed commits, and a documented honest limitation: attribution covers what the tooling can see, not a developer pasting a suggestion by hand. | CC2.1 · CC8.1 |
| An inventory of assistants, models and versions in use | A model or extension update changes the generator that sits upstream of every one of the controls above. Treating that as a change is the difference between a governed pipeline and a drifting one. | The tool and model inventory with owners and approval dates, the record of version and configuration changes, and the reassessment triggered when a materially different model is adopted. | CC3.4 · CC8.1 · CC9.2 |
Two honest cautions about static analysis, because it is the addition most often bought and least often tuned. First, a required check that produces more false positives than engineers can triage does not become a control. It becomes a habit of clicking through, and the habit generalises to the true positives. Budget the tuning time as part of the rollout, not as a follow-up nobody schedules. Second, the reason a default ruleset under-performs on generated code is not that the code is exotic — it is that the code is conventional. It looks like the well-formed examples the ruleset was calibrated against, which is exactly why the specific weak construction slips past both the tool and the reviewer. The rules that earn their place are the ones you wrote after finding a real instance in your own repository.
The note promised in the licence row is worth stating plainly, because it is the kind of precision that saves an argument. Licence and provenance exposure is an intellectual property risk, and the trust services criteria do not address intellectual property. There is no criterion it maps to, so it does not belong in Section 4 of a SOC 2 report and an honest advisor will not pretend otherwise. Where it does belong is the risk register, the vendor assessment of the assistant under CC9.2, the customer contract, and — if you run an AI management system — the risk assessment under ISO/IEC 42001 clause 6.1.2. Mapping a control to a criterion it does not serve is a small dishonesty that a competent assessor finds immediately, and it costs more credibility than the row was worth.
Under ISO/IEC 42001:2023 these additions are not a separate programme. The coding assistant belongs in the AI system inventory. The decision to use it is an operational control with a named owner. The risk assessment under clause 6.1.2 covers what could go wrong for the organisation. Monitoring under clause 9.1 covers whether the controls are working. And internal audit and management review put the results in front of someone with authority to change the arrangement. The Annex A reference set includes a theme covering the use of AI systems, which is where a policy on assisted development actually belongs — inside the management system, not beside it. The starting inventory work is set out in the AI system inventory and registry.
Forty engineers, one recurring defect
An illustrative composite rather than a client. Read the volume figures alongside the latency that did not move — that pairing is the whole story, and it was visible three months before anybody looked at it.
| Baseline | January 2026 | A forty-engineer B2B SaaS company, illustrative and composite rather than a client. Around one hundred and eighty merges a month to the protected branch. Branch protection requires one non-author approval, but administrators can bypass. Dependency scanning runs for known vulnerabilities only. No secret push protection, no attribution, no assistant inventory. |
| The pressure | February – March | Assistants and a coding agent go into general use. Merged volume rises to roughly four hundred and seventy a month. Median approval latency does not move, which is read internally as a productivity win. New third-party dependencies rise from about four a month to nineteen, six of which nobody can attribute to a decision. |
| The finding | 9 April | A readiness review samples twenty merges and finds the same unsafe deserialisation construction in four of them, authored by three different engineers who had never discussed it. Not a coincidence and not a competence problem — one prompt shape, one recurring output. |
| Move 1 — close the bypass | 13 – 24 April | Administrator bypass is switched off. The agent identity is separated from human accounts, granted push but never approval, and excluded from every bypass list. A diff-size ceiling routes anything above six hundred changed lines into a mandatory split or a two-reviewer path. |
| Move 2 — make the class a rule | 20 April – 8 May | The deserialisation pattern becomes a blocking scanner rule rather than four fixes. A sweep of the existing tree finds eleven more instances. Every confirmed generated-code finding from this point forward is required to produce a rule before the ticket can close. |
| Move 3 — the dependency gate | 28 April – 22 May | Builds resolve through an internal registry proxy. CI fails when the lockfile gains an entry with no approving reviewer named. Two of the nineteen additions turn out to be packages under a week old with a single maintainer and no repository. One of them is removed and the code rewritten. |
| Move 4 — measure the gate | From 1 June | Secret scanning with push protection is enabled. Approval latency per hundred lines, zero-comment approval share and revert rate by author class go onto a monthly review that a security lead who does not merge code presents to the engineering director, minuted. |
Nothing in February was misconfigured, and that is the point. Branch protection was on. A non-author approved every merge. The vulnerability scanner ran and was green. Every control in the description operated exactly as written, and the gate had still stopped functioning as a gate, because two hundred and ninety additional merges a month arrived against the same reviewers and the same hours. The signal was sitting in plain view: merged volume up by a factor of two and a half, approval latency unchanged. That combination has only one arithmetic explanation.
The April finding is the systematic-recurrence thesis arriving in a real repository. Four instances of one unsafe construction, three different authors, no shared conversation. The fix that was proposed first — four pull requests correcting four call sites — would have closed the finding and left the eleven siblings the later sweep found, plus every future instance the same prompt would produce. The remediation that held was the scanner rule, and the rule that made it durable was procedural: a confirmed finding in generated code cannot be closed until a detection rule exists.
The dependency work produced the sharpest single result. Nineteen additions in a month against a historical four, six with no attributable decision, two resolving to packages under a week old with one maintainer and no source repository. Neither turned out to be malicious. Both were admitted by a process that had no step at which anybody was asked whether the package should exist in the build, which is the only question that would have caught them.
What the four moves have in common is worth noting. None of them added headcount. None of them required a new policy document. Three were configuration changes that removed a decision from a tired human entirely, and the fourth put a monthly number in front of somebody who does not merge code and can therefore ask an awkward question about it. That last one is the closest thing this page has to a governance recommendation: the review of the review has to sit with someone outside the queue.
Metrics that reveal whether review is real
None of these is a control by itself, and none should be published as a target — the moment a reviewer knows their zero-comment rate is watched, the rate improves and the reviews do not. They are the information a governance forum uses to ask whether the gate is still a gate, and almost all of them are already in systems you own.
| Metric | What it actually tells you | The reading that should worry you |
|---|---|---|
| Approval latency per hundred lines changed | Whether reviewers are reading. A gate that holds under a doubling of volume shows a roughly stable ratio. A gate that has quietly become a formality shows latency flat while diff size climbs. | Median time-to-approve unchanged while merged volume rises materially. That is not efficiency. It is the same attention spread thinner. |
| Share of approvals carrying no comment at all | The texture of the review. Some clean changes deserve silent approval, so the number is never zero — the signal is in the trend and in how it differs from the same team a year ago. | A sustained rise, particularly concentrated in one or two reviewers, or a step change that coincides with an assistant rollout. |
| Approver-is-prompter rate | Whether the second pair of eyes is genuinely second. The person who wrote the prompt has already accepted the output once and reads it as their own work, because it is. | Any material rate on security-relevant paths. This is the failure closest to self-review, and it is invisible unless you record who prompted. |
| Revert and hotfix rate within seven days, split by author class | Whether the review gate is catching what it is supposed to catch. Splitting by author class is the whole value. The aggregate number hides the comparison you need. | A widening gap between agent-authored and human-authored changes. It quantifies review effectiveness rather than review effort. |
| New dependencies per month, and the share with a named requester | Whether the dependency control is operating or being routed around. Dependency growth is the clearest volume signal in an assisted codebase. | Additions appearing in the lockfile that no reviewer can attribute to a decision. Every one of those is an unverified package by definition. |
| Recurrence of a finding class after it was remediated once | Whether you fixed an instance or fixed the cause. This is the metric that tests the systematic-recurrence thesis inside your own codebase. | The same weak construction reappearing weeks after a fix. It means the remediation never became a rule, and the generator upstream has not changed. |
| Secret-scanning alerts that reached the default branch | Whether prevention is working or detection is compensating. Push protection turns this into a near-zero number, while its absence turns it into a rotation workload. | Any non-trivial count, and particularly a repeat in the same repository, which usually means the block was bypassed rather than the practice changed. |
Two of these deserve emphasis because they are cheap and unusually diagnostic. The first is approval latency per hundred lines changed, which needs no new instrumentation and answers the only question that matters about a review gate under load. The second is revert rate split by author class, which is the closest thing available to a direct measure of whether review is catching what it should — and it is useless unless you record author class, which is why attribution appears in the pipeline table above even though it removes no risk on its own. Present both monthly to someone who does not merge code, minute the discussion, and you have a monitoring control with an artefact rather than a dashboard nobody opens.
What the CPA firm actually requests
There is no AI request list. In a SOC 2 examination the service auditor tests the change and access controls you already have, and generated code enters as an attribute of the population rather than as a control family of its own. The first request is still a population, because a sample drawn from an incomplete list proves nothing about the list it came from.
| The request | What satisfies it | What gets rejected |
|---|---|---|
| Define the population of production changes | A system-generated export of every merge to the protected branch across the whole period, with the query, filter, date range and record count visible, reconciled to the deployment record. Where you claim attribution, the same export carries the author-class field so the population can be split. | A list assembled by hand. An export filtered to the changes you consider interesting. A screenshot cropped above the filter bar. A count that differs between the first extract and the second with no explanation. |
| Show the review gate could not be bypassed | Branch-protection configuration captured at two or more dates inside the period, including the setting that prevents administrators bypassing it, plus the organisation audit log of protected-branch changes showing the rule was not relaxed between those captures. | A single screenshot taken during fieldwork. A posture dashboard showing today. Any evidence that establishes the present state of a period that closed months ago. |
| Show the approver was not the author | For each selected merge, the pull-request record showing author and approving reviewer as distinct accounts, with timestamps. Where an agent identity opened the change, evidence that the identity holds no approval or bypass permission. | An approval from the account that pushed the commits. A merge with the required check marked as satisfied by an administrative override. A review recorded after the merge timestamp. |
| Show the dependency control operated | (1) The population of dependency additions for the period, each traced to the pull request that introduced it and the reviewer who accepted it, (2) the registry-proxy or allowlist configuration, and (3) evidence the build fails when resolution falls outside it. | A current software bill of materials offered as evidence about the period. A vulnerability report with no link to the decision that admitted the package. An allowlist that exists as a document and not as a build failure. |
| Show scanning operated and findings were dispositioned | The scanner configuration as a required check, the finding population for the period with severities and closure dates, the remediation records for anything above threshold, and the register of accepted exceptions with an owner and an expiry. | A screenshot of a clean dashboard. Findings closed with no disposition text. An exception with no expiry, which is an unremediated finding with better manners. |
| Show the tooling inventory and its changes | The inventory of assistants and models with owners and approval dates, the change record for versions and configuration, and the assessment performed when a materially different model or capability was introduced. | A statement that the company uses AI coding tools. An inventory dated the week of fieldwork with no history behind it. A vendor marketing page offered in place of the configuration you actually run. |
Sample sizes follow the ordinary logic. Merges to a protected branch are usually a large population, so expect a sample in the region of twenty-five selections rather than a full inspection, with the firm expanding rather than concluding if a deviation appears. Configuration-enforced controls are different in kind: there is one setting, so the evidence is captured at two or more in-period dates plus the audit log proving it was not relaxed in between. Populations that are small by nature — emergency merges, exception approvals, model or tooling changes — are usually tested in full, which means a single missing record is the whole finding. More on how this works generally in sampling and sample sizes and what auditors accept as evidence.
Two pieces of vocabulary make fieldwork easier. Anything you export is information produced by the entity, and the auditor has to establish its completeness and accuracy — which is why they want the query, the filter, the date range and the record count visible rather than the result alone. And the request list arrives as a PBC schedule, prepared by client, typically a week or two before fieldwork opens. Read it and query the ambiguous items rather than answering them the way you assume they were meant.
The most important warning in this section is about your own words. The description of the system in a SOC 2 report is written by management and evaluated against the AICPA description criteria in DC section 200. If that description says AI-generated changes receive human review, or that dependencies are verified before use, those sentences become testable assertions and you will be tested against them. Write what you can evidence every month for a year — and if attribution is partial, say it is partial. The related drafting rules are in writing the system description. Where the standard is ISO/IEC 42001 instead, the certificate is issued by an accredited certification body and the equivalent trap is a Statement of Applicability that claims a control the pipeline does not enforce.
Tranquility Cybersecurity works on the readiness side of this line — designing the controls, tuning the pipeline, defining and reconciling the populations, and coordinating the examination. The testing and the opinion belong to the licensed CPA firm, and an ISO 42001 certificate belongs to the accredited certification body. A firm that designed or operated your controls cannot then examine them, which is the separation that makes the report worth something to the buyer reading it.
The edge cases that generate the questions
The sections above cover the common eighty per cent. These are the situations where reasonable engineers and reasonable assessors disagree, and where settling the position before fieldwork is worth several days of argument during it.
The approver is the person who wrote the prompt
This is the most common way an assisted pipeline loses its gate while every configuration setting still reads correctly. The branch rule tests account identity, and the prompter and the author are different accounts, so nothing fires. But the prompter has already accepted the output once, and reads it back as their own reasoning rather than as somebody else’s work. Some organisations write the prompter out of the approver pool for security-relevant paths and accept the throughput cost, while others accept the arrangement generally but exclude it on authentication, authorisation, cryptography and payment paths. What does not work is claiming independent review in a system description and leaving the prompter as the routine approver.
An AI tool performs the review
Automated review tools are genuinely useful and read every line, which no tired human does at four hundred lines. The governance question is what role you claim they play. As an additional required check they are a strong control and easy to evidence, because the configuration and the finding population are both exportable. As the approving party they are not the second person your change-management control describes, and an auditor testing a control that says a qualified individual other than the author reviews and approves will look for a human decision. The workable position is that AI review reduces the reading load so the human approval is meaningful, not that it replaces the approval.
Auto-merged dependency bumps and trivial diffs
Almost every team exempts something — formatting changes, generated lockfile updates, patch-version bumps merged by a bot. Exemptions are defensible when they are defined narrowly, enumerated in the control description, and enforced by a rule rather than by judgement. They stop being defensible when the exemption is broad enough that a substantive change can be routed through it. Ask one question of every exemption: could a change that alters behaviour, permissions or dependencies qualify? If the answer is yes, the exemption is a bypass. An auto-merge path that admits new transitive dependencies is exactly that.
The emergency path at three in the morning
Break-glass merges are legitimate and every serious pipeline has one. The design that survives testing is not an unmonitored administrator bypass but a fast path that is bounded, logged and reviewed afterwards: a stated reason at the time, an automatic notification to a channel people actually read, and a retrospective review within a defined window that produces a record. The population of emergency merges is then small, testable and matched to incident tickets. Where that population is large or unmatched, expect the auditor to ask what the normal path is actually for.
Generated tests that were written against the code
When the same session produces both the implementation and its tests, the tests encode the behaviour that was produced rather than the behaviour that was required. Coverage climbs, the suite is green, and a whole class of requirement defects becomes invisible. The correction is not to ban generated tests — it is to require that security-relevant behaviour has at least one test written from the requirement, by a person who states the expected outcome before seeing the implementation. Mutation testing, or a coverage measure restricted to changed lines, gives you something to evidence beyond a percentage that has stopped meaning anything.
Comprehension debt: code nobody on the team can explain
A reviewer can approve a change they do not fully understand and be right most of the time. The cost lands later, during an incident, when the person on call has to reason about a subsystem nobody wrote. This is not a compliance finding and no criterion names it, but it degrades incident response, and incident response is examined. Two practical answers: require the pull-request description to state the intent and the alternatives considered in the author’s own words rather than a generated summary, and treat a subsystem with no human owner who can explain it as a risk-register entry rather than as a fact of life.
The code you merged before any of this existed
Most teams adopt assistants first and govern them second, so there is a stretch of history that passed through a gate nobody was watching. Retroactive review of everything is not realistic and is rarely the right allocation. What is realistic is a bounded sweep: run the current scanner ruleset over the whole tree so any recurring class is found wherever it lives, verify the full dependency manifest against the registry rather than only new additions, and rotate any credential that scanning surfaces. Then be accurate about dates in your system description — a control that began in April is described as beginning in April, and the period is chosen accordingly.
Where an agent reaches beyond the repository — into ticketing systems, cloud consoles or external tools through a server it did not author — the questions change again. Start with MCP server security governance and prompt injection and tool calls, which covers the case where the content the agent reads is itself hostile.
What buyers push back on and the answer
These six now appear in most enterprise security reviews of a software vendor. The difference between a good answer and a defensive one is that a good answer names a limitation before the buyer finds it.
“Do you allow AI-generated code in your product?”
The honest answer is almost always yes, and a flat no is a claim most engineering organisations cannot evidence — which makes it the worse answer even when it feels safer. The useful reply reframes to the question the buyer is actually asking, which is whether your controls still hold. Describe the gate: no change reaches production without approval from someone who is not its author, agent identities cannot approve or bypass, dependencies are verified before they enter the lockfile, scanning and secret detection are required checks, and the whole population is testable in your examination. A security team that receives that stops asking the yes-or-no question.
“You cannot actually tell which code was AI-generated.”
Correct, and saying so plainly is worth more than a claim that will not survive a follow-up. Integration-level attribution captures what the tooling can see — an agent-opened pull request, a service identity, a commit trailer — and misses a developer accepting an inline completion or pasting from a chat window. That is a genuine limit. What it does not undermine is the control set, because the gate applies to every change regardless of origin. Attribution is a tuning and measurement aid, not the boundary of the control. Describe it as partial in your documentation and you will never be caught out by the question.
“Your reviewers cannot possibly be reading that volume.”
Often a fair challenge, and the answer is arithmetic rather than assurance. Publish the ratio: merged changes per reviewer per week, median diff size, median approval latency per hundred lines, and the ceiling above which a change must be split. If the numbers are defensible they answer the question directly. If they are not, the honest position is that review capacity is a constraint you manage — with diff-size limits, automated checks that remove classes of defect from the human’s job, and rotation to spread the load — rather than a claim that everything is read closely. Buyers respond well to a named constraint with named mitigations.
“What if a model reproduced licensed code into your product?”
Separate the settled part from the unsettled part. Unsettled: the legal position on assistant output and open-source licence terms is still being litigated, and it is not for a vendor questionnaire to resolve. Settled: the governance answer is knowable today. Confirm and evidence the setting on your assistants that governs suggestions matching public code, scan source files rather than only manifests, keep a disposition path for a match, and be able to say what your customer contract does and does not indemnify. Answer with the controls and the contractual position rather than with a legal opinion you are not in a position to give.
“Does your SOC 2 report cover AI-generated code?”
No trust services criterion mentions AI, and there is no AI module to add. What is examined is the change-management control at CC8.1 and its points of focus, the logical-access controls that govern which identities can merge or bypass, and the monitoring criteria covering detection of configuration changes. Generated code enters those tests as an attribute of the population, not as a separate control family. The one thing that changes materially is what you write in the system description: a description that promises human review of AI-generated changes creates a testable assertion, and you will be tested against your own words.
“We require that no AI tool retains or trains on our source code.”
A legitimate requirement, and one to answer from current contract documents rather than from memory. Retention windows, training use and administrative controls differ structurally between consumer and enterprise offerings, and they change. Treat it as a supplier-diligence item with a review date: record for each assistant the plan tier in use, what the current terms say about retention and training, whether the setting is enforced centrally or per developer, and when you last verified it. A dated record of what was confirmed and when is a better answer than a confident sentence about a product whose terms may have moved since you read them.
A general note on answering these. The questionnaire wording is usually a year behind the practice, so questions arrive shaped as yes-or-no when the honest answer is a control description. Answering the better question is not evasion if you say plainly that you are doing it. More on handling the format in SOC 2 and security questionnaires.
Frequently Asked Questions
Does AI-generated code need a different security review from human-written code?
Is the pull-request model enough for coding agents?
How do we stop code review becoming a rubber stamp at high volume?
What is slopsquatting, and how serious is it?
How do we verify dependencies that an assistant suggested?
Does SOC 2 have controls for AI-generated code?
Can an AI code-review tool satisfy the review requirement?
Should we ban AI coding assistants until our controls are ready?
How do we handle the licensing risk from AI-generated code?
What does it cost to get this in place before an audit?
Related Reading
Governing Coding Agents
Claude Code, Cursor and Copilot assessed by capability graph rather than product label.
Read moreShould a Coding Agent Deploy to Production?
Separating code-generation rights from deployment authority, even when one human holds both.
Read moreCoding Agents, .env Files and Secrets
Why the agent usually needs the capability, not the secret — and the escape paths that matter.
Read moreThe Ten Questions That Govern Any AI Agent
Scope, ownership, data, capability, identity, oversight, failure detection, evidence, reassessment and how to stop it.
Read moreISO 42001 Knowledge Hub
AIMS controls, EU AI Act mapping, risk assessment and guides.
Read moreISO 42001 (AI Management)
The world's first AI management system standard, for AI builders.
Read more