On May 21st, Microsoft published a post titled Improving C# Memory Safety, describing a redesign of the unsafe keyword for C# 16. Preview in .NET 11, production in .NET 12. The technical content is interesting on its own merits. The framing is what should make every engineering leader pay attention.
Buried in a section called AI enablement, near the bottom of a long technical post, product manager Richard Lander writes that the compiler is now the determining authority for whether unsafe code has been written. Not the reviewer. Not the agent. Not the developer who hit the merge button. The compiler. That sentence is doing a lot of work, and it is worth unpacking what Microsoft is actually conceding.
What is actually changing
The new model partitions a call graph into three roles: safe methods, unsafe methods that propagate caller obligations upward, and boundary methods that discharge those obligations with explicit guards. Every unsafe operation has to sit inside an inner unsafe block. Every unsafe member should carry a /// <safety> doc block describing exactly what the caller has to prove. Violations are compile errors, not warnings. The unsafe type modifier from C# 1.0 is being deleted. Pointer types in signatures no longer auto-propagate unsafety on their own. A new safe keyword is required on extern declarations alongside unsafe.
That is the new mechanics. The interesting part is what they are meant to do.
When you set AllowUnsafeBlocks to false in a project under the new model, the compiler refuses to compile any unsafe code at all. None. Not Marshal.ReadByte. Not NativeMemory.Alloc. Nothing. That single project property becomes a guarantee that no unsafe code can ship through that project, full stop. In Lander’s own words, memory-safety auditing collapses from inspecting every diff to checking one project property.
That sentence is the entire pitch. And it has nothing to do with making developers more productive.
The double whammy
Here is what the language committee is saying out loud, and here is what they are saying with their actions.
What they are saying out loud is that AI agents will increasingly produce code, the compiler needs to constrain what those agents can produce, tighter rules narrow the search space, hard errors are better than warnings, and unsafe code needs to be grep-friendly and impossible to slip through by accident.
What they are saying with their actions is that the developer reviewing the agent’s output is also untrusted.
You do not put one project property between yourself and a memory safety incident because you trust your reviewers. You do it because you do not. The whole architecture of the new model assumes that nobody at any point in the pipeline can be relied on to catch the unsafe code visually. Not the agent that wrote it. Not the developer who reviewed it. Not the senior engineer who approved the merge. Only the compiler.
That is the double whammy. It is not just that AI-generated code can’t be trusted to be safe. It is that the human in the loop who is supposed to catch the AI’s mistakes can’t be trusted either. So the language is adding a backstop that doesn’t depend on either of them.
The research is unambiguous
Microsoft cites it in the same post, which is worth flagging because most vendor blog posts cite research the way a teenager cites Wikipedia, but this one does the work.
Perry et al., presented at CCS ’23, looked at developers using AI coding assistants versus developers without them. The result: developers using AI assistants produced significantly less secure code than the unassisted control group. The kicker, and this is the part you should print and tape to your monitor, is that those same developers rated their own AI-assisted output as more secure than the unassisted control group did. So not only does AI assistance produce worse security outcomes, the developers using it have lower fidelity to that fact. They are not just wrong. They are confidently wrong.
Mündler et al., PLDI ’25, showed that pushing type-system constraints into LLM decoding cuts compilation errors by more than half. Khatry et al., COLM ’25, found that agents with compiler feedback roughly double their success rate on C-to-safe-Rust repository translation. Patil et al., NeurIPS ’24, demonstrated that LLMs given retrievable API documentation hallucinate less and call APIs more reliably. Cassano et al., TSE ’23, established that LLM code-generation performance tracks syntactic proximity to high-resource languages, not just training volume in the target language.
Read those papers together. The path to AI-generated code that doesn’t break things is to make the language grammar narrower, the safety obligations machine-readable, and the compiler stricter. The path is not better prompts. It is not smarter agents. It is not better training data. It is restricting the grammar so the agent has fewer ways to be wrong.
That is why C# 16 is being modeled almost identically on Rust’s unsafe / unsafe block pattern. Not because Rust is fashionable. Because Rust’s safety corpus is already massive, well-documented, and pattern-matchable by any modern model. An agent that has read every public Rust crate can transfer that pattern to C# the moment the syntax aligns. Microsoft is buying off the shelf, and that’s the right move.
The threat model shift
Every previous AI-codegen safety pitch I have seen has been about training, RLHF, eval benchmarks, red teaming, or post-hoc scanners. They all share one quiet assumption: the agent can, with enough work, be made safe. C# 16 quietly rejects that assumption.
The new threat model treats the agent as an untrusted code-producing process. Like a P/Invoke into native code that you didn’t write. Like a binary you got from a vendor. Something that produces output you cannot trust on its face and that you need structural constraints to contain.
Lander’s AI enablement section lists two ways an agent can subvert the model. The agent can generate code that doesn’t compile. Or the agent can flip the project flags and turn off the safety model entirely. Both are immediately visible in git history. That is the entire defense. There are no claims about the agent being well-behaved, well-aligned, well-prompted, or well-trained. There are only claims about how easy it is to detect when the agent has done something wrong.
This is what mature security thinking looks like. You design for adversarial outputs even when the producer is not adversarial. You make the bad path expensive and the visibility cheap. You do not trust your way to safety. You constrain your way to safety.
The honest framing
Microsoft is doing something I have not seen any other major language vendor do this clearly. They are publishing a post that says, in plain language, that their previous safety model relied on convention and skill, and that is no longer good enough.
The reason it is no longer good enough has nothing to do with developers getting worse. It has to do with the volume of code in motion. AI-assisted code generation scales faster than human review can absorb. CISA has been beating this drum for years. Google, Microsoft, and Mozilla have been documenting internally that roughly seventy percent of their security bugs are memory safety bugs for the better part of a decade. The new variable is that code production is now decoupling from code reading. Not slowly. All at once.
The honest framing is this. If you are an engineering leader running a team that uses AI coding assistants, your code review process is the bottleneck. Not because reviewers are slow. Because they cannot scale to the volume of code being produced and cannot maintain the level of attention required to catch unsafe patterns reliably. Microsoft is acknowledging that and moving the safety check to a place where the volume doesn’t matter. The compiler doesn’t get tired. The compiler doesn’t approve a PR because it’s late on Friday. The compiler doesn’t trust the author.
Or build slopgentic .NET
Imagine the alternative. The path the rest of the industry is sleepwalking toward if the compiler doesn’t pick up the slack. The path where the answer to AI slop is more AI.
Picture this pipeline. The agent writes the code. A second agent translates the diff into a sixth-grade reading-level English summary and shows it to the developer in the GitHub UI. The developer skims that summary on their phone in the rideshare back from lunch, sees three confident bullet points and a green checkmark, and clicks approve. The agent commits. A GitHub Action wakes up, reads the diff, takes its best guess at what the original agent was trying to accomplish, and writes a 400-word paragraph of speculation labeled intent analysis that no human will ever open. A third agent reviews the intent analysis and either approves it or escalates to a fourth agent on a different model family for a second opinion. Tests run. Some of them pass. The ones that fail get rewritten by a fifth agent until they pass. The compiler, finally, gives up trying to make sense of the C# input as written, and just emits MSIL based on a probabilistic match against the rest of the codebase’s patterns, with a confidence score attached as a build artifact.
Let’s call it what it is. Slopgentic .NET. The pipeline where agents agent at each other in concentric rings around a developer who has not actually read any code in eighteen months, and the build artifact is something that runs without anybody being able to explain why.
This is not a strawman. Every layer I just described exists today as a product. Some of them are venture-funded. A few have IPO’d. The only thing keeping slopgentic .NET from shipping as a fully integrated platform is the lingering pretense that humans are reviewing something, somewhere, at some stage of the pipeline. The moment that pretense drops, and it will drop quietly, slopgentic .NET launches with a keynote, a hero video, and a free tier.
The thing that makes this scenario insidious is that every individual layer of it sounds reasonable in isolation. A plain-English diff summary is helpful. An intent analyzer is helpful. A second-opinion agent is helpful. Auto-repairing failing tests is helpful. Each layer adds a small amount of value. The compounded effect is a system in which nobody, human or machine, has end-to-end accountability for what shipped. The errors compound silently and the audit trail is a stack of LLM monologues.
The C# 16 model is the alternative to that future. Not a smarter wrapper. Not a better-prompted agent. Not a more eloquent intent summary. A narrower grammar, machine-checkable safety contracts, and a compiler that refuses to emit unsafe code unless somebody explicitly checked a box that the entire org can audit in five seconds. The whole pipeline collapses back to two things you can actually trust. What the compiler enforces, and what the project file says. Everything else is slop.
Where this is going
The next decade of language design is going to be defined by this shift. Languages that take it seriously will get a structural advantage. Languages that do not will become the substrate on which the next generation of supply-chain incidents are written, narrated to the executive team in plain English by an agent that does not understand what it is summarizing.
C# 16 is the first major mainstream managed language to make the move in a fully public, fully designed, fully shipping form. Rust got there first by being designed for it from the beginning. Swift is partway there with strict-memory-safety mode. Java, Python, JavaScript, Go, and the rest of the broad ecosystem are still pretending that linting and code review are sufficient. They are not. They have not been for a while.
The smaller blast radius is the only honest answer. Microsoft just put it in writing.
If you are shipping production .NET code in 2026, here is the move. Watch for the new opt-in property when .NET 11 preview lands. Enable it in your templates the day it ships. Leave AllowUnsafeBlocks set to false at the project level. Audit every project where you have flipped it to true. Get your unsafe API surface documented with /// <safety> blocks before your agents start writing code against it. Treat the new model the way you treated nullable reference types when they shipped, except with more urgency, because this one isn’t about cleaner code. It is about not getting owned by a PR you didn’t read carefully enough.
The compiler is the new code reviewer. The project file is the new audit log. Act accordingly, or ship in the slopgentic stack and find out what production looks like when nobody can explain the diff.



