# Edge's Two Password Cryptographies: A Beautiful PSI on the Wire, and Plaintext RAM by Design

> Microsoft Edge ships a homomorphic-encryption PSI for breach checking and decrypts every saved password into process RAM at launch. Both designs are deliberate. They defend different threat models.

*Published: 2026-05-11*
*Canonical: https://paragmali.com/blog/edges-two-password-cryptographies-a-beautiful-psi-on-the-wir*
*License: CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/*

---
<TLDR>
Microsoft Edge ships two cryptographic designs for "passwords" inside the same `msedge.exe` binary, owned by the same product team, with radically different threat models. The first -- Password Monitor -- is a deployed Private Set Intersection protocol built on Microsoft SEAL, the first production consumer homomorphic-encryption deployment in a browser, and is state-of-the-art cryptography for defending against a compromised breach-corpus server. The second -- Edge's local credential storage -- decrypts every saved password into process memory at browser launch and keeps it there for the lifetime of the session, a design Tom Joran Sonstebyseter Ronning's `EdgeSavedPasswordsDumper` (May 4, 2026) made legible and that Microsoft classified as "by design." These are not incompatible designs. They are precise statements about which threat models the Edge product team is and is not defending against, and treating them as one unified "password security" story masks where the actual compromise happens in 2026.
</TLDR>

## 1. Two cryptographies, one product, one week

On **January 21, 2021**, Microsoft Research's Cryptography and Privacy group announced Edge's Password Monitor ships a homomorphic-encryption-based Private Set Intersection protocol built on Microsoft SEAL. The post is explicit that this is "possible due to pioneering cryptography research and technology incubation done here at Microsoft Research," that it is the result of a collaboration "between [the] Cryptography and Privacy Research Group, and Edge product team," and that the protocol descends from two specific papers: "Fast Private Set Intersection from Homomorphic Encryption" and "Labeled PSI from Fully Homomorphic Encryption with Malicious Security" [@msr-password-monitor-2021]. It is, by a comfortable margin, the first production consumer deployment of homomorphic encryption in a browser.

On **May 4, 2026, at 14:29:51 UTC**, a researcher in Oslo named Tom Joran Sonstebyseter Ronning posted to X: "Microsoft Edge loads all your saved passwords into memory in cleartext -- even when you're not using them" [@ronning-x]. He linked a GitHub repository called `EdgeSavedPasswordsDumper`: roughly 500 lines of C# that opens a handle to the parent `msedge.exe` process and reads every saved credential as plaintext, with no kernel exploit, no admin (against same-user processes), and no [DPAPI](/blog/dpapi-and-dpapi-ng-the-credential-vault-under-everything/) bypass [@ronning-github]. The README confirms the behaviour is present in "any Edge versions that's Chromium based (from version 79 and newer, including 147.0.3912.98 and any future version)" [@ronning-github]. Two days later, on **May 6, 2026**, Microsoft told Forbes that the in-memory behaviour is "an expected feature of the application" and "by design" [@forbes-winder].

Both designs ship in the same binary. Both are owned by the same product team. Both can be defended on technical grounds. And both stories get told about the same word: "passwords."

This article argues they are about two different threat models, and the apparent contradiction in the headline disappears once you separate them.

<Definition term="Private Set Intersection (PSI)">
A two-party cryptographic protocol in which Alice holds a set $S_A$, Bob holds a set $S_B$, and they jointly compute $S_A \cap S_B$ such that each party learns the intersection (or, in some variants, only one party does) and nothing else about the other party's set beyond what the intersection implies.
</Definition>

The PSI story is genuinely beautiful. It begins in 1986 with a paper hardly anyone reads, climbs through a 35-year cryptographic engineering effort to make oblivious transfer cheap enough to be free, lands in 2017 on a homomorphic-encryption breakthrough whose cost curve fits the breach-checking problem exactly, and ships on consumers' desktops by 2021 [@msr-password-monitor-2021]. The endpoint-storage story is genuinely awkward. Edge unwraps every DPAPI-encrypted saved credential into process memory when the password feature first activates, keeps the plaintext resident for the lifetime of the session, and accepts that any same-user process can read it back out [@ronning-github]. Microsoft's official position is that local code execution on the user's machine is "outside the threat model" of the browser password store -- a position that is internally consistent with a decade of MSRC policy and also true [@forbes-winder].

The thesis: **"password security" is at least two threat models**, and Microsoft has chosen to deploy genuinely state-of-the-art cryptography against one of them while explicitly conceding the other. Treating both as one unified story is how product narratives obscure where the actual compromise happens in 2026.

<Mermaid caption="The two-thread timeline: PSI's 40-year academic lineage on top, the browser credential-storage architectural choice on the bottom, converging in the same msedge.exe binary in 2026.">
timeline
    title PSI and browser credential storage, 1986 to 2026
    1986 : Meadows PSI
         : NRL matchmaking
    1999 : Huberman-Franklin-Hogg
         : DH meet-in-the-middle
    2003 : IKNP03 OT extension
    2004 : FNP04 polynomial PSI
    2015 : KOS15 active security
    2016 : KKRT16 OPRF-PSI
    2017 : CLR17 HE-PSI
         : Signal SGX contact discovery
    2018 : CHLR18 Labeled PSI
         : HIBP v2 k-anonymity
    2019 : Google Password Checkup
         : Silent OT
    2021 : Edge Password Monitor ships
         : Cong et al. CCS 2021
    2024 : Chrome App-Bound Encryption
    2026 : Ronning EdgeSavedPasswordsDumper
         : Microsoft "by design"
</Mermaid>

To see why the two designs are not a contradiction, we need to understand how PSI got to be deployable at all -- a story that begins forty years before Edge Password Monitor existed.

## 2. Why Private Set Intersection exists at all

Imagine two parties, neither of whom trusts the other. Alice has a set of identifiers; Bob has a set of identifiers. They want to learn which identifiers they share -- and only that. Each party wants to learn nothing about elements not in the intersection.

This is not an obvious problem to need a protocol for. If Alice and Bob trusted a third party, they would hand over their sets. If they trusted each other, they would compare directly. The problem only becomes interesting when neither assumption holds. The 2026 canonical version looks like this: *Microsoft holds a curated set of roughly five billion breached credentials, and the user holds a few hundred passwords saved in their browser. The user wants to know which of their passwords appear in Microsoft's breach corpus -- and they want Microsoft to learn nothing about the passwords that do not.* (Throughout this article the "five billion" figure is the author's 2026 forward projection of Microsoft's compromised-credential corpus; the contemporaneous Microsoft Research figure used in the 2021 Password Monitor announcement is four billion [@msr-password-monitor-2021], and the §3 sidenote spells out the inference.)

That framing did not exist in 1986. The original motivation was much weirder.

### The 1986 paper

Catherine Meadows, then at the U.S. Naval Research Laboratory, published "A More Efficient Cryptographic Matchmaking Protocol for Use in the Absence of a Continuously Available Third Party" at the 1986 IEEE Symposium on Security and Privacy [@meadows-1986][@ieee-6234864]. The titular "matchmaking" problem was prosaic. Two parties want to learn whether they share an interest in some sensitive list -- classified-mailing-list membership, intelligence-source overlap, the everyday work of compartmented information systems -- without revealing anything else.

Meadows's protocol uses commutative encryption. Alice and Bob both raise the elements of their sets to private exponents over a Diffie-Hellman group. After two rounds, both parties hold the doubly-blinded versions of both sets. Equal underlying elements produce equal doubly-blinded values, because exponentiation in an Abelian group commutes. Unequal elements look like uniform-random group elements to both sides. The intersection comes out; the rest does not.

Meadows wrote this ten years before Diffie-Hellman key exchange shipped in SSL 3.0 (November 1996), the protocol family TLS would standardise in 1999 [@wikipedia-tls], and forty years before her protocol's intellectual descendants would ship in a consumer browser.

### The 1999 revival

The same protocol shape was rediscovered and given its modern formulation by Bernardo Huberman, Matthew Franklin, and Tad Hogg at Xerox PARC in 1999. Their paper "Enhancing Privacy and Trust in Electronic Communities" was published at the First ACM Conference on Electronic Commerce [@hfh-1999]. The motivations were online-community problems that look quaint today: which of your friends are on this matchmaking site, do we share interests on a sensitive bulletin board, can two early-internet communities establish trust without leaking their member lists. The protocol they wrote down -- usually called "DH meet-in-the-middle" or just "the Huberman-Franklin-Hogg protocol" -- is the canonical PSI shape every security engineer still reaches for first.

<Sidenote>The dblp BibTeX record gives the canonical DOI as 10.1145/336992.337012, which the ACM Digital Library 403s to most non-browser User-Agents. The dblp HTML mirror returns 200 and confirms the citation [@dblp-hfh].</Sidenote>

### What had to exist before

PSI predates breach checking by twenty years. The cryptographers who built PSI did not know they were building Edge Password Monitor. They were building a protocol primitive that happened, much later, to map cleanly onto a problem the world did not yet have.

The first such mapping landed in 2018 with HIBP's k-anonymity API and the cluster of academic and industry PSI deployments that followed [@hunt-pwned-v2-2018]. The primitive predated the killer application by two and a half decades. This is the normal shape of cryptographic engineering: the primitive sits on the shelf until the world needs it.

The DH meet-in-the-middle protocol is elegant. It is also catastrophically wrong for the breach-checking use case. To see why, we have to count exponentiations.

## 3. Early approaches: DH meet-in-the-middle and FNP04

Let us walk the DH meet-in-the-middle protocol step by step. Alice holds a set $S_A$. Bob holds a set $S_B$. Both parties agree on a Diffie-Hellman group $G$ of prime order $q$ with generator $g$, and on a cryptographic hash function $H: \{0,1\}^* \to G$ that maps set elements into the group. Alice picks a private exponent $a \in \mathbb{Z}_q$; Bob picks $b$.

The protocol proceeds in two rounds:

1. Alice computes $\{H(x)^a : x \in S_A\}$, shuffles, and sends to Bob.
2. Bob computes $\{H(y)^b : y \in S_B\}$, shuffles, and sends to Alice.
3. Alice exponentiates every value Bob sent her by $a$, producing $\{H(y)^{ab} : y \in S_B\}$. She sends this set back to Bob *in the order Bob originally sent his* $\{H(y)^b\}$, so Bob can index by his own set.
4. Bob exponentiates Alice's first-round values by $b$, producing $\{H(x)^{ab} : x \in S_A\}$. (In the symmetric variant Bob also sends his doubly-blinded set back to Alice; either side can then perform the match.)
5. Both parties now hold the same doubly-blinded set for both sides. Equal underlying elements collide; unequal ones do not. They intersect locally.

<Mermaid caption="DH meet-in-the-middle PSI: each party blinds their set with a private exponent, exchanges the blinded set, and the equal-blinded-value match reveals the intersection without revealing anything else.">
sequenceDiagram
    participant A as Alice (set S_A)
    participant B as Bob (set S_B)
    Note over A,B: shared group G, hash H, private exponents a (Alice), b (Bob)
    A->>B: shuffled set of H(x)^a for x in S_A
    B->>A: shuffled set of H(y)^b for y in S_B
    A->>A: compute H(y)^(ba) for each item from Bob
    B->>B: compute H(x)^(ab) for each item from Alice
    Note over A,B: equal underlying elements yield equal doubly-blinded values
    A->>B: ordered set of H(y)^(ab) for matching
    Note over A,B: intersection computed locally
</Mermaid>

Why this is right. Under the Decisional Diffie-Hellman (DDH) assumption in $G$, the doubly-blinded values $H(x)^{ab}$ for $x \notin S_A \cap S_B$ look uniformly random to the other side. Equal underlying elements collide; unequal underlying elements do not. The reader can verify this for themselves in the demonstration below, which is the canonical pedagogical version of the protocol.

<RunnableCode lang="js" title="Toy DH meet-in-the-middle PSI in ~30 lines">{`
// Toy PSI -- pedagogical only, NOT secure (small modulus, weak hash).
const p = 2n ** 61n - 1n;      // Mersenne prime, small for demo
const g = 37n;                  // generator over Z_p* (toy)
const H = s => {
  // toy hash: deterministic map string -> [1, p-1]
  let h = 1469598103934665603n;
  for (const c of s) h = ((h ^ BigInt(c.charCodeAt(0))) * 1099511628211n) % p;
  return h === 0n ? 1n : h;
};
const expMod = (base, exp, mod) => {
  let r = 1n, b = base % mod, e = exp;
  while (e > 0n) {
    if (e & 1n) r = (r * b) % mod;
    b = (b * b) % mod;
    e >>= 1n;
  }
  return r;
};
const S_A = ["alice-at-example.com", "bob-at-example.com", "carol-at-example.com"];
const S_B = ["dave-at-example.com", "bob-at-example.com", "carol-at-example.com"];
const a = 0xC0FFEEn, b = 0xBADCAFEn;
const A1 = S_A.map(x => expMod(H(x), a, p));   // Alice -> Bob
const B1 = S_B.map(y => expMod(H(y), b, p));   // Bob -> Alice
const A2 = A1.map(v => expMod(v, b, p));       // Bob blinds Alice's set
const B2 = B1.map(v => expMod(v, a, p));       // Alice blinds Bob's set
// Reveal intersection by matching doubly-blinded values
const setA2 = new Set(A2.map(String));
const intersection = S_B.filter((_, i) => setA2.has(String(B2[i])));
console.log("Intersection:", intersection);
`}</RunnableCode>

The protocol does work. It gives semi-honest security under DDH and costs $O(|S_A| + |S_B|)$ group exponentiations per side, plus the same again to blind the received set. In a balanced setting -- two sets of similar size, perhaps a few thousand elements each -- it is genuinely deployable.

### The three things that go wrong at scale

For breach checking, the protocol breaks in three documented ways.

**Set-cardinality leakage.** The shuffled lists Alice and Bob send each other have lengths $|S_A|$ and $|S_B|$. Bob learns precisely how many passwords Alice has saved; Alice learns precisely how big Bob's breach corpus is. The first leak is small but real; the second is fine when the server publishes its corpus size anyway (HIBP does), but the protocol does not hide it.

**Online-cost asymmetry.** The server pays $O(|S_B|)$ exponentiations per client query. At the five-billion-element scale of Microsoft's compromised-credential corpus, no realistic group exponentiation cost makes this feasible per query: even at 100 microseconds per exponentiation (optimistic for $|q| = 256$), five billion exponentiations is more than five days of single-core CPU. Sharding helps. Caching helps. Pre-computation helps. None makes the asymptotic curve workable as the corpus grows.

**No labeled variant.** The protocol returns set membership, not associated metadata. Edge Password Monitor wants to tell you "this credential appeared in breach X" -- so the protocol has to support associating a server-side label with each set element and returning the label for matched elements. DH meet-in-the-middle does not, without unpleasant extensions.

### FNP04: the right idea, wrong substrate

The algebraic alternative arrived in 2004 with Freedman, Nissim, and Pinkas's "Efficient Private Matching and Set Intersection" at EUROCRYPT [@fnp-2004]. The idea is gorgeous. Alice encodes her set $S_A = \{x_1, \dots, x_n\}$ as the polynomial whose roots are her set:

$$p(z) = \prod_{i=1}^{n} (z - x_i)$$

Alice encrypts each coefficient of $p$ under an additively-homomorphic encryption scheme (Paillier, in the paper). She sends the encrypted coefficients to Bob. Bob homomorphically evaluates $p(y)$ for every element $y$ of his set $S_B$ and returns the encrypted results. If $y \in S_A$, then $p(y) = 0$, and after decryption Alice sees a zero in the corresponding position. If $y \notin S_A$, then $p(y)$ is a non-trivial polynomial evaluation that, randomized correctly, decrypts to a uniform value Alice cannot interpret.

This is the first asymmetric PSI -- the first protocol where one party can do most of the work while the other sends only a small encrypted query. It is also, in deployment terms, structurally infeasible at scale. Paillier ciphertexts live in $\mathbb{Z}^*_{n^2}$ and are $2 \cdot |n|$ bits each [@paillier-1999] (2048 bits for FNP04's $|n| = 1024$ default; 4096 bits for the $|n| \geq 2048$ that modern security demands). Paillier homomorphic evaluation needs full-size modular exponentiation per coefficient, and the server compute scales as $O(|S_A| \cdot |S_B|)$. At Edge Password Monitor's target scale -- a client set of a few hundred passwords against a five-billion-element server corpus -- a single query would take minutes to hours of server compute and tens of megabytes of round-trip data per query.

<Sidenote>The 5-billion-element estimate is INFERRED, not measured (see §2 for the article-wide projection disclosure). No published source benchmarks FNP04 at that scale; the inference combines the $O(|S_A| \cdot |S_B|)$ asymptotic with measured Paillier throughput on commodity hardware. The order-of-magnitude conclusion is sound; treat the precise number as a back-of-envelope.</Sidenote>

<Sidenote>The polynomial-roots idea is not dead. Thirteen years later, Chen, Laine, and Rindal will revive exactly this construction inside CLR17 [@clr-2017], with Paillier replaced by BFV-style somewhat-homomorphic encryption and a partition-and-evaluate trick that fixes the $O(|S_A| \cdot |S_B|)$ blow-up. The structure survives; the substrate gets swapped.</Sidenote>

| Protocol | Era | Server cost | Communication | Verdict at 5B-element scale |
|---|---|---|---|---|
| DH meet-in-the-middle [@hfh-1999] | 1999 | $O(|S_B|)$ DH exponentiations | $O(|S_A| + |S_B|)$ | Bandwidth and compute both impossible |
| FNP04 [@fnp-2004] | 2004 | $O(|S_A| \cdot |S_B|)$ Paillier ops | $O(|S_A|)$ ciphertexts | Compute impossible |
| (preview) HE-PSI on BFV [@clr-2017] | 2017 | $O(|S_B| \log |S_A|)$ FHE ops | $O(|S_A| \log |S_B|)$ | Workable |

> **Note:** The naive approach -- "just hash and compare" -- leaks set cardinality at a minimum, and plain hashing is brute-forceable against any password the server can guess. Doing PSI properly under encryption requires either $O(|S_A| \cdot |S_B|)$ server work and 2048-bit Paillier ciphertexts (FNP04, dead at billions), or a new primitive: oblivious transfer at scale. It takes a decade of engineering to make that primitive free.

FNP04's polynomial idea will turn out to be the right idea -- but only after we replace Paillier with somewhat-homomorphic encryption thirteen years later. Before we can get there, we need a different breakthrough: making the underlying oblivious-transfer primitive cheap enough that *every* PSI in the literature can ride on it.

## 4. The evolution: oblivious transfer extension

Here is the central fact that drove a decade of cryptographic engineering: **every PSI protocol that scales eventually reduces to "many oblivious transfers."** OT is the universal building block. Once you can do millions of OTs per second, you can do nearly any two-party secure computation, including PSI. The question is how cheap "many OTs" can become.

<Definition term="Oblivious transfer (OT)">
A two-party primitive. In 1-out-of-2 OT, the sender holds two messages $(m_0, m_1)$, the receiver chooses a bit $b$, and after the protocol runs the receiver learns $m_b$ while the sender learns nothing about $b$. OT is universal -- it suffices for secure two-party computation of any function -- and it is also expensive: implemented directly from public-key primitives, each OT costs at least one Diffie-Hellman exponentiation, on the order of a millisecond per OT on commodity hardware.
</Definition>

<Definition term="OT extension">
A two-phase protocol that performs $m$ OTs at the cost of $\kappa$ "base" OTs (typically $\kappa = 128$, implemented with public-key crypto) plus $O(m)$ symmetric primitive calls. Because $\kappa$ is small and constant, the per-OT cost drops from public-key cost (~1 ms) to symmetric-crypto cost (~100 ns) -- roughly three orders of magnitude, and the asymptotic gap widens with $m$.
</Definition>

### Generation 1: IKNP03

In 2003, Yuval Ishai, Joe Kilian, Kobbi Nissim, and Erez Petrank published "Extending Oblivious Transfers Efficiently" at CRYPTO 2003 [@iknp-2003].

<MarginNote>Ishai and Petrank are at Technion; Kilian and Nissim were at NEC Labs America at the time.</MarginNote> The construction is short enough to summarize in one paragraph and important enough to be called *the* OT extension: start with $\kappa$ "base" OTs done the expensive way (one public-key operation each), then use them to seed pseudorandom generators and a clever transposition trick that, with $O(m)$ hash-function calls, produces $m$ effective OTs. The base cost stays fixed at $\kappa$ public-key operations; the per-OT marginal cost collapses to a few hash invocations.

The numerical impact: before IKNP, secure-computation researchers cited oblivious-transfer cost in milliseconds; after IKNP, in hundreds of nanoseconds. Three orders of magnitude is the difference between "research artifact" and "this protocol can ship."

<Sidenote>IKNP03 has no IACR ePrint preprint; ePrint 2003/052 is a different paper by different authors (Klima, Pokorny, Rosa). Cite Springer LNCS only [@iknp-2003].</Sidenote>

### Generation 2: KOS15

IKNP03 is secure against a *semi-honest* adversary -- one who follows the protocol but tries to learn extra information from the transcript. Real-world deployments often need *active* security: protection against an adversary who deviates to extract information or bias the output.

In 2015, Marcel Keller, Emmanuela Orsini, and Peter Scholl published "Actively Secure OT Extension with Optimal Overhead" [@kos-2015]. The construction adds a correlation-check phase on top of IKNP03 that catches active deviations with overwhelming probability. The paper's own abstract: "no more than 5% more time than the passively secure IKNP extension, in both LAN and WAN environments, and thus is essentially optimal with respect to the passive protocol." Modern implementations (libOTe, EMP-toolkit, MP-SPDZ) report on the order of 10-20% wall-clock overhead and 5-10% communication overhead over semi-honest IKNP03 in production -- the "optimal overhead" in the title is the claim that this margin vanishes as the OT count grows.

After KOS15, "active security is free" became the industry default. Every modern OT-extension library -- libOTe, EMP-toolkit, MP-SPDZ -- ships KOS15 (or a close variant) as the production-grade default. The earlier semi-honest-only choice is a research artifact.

### Generation 3: Silent OT

In 2019, a six-author collaboration -- Elette Boyle, Geoffroy Couteau, Niv Gilboa, Yuval Ishai, Lisa Kohl, and Peter Scholl -- published "Efficient Pseudorandom Correlation Generators: Silent OT Extension and More" at CRYPTO 2019 [@silent-ot-2019]. The construction replaces the communication-heavy IKNP/KOS phase with a *Pseudorandom Correlation Generator* (PCG): the two parties exchange a few-kilobyte seed and locally expand it into millions of correlated OTs.

<Definition term="Pseudorandom Correlation Generator (PCG)">
A protocol primitive that, given a short shared seed, lets two parties locally expand the seed into long correlated random strings -- in the OT case, the random correlations needed to "consume" each OT call. Once the seed is exchanged, no further communication is needed to produce more OTs; the parties simply expand more locally. PCGs reduce the per-OT wire cost to zero in the post-seed phase.
</Definition>

The numerical impact this time is *bandwidth*. Pre-Silent-OT, OT-extension protocols sent on the order of $\kappa$ bits per OT. Silent OT sends a polylogarithmic amount of data total for the entire extension. The precursor construction "Compressing Vector OLE" by Boyle, Couteau, Gilboa, and Ishai [@boyle-vector-ole-2019] laid the algebraic foundation.

For Edge Password Monitor's deployment shape (small client set, large server set), Silent OT does not land in the production protocol -- HE-PSI provides the asymmetric communication scaling -- but its existence in 2019 is part of why the industry treats OT extension as essentially solved engineering and feels free to ride a higher-layer protocol on top.

### The OPRF-PSI plateau: KKRT16

Pure OT-extension is one substrate; the other is the Oblivious Pseudorandom Function.

<Definition term="Oblivious Pseudorandom Function (OPRF)">
A two-party protocol in which the sender holds a key $k$, the receiver holds an input $x$, and after the protocol the receiver learns $F_k(x)$ while the sender learns nothing about $x$. The receiver gets the PRF output without giving up the input; the sender keeps the key without giving up the output. OPRFs are the building block under most modern PSI: each party evaluates the OPRF on their set, then plaintext-compares the outputs.
</Definition>

In 2016, Vladimir Kolesnikov, Ranjit Kumaresan, Mike Rosulek, and Ni Trieu published "Efficient Batched Oblivious PRF with Applications to Private Set Intersection" at CCS 2016 [@kkrt-2016]. The paper builds a batched OPRF directly on top of KOS-style OT extension. The reported benchmark: intersecting two $2^{20}$-element sets on a LAN took about 3.8 seconds total. For several years, KKRT16 was the deployment-grade symmetric-PSI protocol.

KKRT16 is great if your two sets are roughly the same size. The Edge Password Monitor problem is fundamentally asymmetric -- the client holds a few hundred saved passwords, the server holds billions of breached credentials. For *asymmetric* PSI, the OT-extension lineage hits a wall the next generation has to climb.

<Mermaid caption="OT extension as the substrate that all modern PSI rides on. Public-key base OTs are amplified by symmetric crypto into millions of effective OTs; OPRF-PSI (KKRT16) and HE-PSI (CLR17, CHLR18) both layer on top.">
flowchart LR
    A["Kappa base OTs<br/>(public-key)"] --> B["IKNP03 extension<br/>(symmetric)"]
    B --> C["KOS15 active security"]
    C --> D["Silent OT<br/>(PCG-based)"]
    B --> E["KKRT16 OPRF-PSI"]
    C --> F["CHLR18 HE-PSI<br/>+ OPRF wrapping"]
    D --> G["Modern OT-extension libraries:<br/>libOTe, EMP-toolkit"]
    E --> H["Symmetric balanced PSI"]
    F --> I["Edge Password Monitor"]
</Mermaid>

## 5. The breakthrough: HE-based PSI

Asymmetric PSI requires that the server's heavy compute stays on the server, and that the client send only a tiny encrypted query whose size is independent of $|S_B|$. That is exactly what fully homomorphic encryption -- or, more precisely, *somewhat-homomorphic* encryption -- can offer.

<Definition term="Homomorphic encryption (HE), SWHE, FHE">
An encryption scheme is *homomorphic* if operations on ciphertexts decrypt to the corresponding operations on plaintexts. *Somewhat-homomorphic encryption* (SWHE) supports a bounded depth of operations (typically additions and multiplications) before noise growth requires re-encryption. *Fully homomorphic encryption* (FHE) supports arbitrary-depth circuits via bootstrapping. The BFV scheme (Brakerski-Fan-Vercauteren), implemented in Microsoft SEAL [@ms-seal], is the SWHE variant Edge Password Monitor uses; FHE is the popular term but the actual deployed circuit depth fits comfortably within SWHE.
</Definition>

### CLR17: the cost curve flips

In 2017, Hao Chen, Kim Laine, and Peter Rindal published "Fast Private Set Intersection from Homomorphic Encryption" at CCS 2017 [@clr-2017]. The construction is a clean revival of FNP04's polynomial-roots idea, with three engineering moves that fix every reason FNP04 was infeasible.**Move 1: SWHE instead of Paillier.** BFV ciphertexts pack many plaintext slots and support SIMD-style homomorphic operations. A single ciphertext can encrypt and evaluate over thousands of plaintext values in parallel; the slot count is set at scheme-parameter time.

**Move 2: Cuckoo hash partitioning.** The receiver Cuckoo-hashes its set $S_R$ into bins. The sender hashes each element of $S_S$ to the same set of bins. Instead of one giant polynomial whose roots are all of $S_S$, the sender builds one small polynomial per bin -- typically a few thousand bins, each holding a few hundred elements.

<Definition term="Cuckoo hashing">
A hashing scheme that uses $k$ hash functions and inserts each element into one of $k$ candidate bins, displacing existing occupants if necessary (the displaced element finds another of its candidate bins). Cuckoo hashing achieves $O(1)$ worst-case lookup; the achievable load factor depends on the number of hash functions and the bucket size -- roughly 49% with $k=2$ (the original Pagh-Rodler 2001 construction [@pagh-rodler-2001]), roughly 91% with $k=3$, and higher with a stash of evicted elements or $k \geq 4$. CLR17 and CHLR18 use parameter choices in the high-load regime. In CLR17, Cuckoo hashing pairs the receiver's set with the sender's set so that two equal elements end up in the same bin with overwhelming probability.
</Definition>

**Move 3: Partition-and-evaluate.** The receiver encrypts its bins under BFV and sends them. The sender homomorphically evaluates its per-bin polynomial at the encrypted receiver's bin. Because of SIMD slot packing, each bin's polynomial is evaluated in parallel across all slots, and the sender's total work is $O(|S_S| \log |S_R|)$ FHE operations instead of FNP04's $O(|S_R| \cdot |S_S|)$.

The headline benchmark from the paper, on the MSR publication page: "36 seconds of online-computation and 12.5 MB of round trip communication to intersect five thousand 32-bit strings with 16 million 32-bit strings" [@msr-clr17-pub]. Communication scales linearly in the small set and logarithmically in the large set. The cost curve is finally right.

<Mermaid caption="Edge Password Monitor's on-the-wire dance: an OPRF preprocessing round binds the client's query to the server's secret key, then the BFV ciphertext flies one-way for sub-linear homomorphic matching against a sharded breach corpus.">
sequenceDiagram
    participant C as Client (Edge)
    participant S as Server (Microsoft)
    Note over C,S: stage 1 -- OPRF preprocessing (binds queries to server's secret key)
    C->>S: blinded credential beta * H(cred)
    S->>C: alpha * (blinded H(cred)) using server key alpha
    C->>C: unblind, obtain F_alpha(cred)
    Note over C,S: stage 2 -- HE-PSI on sharded corpus
    C->>S: BFV ciphertext encrypting F_alpha(cred), sharded by 2-byte prefix
    S->>S: Cuckoo-hash shard, evaluate per-bin polynomial homomorphically
    S->>C: encrypted match result + label ciphertext
    C->>C: decrypt result, then if match surface breach metadata
</Mermaid>

### CHLR18: labeled, malicious, deployable

The next year, the same authors plus Zhicong Huang published "Labeled PSI from Fully Homomorphic Encryption with Malicious Security" at CCS 2018 [@chlr-2018]. The paper adds three production-grade properties.

**Labels.** Each element in the server's set can carry an associated label (which breach, when, severity). When the receiver finds a match, they also recover the label.

**Malicious security.** The protocol is secure against an actively malicious sender, layered on top of the underlying semi-honest construction via an OPRF preprocessing step. The OPRF is the same primitive we met in §4; here it does double duty: it prevents the client from brute-forcing the server's corpus offline (the client cannot evaluate $F_k(\cdot)$ without server interaction) and provides the malicious-security guarantee.

**Arbitrary-length items.** The protocol handles long inputs (full URLs plus usernames, in the breach-checking case), not just short fixed-width keys.

The headline benchmark: "for an intersection of $2^{20}$ and 512 size sets of arbitrary length items our protocol has a total online running time of just 1 second (single thread), and a total communication cost of 4 MB" [@msr-chlr18-pub]. A larger benchmark of $2^{28}$ and 1024 takes 12 seconds multithreaded with less than 18 MB of communication.

### Cong et al. 2021: the production-grade successor

The protocol that ships in Edge Password Monitor today is the descendant published by Kelong Cong, Radames Cruz Moreno, Mariana Botelho da Gama, Wei Dai, Ilia Iliashenko, Kim Laine, and Michael Rosenberg at CCS 2021: "Labeled PSI from Homomorphic Encryption with Reduced Computation and Communication" [@cong-2021]. The paper is the basis for Microsoft's open-source APSI library [@ms-apsi], whose README states verbatim that it "provides a PSI functionality for asymmetric set sizes based on the protocol described in eprint.iacr.org/2021/1116" and that it "uses the BFV encryption scheme implemented in the Microsoft SEAL library."

<Sidenote>The Cong et al. 2021 byline is seven authors: Kelong Cong, Radames Cruz Moreno, Mariana Botelho da Gama, Wei Dai, Ilia Iliashenko, Kim Laine, Michael Rosenberg. Some upstream reporting conflates a different author list onto the same URL; the citation_author meta-tags returned by ePrint 2021/1116 confirm this seven-author septuple [@cong-2021].</Sidenote>

### The OPRF wrapping and corpus sharding

Two practical layers on top of the bare HE-PSI protocol turn the academic construction into a production deployment, and the Microsoft Research Password Monitor blog is explicit about both [@msr-password-monitor-2021].

First, the OPRF preprocessing. Without it, a malicious client could send candidate passwords one at a time and observe match results, brute-forcing the server's corpus. With it, every client query passes through $F_k(\cdot)$ where $k$ is a server secret. The MSR blog states: "the client communicates with the server to obtain a hash $H$ of the credential, where $H$ denotes a hash function that only the server knows... using an OPRF... the client is prevented from performing an efficient dictionary attack on the server" [@msr-password-monitor-2021].

Second, corpus sharding. The MSR blog notes that the corpus is sharded by the first two bytes of a username-hash. The blog's verbatim example: "Suppose the database $D$ consists of 4 billion credentials, then after sharding each subset, it will contain about 60,000 credentials on average." At the article's 2026 5-billion projection the math is the same -- corpus divided by $2^{16}$ -- and per-shard work is closer to 76,000 credentials. Either way, the per-query homomorphic evaluation runs against tens of thousands of credentials instead of the full corpus. This is the same engineering trade as Apple's 15-bit bucketing -- a small information leak (the client reveals which shard their query lives in) in exchange for tractable per-query compute.

<Definition term="Data Protection API (DPAPI)">
A Windows facility, introduced in Windows 2000, that encrypts arbitrary blobs under a user-derived key chain (ultimately rooted in the user's password, with hardware-bound variants under DPAPI-NG) and exposes a simple `CryptProtectData` / `CryptUnprotectData` API [@ms-learn-dpapi-ng]. Browsers including Chromium store the symmetric key that wraps their saved-password database under DPAPI at rest. This protects the on-disk database when the user is not logged in, but it does not protect process memory after the same user has unwrapped the data into a running browser.
</Definition>

<PullQuote>
"This unique security feature is possible due to pioneering cryptography research and technology incubation done here at Microsoft Research." -- Microsoft Research, January 21, 2021 [@msr-password-monitor-2021]
</PullQuote>

The administrator-visible group policy that controls this feature is `PasswordMonitorAllowed`, documented on Microsoft Learn [@ms-learn-edge-pm].

> **Key idea:** Asymmetric PSI on somewhat-homomorphic encryption flips the cost curve so that communication scales with the small client set, not the enormous server set. That is why a homomorphic-encryption protocol can ship on a consumer browser in 2021 without melting the user's CPU. The cryptographic case for Edge Password Monitor is auditable down to the published papers and unequivocally well-engineered.

Microsoft has shipped the first production consumer homomorphic-encryption deployment in a browser, against the threat "server-side breach corpus leakage," on the same browser that, in §7, will turn out to hold every saved credential in plaintext RAM the entire time you have it open. To make sense of that contrast, we need to see what the rest of the industry did with the same problem.

## 6. State of the art: four deployed compromised-credential services

PSI on paper is one thing. PSI in production is another. The "pure PSI" ideal -- both parties learn the intersection and *nothing else*, no information leaks on either side -- is impractical at planetary scale. Every deployed compromised-credential service in 2026 makes a concession somewhere.

> **Note:** The concessions reveal which threats each provider takes most seriously. Read the next table by column 3 ("what is revealed on the wire") and column 6 ("dictionary-attack hardening") side by side: that pair tells you the threat model each provider chose.

The four services compared here are HIBP Pwned Passwords v3, Google Password Checkup, Apple Password Monitoring (iCloud Keychain), and Microsoft Edge Password Monitor. A fifth, Signal contact discovery, is technically a contact-discovery service rather than a breach checker, but it sits on the same protocol map and is the canonical "we used a TEE instead of pure crypto" data point.

| Service | Protocol family | What's revealed on the wire | Server trust | Bandwidth at scale | Dictionary-attack hardening |
|---|---|---|---|---|---|
| HIBP Pwned Passwords v3 [@hibp-api-v3] | Pure SHA-1 5-hex-char k-anonymity | A 20-bit hash prefix per query | None (zero-trust API) | Trivial (a few KB per query) | None on the wire; SHA-1 hash makes corpus searchable |
| Google Password Checkup [@thomas-usenix-2019] | k-anonymity + blinded-hash OPRF | A small hash prefix per query | Honest-but-curious | Tens of KB per query | OPRF prevents corpus enumeration by the client |
| Apple Password Monitoring [@apple-password-monitoring] | EC-based PSM on NIST P-256 + 15-bit bucket | A 15-bit prefix + double-blinded EC point | Honest-but-curious | A few hundred KB per query (padded) | OPRF + double-blinding + padding-to-fixed-count |
| Signal contact discovery (2017) [@signal-private-contact-2017] | SGX enclave + ORAM (no pure crypto) | Nothing visible to Signal staff | TEE attestation | Negligible (single SGX RPC) | Enclave isolation rather than crypto hardening |
| Microsoft Edge Password Monitor [@msr-password-monitor-2021] | HE-PSI on Microsoft SEAL + OPRF + 2-byte shard | 2-byte username-hash prefix + BFV ciphertext | Honest-but-curious | Single MB-range round trip | OPRF binds queries to server key; HE prevents transcript leaks |

### HIBP Pwned Passwords v3: the k-anonymity baseline

Troy Hunt's "Have I Been Pwned" launched in 2018 with the help of Junade Ali at Cloudflare; the design is published in two posts, Hunt's "I've Just Launched Pwned Passwords Version 2" and Ali's "Validating Leaked Passwords with k-Anonymity" [@hunt-pwned-v2-2018][@ali-cloudflare-2018]. The protocol is delightfully simple: the client hashes the candidate password under SHA-1, sends the first 5 hex characters (20 bits) of the hash to the API, and the API returns every suffix in that bucket. The client compares locally.

<Definition term="k-anonymity (in password monitoring)">
A privacy property: each query produces output that is consistent with at least $k$ other potential queries the client could have made. In the HIBP context, $k$ is the number of distinct password hashes that share the same 20-bit SHA-1 prefix -- typically a few hundred. The server learns the bucket but not which specific password the client cares about, and (because hashes are sparse over the prefix space) cannot easily distinguish "the user has password X" from "the user has password Y" if X and Y share the prefix.
</Definition>

The HIBP corpus serves "18B+ Monthly Requests" against roughly a billion hashes [@hibp-passwords]. Operationally, this is a one-shot HTTP GET. There is no PSI on the wire beyond TLS. The whole protocol fits on the back of an envelope. The cost: each query leaks the 20-bit prefix, which is enough to identify the user's password if the attacker has independent information narrowing the candidate space.

<RunnableCode lang="js" title="k-anonymity bucket simulator: see what a 20-bit prefix actually leaks">{`
async function sha1Hex(s) {
  const buf = new TextEncoder().encode(s);
  const hash = await crypto.subtle.digest("SHA-1", buf);
  return [...new Uint8Array(hash)].map(b => b.toString(16).padStart(2, "0")).join("").toUpperCase();
}
async function showBucket(password) {
  const h = await sha1Hex(password);
  const prefix = h.slice(0, 5);    // 5 hex chars -- 20 bits sent to server
  const suffix = h.slice(5);
  console.log("Password:", password);
  console.log("SHA-1:   ", h);
  console.log("Prefix (leaves your device):", prefix);
  console.log("Suffix (compared locally):  ", suffix);
  console.log("Approx bucket size: ~", Math.round(847_223_402 / (1<<20)), "entries");
}
showBucket("hunter2");
`}</RunnableCode>

The mental model the runnable above gives is the precise shape of the trade. Every HIBP query says "I am asking about a password whose SHA-1 starts with these 20 bits." There are roughly $2^{20} \approx 1{,}048{,}576$ possible prefixes, so each query narrows the server's posterior over your password by exactly that much.

### Google Password Checkup: k-anonymity with an OPRF on top

In August 2019, Kurt Thomas and colleagues at Google published "Protecting Accounts from Credential Stuffing with Password Breach Alerting" at USENIX Security [@thomas-usenix-2019]. The accompanying blog post on the Google Security Blog announces the deployment [@google-blog-password-checkup-2019]. The numbers are familiar at this point: "a cloud service that mediates access to over 4 billion credentials found in breaches and a Chrome extension serving as an initial client. Based on anonymous telemetry from nearly 670,000 users and 21 million logins, we find that 1.5% of logins on the web involve breached credentials" [@thomas-usenix-2019].

The protocol upgrades HIBP's k-anonymity baseline with an OPRF preprocessing round: instead of hashing under SHA-1 locally and sending the prefix, the client first obtains $F_k(\text{password})$ via an OPRF interaction, where $k$ is a Google-held key. The OPRF output is then bucketed and matched against Google's corpus. The OPRF prevents the client from enumerating Google's corpus offline; the bucketing limits per-query server work.

### Apple Password Monitoring: PSM with double-blinding

Apple's protocol is the most cryptographically elaborate of the four. The Apple Platform Security guide is unusually explicit [@apple-password-monitoring][@apple-security-guide-pdf]. From the guide, verbatim: "a form of cryptographic private set intersection is deployed that compares the users' passwords against a large set of leaked passwords"; the corpus is "approximately 1.5 billion passwords... into $2^{15}$ different buckets"; and the protocol uses elliptic-curve PSM on NIST P-256 with a double-blinded structure.

The math, slightly compressed. Let $H_{\text{SWU}}$ be the Shallue-van de Woestijne-Ulas hash-to-curve.

<MarginNote>Google publishes an open-source PSM construction at `google/private-membership` [@google-private-membership-github]; Apple's protocol shares the EC double-blinding skeleton.</MarginNote> Apple computes a per-corpus-element representation:

$$P_{pw} = \alpha \cdot H_{\text{SWU}}(pw)$$

where $\alpha$ is a secret random key known only to Apple. The client computes its query:

$$P_c = \beta \cdot H_{\text{SWU}}(u \| pw)$$

with $\beta$ chosen randomly per-query. The interaction lets the client recover $\alpha \cdot H_{\text{SWU}}(u \| pw)$ and check it against a 15-bit bucket of $P_{pw}$ values. The double-blinding is the point: $\alpha$ stays Apple's secret (so the client cannot enumerate); $\beta$ stays per-query random (so Apple cannot link two queries from the same client).

<Sidenote>Apple's PSM defends *also* against the server learning how many unique passwords a user has, by padding-to-fixed-count with random queries: "if a user has fewer than this number, random passwords are generated and added to the queries to make up the difference" [@apple-password-monitoring]. None of the other four services deploys this defence. The padding cost is the price.</Sidenote>

### Signal contact discovery: the TEE outlier

In September 2017, Moxie Marlinspike published "Technology Preview: Private Contact Discovery" on Signal's blog [@signal-private-contact-2017]. The post is candid about the cost calculation that drove Signal toward Intel SGX rather than pure cryptographic PSI:

<PullQuote>
"Signal clients will be able to efficiently and scalably determine whether the contacts in their address book are Signal users *without revealing the contacts in their address book to the Signal service*." -- Moxie Marlinspike, September 2017 [@signal-private-contact-2017]
</PullQuote>

Marlinspike is explicit about the cost calculation: "Doing better is difficult. There are a range of options that don't work... like using bloom filters, encrypted bloom filters, sharded bloom filters." Signal examines pure cryptographic PSI and decides, given its scale and latency requirements, that an SGX enclave running a constant-time ORAM-protected lookup is the better engineering trade [@signal-cds-github].

<Aside label="Why Signal chose SGX">
The SGX choice came with side-channel debt that subsequent literature made expensive. Foreshadow (2018) [@foreshadow-2018], SgxPectre (2018) [@sgxpectre-2018], SGAxe (2020) [@sgaxe-2020], and AEPIC Leak (2022) [@aepic-leak-2022] all targeted SGX directly. Each disclosure prompted Signal to publish a re-evaluation. Signal eventually migrated to the second-generation Contact Discovery Service (CDSI), which continues to rely on TEEs but with a hardened threat model. The point for our story is not that SGX is bad. It is that "pure crypto vs. TEE" is not a settled question; every provider revisits it under their own latency, corpus, and threat-model constraints, and each makes a different decision.
</Aside>

### Microsoft Edge Password Monitor

The Microsoft deployment is the only one shipping a full HE-PSI protocol on the wire against the full corpus. As established in §5, the protocol stack is:

1. Two-byte username-hash shard selection (corpus partitioned, sender does work only against tens of thousands of elements per query -- the MSR blog's 2021 example uses 4 billion / $2^{16} \approx$ 60,000; the article's 2026 5-billion projection yields $\approx$ 76,000).
2. OPRF preprocessing (binds queries to a server secret; prevents client-side enumeration).
3. BFV-encrypted query, evaluated against the Cuckoo-hashed per-bin polynomials, returned as a single ciphertext per shard.
4. Client decrypts; if matched, decrypts the associated label (the breach metadata).

All four moving parts are described in the MSR blog, the Cong et al. 2021 paper, and the open-source APSI library [@msr-password-monitor-2021][@cong-2021][@ms-apsi]. Communication scales with the small client set; sender compute scales with the (sharded) server set. The Microsoft Edge enterprise documentation says the feature "helps Microsoft Edge users protect their online accounts by informing them if any of their passwords are found in an online leak" [@ms-learn-edge-pm].

### Four products, four concessions

| Service | Primary concession | What it defends against | What it does not |
|---|---|---|---|
| HIBP | 20-bit prefix leak per query | Server learning the password | A linkage attack on repeated queries |
| Google PCU | OPRF transcript + prefix | Client-side corpus enumeration | Server-side query inference if the prefix is rare |
| Apple PSM | 15-bit bucket + double-blinding overhead | Both client and server enumeration; query linkage | Side-channels on the EC implementation |
| Signal CDS | TEE attestation trust | Server-side mass-data exfiltration | SGX side-channel attacks |
| Edge PM | 2-byte shard leak + OPRF transcript | Anything short of breach corpus leakage from inside Microsoft | Endpoint compromise -- see §7 |

Four products. Four different concessions. Each is internally coherent. None of them solves a problem that Tom Joran Sonstebyseter Ronning's PoC will turn out to make trivial.

## 7. The other half: plaintext RAM "by design"

Now we turn the article inside out.

Everything we have built so far -- IKNP, KOS, KKRT, CLR17, CHLR18, Cong et al., Apple's PSM, Google's k-anonymity wrapping, the entire CCS-grade cryptographic stack inside Edge -- assumes the *endpoint* is trustworthy. The question Ronning asked on May 4, 2026 is what happens when it is not.

### The disclosure

The X post arrived at 14:29:51 UTC on May 4, 2026 [@ronning-x]: "Microsoft Edge loads all your saved passwords into memory in cleartext -- even when you're not using them." Five hours later the GitHub repository went public, with a complete C# proof-of-concept and a long README [@ronning-github]. PCWorld picked up the story two days later under the byline of Laura Pippig, summarising Microsoft's response in English [@pcworld-pippig-2026]. The Norwegian origin, ITavisen, carried the verbatim "by design" rendering and named Ronning's affiliation with the transmission-system operator Statnett [@itavisen-2026]. Davey Winder at Forbes reached Microsoft and obtained the official spokesperson statement on May 6, 2026 [@forbes-winder].

<Sidenote>Ronning works at Statnett and presented this finding at BigBiteOfTech (Palo Alto Networks Norway) on April 29, 2026 -- five days before the public X-post disclosure [@itavisen-2026]. The X bio describes "#PenetrationTesting using only tools that are already on the system."</Sidenote>

### What the PoC does

The C# program is short. `OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, ...)` against the parent `msedge.exe`. A walk over committed memory regions via `VirtualQueryEx`. `ReadProcessMemory` reads of every region. Pattern matching for stored credential structures. Output: every saved Edge password as plaintext.

The README is explicit on the constraints. "Can be run without Adminstrator rights, but will only be able to access Edge processes ran by the same user. If run with Administrator privileges, the program can access and read memory from other users' Edge processes on the same machine" [@ronning-github]. No kernel exploit. No DPAPI bypass. The DPAPI unwrap happened earlier, when Edge launched (or when the password feature first activated); the cleartext has been sitting in `msedge.exe`'s heap ever since.

The tested target is Edge 147.0.3912.98, but the README explicitly generalises: "Any Edge versions that's Chromium based (from version 79 and newer, including 147.0.3912.98 and any future version, as Microsoft won't change this feature)" [@ronning-github].

### What the architectural choice is

The behaviour Ronning identifies is not a memory-safety bug. It is a design choice: Edge unwraps every DPAPI-protected saved credential into process memory when the password manager activates, and keeps the plaintext resident for the lifetime of the session.

<Mermaid caption="Edge process memory architecture: DPAPI-encrypted on disk, unwrapped into process heap on launch, readable by any same-user process via ReadProcessMemory.">
flowchart TD
    A["Saved password file<br/>(SQLite blob)"] -->|"DPAPI-wrapped at rest"| B["Disk: encrypted with<br/>per-user DPAPI key"]
    B -->|"msedge.exe launches"| C["DPAPI CryptUnprotectData()<br/>unwraps key"]
    C -->|"password manager activates"| D["Plaintext credentials<br/>resident in msedge.exe heap"]
    D -->|"OpenProcess + ReadProcessMemory<br/>(same-user, no admin)"| E["EdgeSavedPasswordsDumper<br/>reads cleartext"]
    D -->|"autofill flow"| F["Plaintext copied into<br/>renderer / web form"]
    style D fill:#fee,stroke:#c33
    style E fill:#fcf,stroke:#939
</Mermaid>

Chrome and Brave do not do this. Both browsers decrypt credentials only at the autofill RPC -- the password manager fetches the DPAPI-wrapped blob, decrypts in a narrow window, hands the plaintext to the relevant renderer, and zeroes the buffer [@chromium-os-crypt]. PCWorld corroborates: "Other password managers, including those that are built into browsers, don't operate in this way -- Ronning says Edge is the only Chromium-based browser he's tested with this behavior" [@pcworld-pippig-2026].

In July 2024, Google announced Chrome App-Bound Encryption -- a further hardening of exactly this same-user-LCE threat model. ABE binds the on-disk key unwrap to a verified Chrome process identity, so a malicious program impersonating Chrome cannot ask DPAPI to unwrap Chrome's data even if it runs as the same user [@google-chrome-abe-2024]. Microsoft has the same DPAPI substrate; Edge has not adopted the equivalent control.

### The .NET runtime tie-in to AMSI

The PoC's original implementation language is a noteworthy detail. Ronning's README states: ".NET Framework 4.8.1 (changed from 3.5 originally)" [@ronning-github]. The original .NET 3.5 choice was deliberate. The Antimalware Scan Interface (AMSI) [@ms-amsi-portal] scans .NET 4.8+ assemblies before execution; .NET 3.5 predates AMSI's `Amsi*` API surface entirely [@ms-amsi-dotnet48].

<Sidenote>The current GitHub README has changed the framework version to .NET 4.8.1 (likely to ensure the PoC runs out-of-the-box on modern Windows), but the original framing -- and the original threat-model point -- was the AMSI evasion that .NET 3.5 enables. The sibling AMSI post in this series explains why the 3.5 framing matters.</Sidenote>

### Microsoft's response, verbatim

<PullQuote>
"Safety and security are foundational to Microsoft Edge. Access to browser data as described in the reported scenario would require the device to already be compromised. Design choices in this area involve balancing performance, usability, and security, and we continue to review it against evolving threats. Browsers access password data in memory to help users sign in quickly and securely -- this is an expected feature of the application. We recommend users install the latest security updates and antivirus software to help protect against security threats." -- Microsoft spokesperson, via Forbes, May 6, 2026 [@forbes-winder]
</PullQuote>
The statement is technically defensible. The threat model is exactly what the spokesperson says: an attacker who can already execute code as the user on the user's machine. In MSRC's published servicing criteria [@msrc-servicing-criteria], "exploitation requires local code execution" is a recurring boundary line -- the same line MSRC applied to Mimikatz against LSASS in the pre-Credential-Guard era, and that Microsoft eventually crossed by shipping [Credential Guard](/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/). The "by design" framing is consistent with a decade of precedent.

<Aside label="MSRC servicing criteria, in context">
Microsoft's response is internally consistent with a decade of MSRC policy. The "exploitation requires local code execution" framing was applied to Mimikatz against LSASS for years before Credential Guard arrived. It is applied to "give me a debugger and I can read anything" type attacks generally. The position is not improvised, and it is not a special accommodation for Edge. The question this article asks is not "is the position internally consistent" -- it is -- but "what threat model does the position concede." The answer is the same-user local-code-execution threat model. Whether the concession is acceptable depends on whether the user's environment makes same-user LCE rare (a single-user Surface) or routine (a Citrix farm, an AVD pool, a shared family computer).
</Aside>

> **Note:** If you operate a multi-user Windows host -- RDS, AVD, Citrix, a shared lab, a family PC with multiple sign-in accounts -- every Edge session's saved credentials are recoverable by any same-user process during that session, and by an administrator across sessions. The "the device is already compromised" framing is asymmetric: a same-user LCE event on a multi-user host is structurally more common than on a single-user laptop, because there are more identities sharing the same physical machine.

> **Key idea:** Edge does not have a credential-storage vulnerability. Edge has a credential-storage architectural choice. The choice is to spend the entire browser session's worth of plaintext-in-RAM budget on autofill UX latency. The choice is defensible. It is also a precise statement of which threats the Edge product team is and is not defending against.

Microsoft's response is technically defensible. It is also a precise statement of which threat model the Edge product team is and is not defending against. To see why both halves of this article describe the same product, we need to look at the architectural alternatives.

## 8. Competing approaches: where should the secret store live?

Three architectural positions present themselves, as siblings rather than as a generational ladder:

1. **Browser-as-secret-store, decrypt-on-launch** (Edge today). Plaintext-in-RAM window: the entire session. Autofill latency: a memcpy.
2. **Browser-as-secret-store, decrypt-on-autofill** (Chrome, Brave). Plaintext-in-RAM window: the autofill RPC. Autofill latency: one DPAPI unwrap per fill (microseconds).
3. **OS-as-secret-broker** (the design the Windows Credential Manager and DPAPI-NG already implement for native apps). Plaintext never crosses into the browser's process; a higher-privileged broker holds the plaintext at autofill time and the browser receives a handle, not the secret.

<Mermaid caption="Three credential-storage architectures: decrypt-on-launch (Edge), decrypt-on-autofill (Chrome, Brave), and OS-broker (the native Windows Credential Manager pattern). The plaintext-in-RAM window shrinks as the architecture moves right.">
flowchart LR
    subgraph "Decrypt-on-launch (Edge)"
        A1[Disk: DPAPI blob] --> A2[Browser process<br/>plaintext, full session]
        A2 --> A3[Renderer: autofill memcpy]
    end
    subgraph "Decrypt-on-autofill (Chrome / Brave)"
        B1[Disk: DPAPI blob] --> B2[Browser process<br/>plaintext, narrow RPC]
        B2 --> B3[Renderer: autofill]
    end
    subgraph "OS-as-secret-broker"
        C1[Disk: DPAPI-NG blob] --> C2[OS broker process<br/>plaintext only here]
        C2 -.handle.-> C3[Browser receives handle]
        C3 -.autofill via broker.-> C4[Renderer]
    end
</Mermaid>

### Six-axis comparison

| Axis | Decrypt-on-launch (Edge) | Decrypt-on-autofill (Chrome, Brave) | OS-as-broker |
|---|---|---|---|
| Plaintext-in-RAM window | Full session | Autofill RPC (~ms) | Never, in the browser process |
| Autofill latency | Memcpy (nanoseconds) | DPAPI unwrap (~10s of microseconds) | IPC + broker policy check (~ms) |
| Same-user-LCE attack surface | High (ReadProcessMemory exposes all) | Low (must catch the RPC window) | Negligible (no plaintext in the browser) |
| Memory-scraping forensics | Trivial (any same-user dump works) | Hard (must dump during fill) | Impossible (no plaintext to dump) |
| Sync UX with cloud account | Standard | Standard | Standard (broker handles sync) |
| Engineering cost to ship | Already shipped | Already shipped (Chromium baseline) | High (broker IPC, signed code path, extension renegotiation) |

The OS-broker position is not hypothetical. The Windows Credential Manager already provides this property for Windows-app credentials. [WebAuthn and passkeys](/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/) provide it for sites that have adopted the standard. The DPAPI-NG protection descriptors include a `WEBCREDENTIALS=` variant [@ms-learn-dpapi-ng][@ms-learn-dpapi-ng-descriptors]. [Pluton](/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/)-anchored vTPM key unwrap provides a hardware-rooted broker substrate [@ms-learn-pluton]. Credential Guard's LSAISO trustlet is architecturally an isolated secret-broker for LSASS-derived secrets [@ms-learn-credential-guard].

None of these primitives are wired into Edge's saved-passwords path. The engineering cost is non-trivial: the broker needs an IPC contract, the browser needs a signed-and-attested code path that talks to the broker, and the renderer extension API surface needs renegotiation. But the cost is finite, and the alternative is what Google has been shipping in Chrome since 2024 -- Chrome's App-Bound Encryption (see §7) is exactly a step toward the broker model, and Microsoft has the same DPAPI substrate but no equivalent control for Edge [@google-chrome-abe-2024].

### What "by design" means structurally

Microsoft can take the "by design" position because they are not wrong about cryptography. They are right about the bound. No protocol can autofill plaintext into a child renderer without *some* process in the chain holding plaintext at the moment of fill. The architectural question is *which* process and *for how long*.

Edge's answer: "the parent browser process, for the entire session." Chrome and Brave's answer: "the parent browser process, for the autofill RPC." The broker design's answer: "a separate, higher-privileged process, for the autofill RPC, and never the browser at all."

All three are valid points in the design space. The question is not "which is right" -- the answer depends on the user's environment -- but "what should the default be for a 2026 consumer browser." The PSI half of the article shows Microsoft can choose the most demanding default when they want to. The endpoint half shows what default they chose here.

To see why this is a structural property of the problem, not a Microsoft-specific gap, we need to look at the theoretical limits on both sides.

## 9. Theoretical limits

Two lower bounds, in parallel: one cryptographic (the PSI side), one architectural (the endpoint side).

### PSI side: communication and computation lower bounds

The communication lower bound for PSI is folklore, used as the comparison baseline in Pinkas-Schneider-Zohner at USENIX Security 2014 [@psz-2014]. Informally: any PSI protocol must transmit at least $\Omega(\min(n_A, n_B) \cdot \kappa)$ bits, where $\kappa$ is the security parameter. The argument is information-theoretic: the receiver has to learn the intersection, which can have size up to $\min(n_A, n_B)$, and each element identifier needs $\Omega(\kappa)$ bits of representation to avoid collisions.

Silent OT [@silent-ot-2019] meets this lower bound up to polylogarithmic factors in the symmetric balanced setting. HE-PSI in the asymmetric setting gets to $O(n_R \cdot \log n_S)$ ciphertexts via CLR17's partition-and-evaluate construction [@clr-2017], which is sublinear in $n_S$ -- the breakthrough that makes Edge Password Monitor practical.

The computation lower bound on the sender side is $\Omega(n_S)$. The sender must, in the limit, touch each element of its set at least once per query. There is no way around this without trading correctness or privacy. Apple "cheats" by reducing the effective $n_S$: their 15-bit bucket cuts the per-query work to roughly $1.5\text{B} / 2^{15} \approx 46{,}000$ elements. Microsoft's two-byte shard cuts to roughly $5\text{B} / 2^{16} \approx 76{,}000$ elements. The lower bound applies *per shard*, not per total corpus.

The OT-extension lower bound is $\Omega(\kappa)$ base OTs per protocol session, with the bulk of the OT count amortised away by symmetric crypto. KOS15 meets this; Silent OT improves the wire constants further. By 2026, OT extension is essentially solved engineering.

### Endpoint side: the "no plaintext in process" lower bound

The cryptographic side is comfortably tight. The endpoint side is much weirder.For a process $P$ to autofill a credential into a child form, *some component* in the trust chain must hold the plaintext at the moment of fill. There are exactly three possible holders:

1. **$P$ itself.** The Edge design. Plaintext lives in the parent browser process throughout the session.
2. **A child renderer $Q$.** The Chrome / Brave design. Plaintext crosses the parent-renderer boundary for the duration of the autofill RPC and gets zeroed.
3. **A separate higher-privileged broker $B$.** The OS-broker design. Plaintext lives in a sibling process that is harder to dump than the browser (in the limit, a PPL or a Credential-Guard-style trustlet).

No general cryptographic primitive lets a process *use* a plaintext credential without ever *holding* it. The plaintext is a value; the operations on it (paste-into-form, compute-HMAC-with-it, transmit-over-TLS-as-a-bearer-token) all require it in cleartext at some point. This is not a deficiency of any particular cryptosystem. It is the definition of "use."

The plaintext-RAM design Edge ships is not a cryptographic failure. It is a deliberate choice to spend the plaintext-in-RAM budget on UX latency. The escape hatch is *architectural*: a hardware-isolated broker process. Pluton-anchored vTPM key unwrap [@ms-learn-pluton], Credential Guard's LSAISO pattern [@ms-learn-credential-guard], DPAPI-NG with the right protection descriptor [@ms-learn-dpapi-ng-descriptors] -- the OS primitives all exist.

> **Key idea:** There is no cryptographic primitive that lets a process autofill plaintext without holding it. The only escape hatch is an architectural one: a higher-privileged broker. Microsoft already ships the broker primitives -- DPAPI-NG, Credential Guard, Pluton. They are not wired into Chromium.

The aha moment the rest of the article was built to deliver: the Ronning PoC is not a "bug" in any meaningful sense. The structural question is whether Microsoft should ship the architectural primitive -- which they already have, in DPAPI-NG and Credential Guard -- but have not wired into Chromium's password store. The "by design" response is technically true and politically convenient simultaneously. Both are correct readings.

Both lower bounds are tight or near-tight today. The PSI side is essentially solved engineering; the endpoint side is essentially solved policy and unsolved deployment. The open questions are about which side we invest in next.

## 10. Open problems

Four open problems, framed as research directions Microsoft, Apple, and Google have not jointly committed to.

### Open problem 1: post-quantum PSI and OT extension

Every deployed breach-checking protocol today rests on assumptions [Shor's algorithm](/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati/) breaks. The OPRFs in Apple PSM and Google Password Checkup rely on discrete log over elliptic curves; the HE-PSI in Edge Password Monitor relies on BFV-on-classical-parameters; Paillier (historic, FNP04) relies on integer factorisation. Harvest-now-decrypt-later exposure on durable transcripts is the near-term migration question: an adversary capturing PSI transcripts today and storing them until a cryptographically relevant quantum computer arrives could, in principle, reconstruct the queries.

Lattice-based OT extension exists at currently-secure parameters, at roughly $10\times$ the communication of IKNP per OT in early prototypes. Whether the breach-checking deployments at Microsoft, Apple, and Google migrate on the same timeline as the rest of TLS (the IETF post-quantum-handshake transition) is an open coordination problem.

### Open problem 2: multi-party breach corpora

No production deployment of a $>2$-party breach-checking service exists. HIBP, Google, Apple, and Microsoft each hold corpora that overlap but contain unique breaches. Consolidating them privately -- so a query gets the union of all four corpora's match metadata without any one provider learning more than their own corpus contributed -- would meaningfully improve detection.

The academic literature on multi-party PSI is substantial and growing, but the engineering and the governance work has not been done. Each provider has a different commercial relationship with the breach dataset, a different legal posture, and a different operational interest in their corpus being canonical. The cryptographic primitive is the easy part.

### Open problem 3: sub-linear sender-side amortisation

The $\Omega(n_S)$ sender-side computation lower bound is *per query*. For a service serving billions of queries against a static $S_S$, can per-query cost be amortised across queries via a preprocessing step the sender pays once?

Cong et al. 2021 [@cong-2021] reduces constants substantially and pushes the practical envelope. Sub-linear *asymptotic* sender-side cost is open. The information-theoretic barrier is real -- the sender must touch any element that could be in the receiver's query -- but the *expected* cost over many queries against a static corpus admits a more aggressive analysis under the right access patterns.

### Open problem 4: hardware-broker browser secret stores

The endpoint architectural problem. Migrate Edge, Chrome, and Brave from "process-RAM plaintext" to "OS-broker (plaintext never crosses into the browser)" using DPAPI-NG with a broker-PPL protection descriptor or a Credential Guard-style trustlet.

WebAuthn and passkeys offer this property already -- the platform authenticator holds the private key, and the browser receives signed assertions without ever seeing the secret. But passkeys require per-site enrollment that traditional username-password sites have not adopted at scale; the long tail of legacy login forms will remain on saved-passwords-as-strings for years.

The Windows Credential Manager offers the broker property for *Windows-app* credentials -- but it is not wired into Chromium for *browser* credentials. The engineering work is real; the cryptographic work is essentially trivial. Whether and when Microsoft, Google, or Brave commit to it is the question.

| Open problem | What's been tried | Current best | Why it matters |
|---|---|---|---|
| Post-quantum PSI | Lattice-based OT, ring-LWE OPRFs | Prototype-grade; 10x classical at ~secure parameters | Harvest-now-decrypt-later on PSI transcripts |
| Multi-party breach corpora | Multi-party PSI literature (e.g., Kolesnikov et al. CCS 2017) | Academic constructions; no production deploy | Each provider's corpus has unique recall |
| Sub-linear sender cost | Cong et al. 2021 constants reduction | Linear $\Omega(n_S)$ per query | $5 \times 10^9$ corpus, billions of queries |
| Hardware-broker secret stores | WebAuthn / passkeys; DPAPI-NG, Credential Guard | Standards exist; wiring into browsers is missing | The Ronning PoC threat model |

<Spoiler kind="hint" label="A simple Chrome App-Bound Encryption check on your machine">
Open Chromium's process tree on Windows (Task Manager: Details, group by Path) and look for the `Google Chrome.exe` (or `msedge.exe`) process running with the `--type=` argument absent -- that's the parent. App-Bound Encryption binds the DPAPI unwrap to that exact parent process's signature, so a same-user attacker masquerading as Chrome cannot ask DPAPI to unwrap Chrome's data even with the right user identity. The architectural primitive is sitting in Chrome's source tree as of July 2024 [@google-chrome-abe-2024]; the equivalent control for Edge's password store has not shipped.
</Spoiler>

These four open problems share a structure: each would require coordination across multiple vendors and across the cryptography / platform / browser boundary. None is research-blocked. All are governance-blocked.

## 11. Practical guide

What should you do this week?

### Users

If your Edge browser is your password manager and you are on a single-user laptop you control end-to-end, the Ronning PoC's threat model is "an attacker who can run code as you on your own machine." If that happens, the attacker is already in a strong position regardless of how Edge holds passwords -- they can keylog the next login, screenshot anything you autofill, or install a malicious browser extension. The marginal risk of the plaintext-RAM design on a single-user laptop is real but bounded.

If you share a Windows host -- a family PC with multiple accounts, a small-business workstation several employees sign into, a domain-joined laptop on which IT has administrative access -- the calculus changes. Any same-user process can read your Edge plaintext during your session. Any administrator can read it across sessions (the PoC's "Administrator can access other users' Edge processes" mode). The case for moving saved credentials out of Edge into a dedicated password manager (1Password, Bitwarden, KeePass) is structurally stronger here.

A dedicated password manager usually still keeps plaintext in *its* own process RAM during autofill -- this is the §9 lower bound asserting itself. The difference is the size of the plaintext-in-RAM window: dedicated password managers tend to require an explicit unlock and re-lock after a configurable idle period. Edge's window is the entire browser session.

> **Note:** On a multi-user Windows machine -- RDS, AVD, Citrix, a family computer with separate accounts -- disable Edge's password manager via the `PasswordManagerEnabled` group policy and route users to an out-of-process credential broker (1Password's CLI integration, Bitwarden's desktop helper, or the platform Credential Manager).

### Windows admins

The two relevant Edge enterprise policies are documented on Microsoft Learn:

- **`PasswordManagerEnabled`** [@ms-learn-passwordmanagerenabled] -- turns Edge's saved-passwords feature on or off entirely. On a multi-user host with sensitive data, the right value is `0`.
- **`PasswordMonitorAllowed`** [@ms-learn-edge-pm] -- controls whether Password Monitor's breach-checking PSI runs at all. The default is "user-controlled"; in a managed enterprise, you may want to mandatorily enable it (independent of whether the password manager itself is enabled, because Password Monitor can check passwords you type into login forms, not just ones you have saved).

For RDS, AVD, and Citrix environments specifically, the threat model is structurally worse than a single-user laptop. Multiple users share a single Windows host. Their Edge profiles are isolated by Windows ACLs but their *processes* are not isolated against an administrator. The PoC's "Administrator privileges can access other users' Edge processes" mode is exactly the privilege available to a session-host administrator who has been compromised, or to a malicious tenant who escalates locally.

<Aside label="For RDS, Citrix, and AVD admins">
On a shared-tenant Windows host, the question is not whether same-user LCE will occur -- it is structurally more common than on a single-user laptop -- but how containable it is when it does. Saved browser credentials are an outsized lever for an attacker who pivots laterally: a single compromised user account on a session-host can yield every saved corporate credential for that user, and an administrator escalation can yield every saved credential for every user on the host. The hardening recommendation is to disable browser-based password management entirely (`PasswordManagerEnabled=0`) on session-host images, document an approved credential broker for your environment (Windows Credential Manager for native apps; an enterprise password manager with broker integration for browsers), and audit Edge profile directories on session-host images for stale `Login Data` SQLite files left over from earlier deployments.
</Aside>

### Developers

If you ship a component that handles credentials, the design lesson from §9 is not "never hold plaintext" -- you cannot avoid it without an OS-level broker -- but "minimise the plaintext-in-RAM window."

The Chrome App-Bound Encryption pattern from July 2024 [@google-chrome-abe-2024] is a template: bind your at-rest key unwrap to a verified process identity so an attacker who exfiltrates your wrapped data cannot trivially unwrap it from a different process. If you must hold plaintext in the parent process for the lifetime of the session (the Edge design), make the trade explicit in the threat model documentation and ensure operations consuming the plaintext are auditable.

If you can architecturally afford a broker, do it. The IPC cost is real (low-microsecond per call) but small compared to the operational reduction in incident severity. WebAuthn / passkeys are the long-term destination for credentials; the broker pattern is the short-term destination for everything else.

## 12. Frequently asked questions

<FAQ title="Frequently asked questions about Edge's two password cryptographies">

<FAQItem question="Doesn't DPAPI protect the saved passwords?">
Yes, at rest on disk. DPAPI wraps the symmetric key that encrypts Edge's `Login Data` SQLite file under a key chain rooted in the user's password. When the user is logged out (or the machine is powered off), the on-disk blob is opaque to anyone who does not have the user's DPAPI credentials. The protection ends the moment Edge unwraps the DPAPI blob into process memory, which happens during browser launch or the first password-feature activation. Once unwrapped, the credentials sit in `msedge.exe`'s heap until the process exits, and `ReadProcessMemory` from any same-user process reads them as plaintext. DPAPI is an at-rest control, not an in-memory one.
</FAQItem>

<FAQItem question="Couldn't Protected Process Light (PPL) or RunAsPPL fix this?">
Partially. If Edge ran as a protected process at an appropriate signature level, only an antimalware-PPL-elevated process could open it for `ReadProcessMemory`, which would substantially raise the bar against a same-user attacker. Browser-process PPL has implications for every loaded DLL (each must be signed at or above the host's PPL level) and every extension API the renderer expects to call. Chrome and Brave have not adopted PPL for the browser process either. Microsoft has the option; they have not used it. PPL would address the same-user-LCE concern but not the administrator-across-sessions concern.
</FAQItem>

<FAQItem question="Doesn't Credential Guard cover browser credentials?">
No. Credential Guard isolates LSASS-derived secrets (NTLM hashes, Kerberos tickets, cached credentials) into the LSAISO trustlet running under Virtualization-Based Security, which is unreachable from the normal-world kernel let alone normal-world user-mode processes. It does not cover browser-owned secrets. Saved Edge credentials live in `msedge.exe`'s heap, not in LSASS, and Credential Guard does not extend protection to arbitrary user-mode application secret stores.
</FAQItem>

<FAQItem question="Is k-anonymity 'real' PSI?">
No, in the strict cryptographic sense. K-anonymity leaks the bucket index by design -- the server learns a 20-bit (HIBP), 15-bit (Apple), or 16-bit (Edge shard) prefix of the hash being queried, which carries non-trivial information about which password the client is asking about. A proper PSI protocol leaks nothing beyond the intersection itself. The argument for k-anonymity is that the bucket is large enough -- on the order of hundreds to thousands of possible hashes per bucket -- that the residual information is not actionable for the threats most users face. It is a precise statement of "a small leak in exchange for vast practical efficiency"; the cost is documented and bounded, and that is why every deployed service uses some variant of it. But it is not zero-leak.
</FAQItem>

<FAQItem question="Why didn't Microsoft use SGX like Signal?">
Threat-model differences and SGX's well-documented side-channel literature (see the §6 Aside for the four-attack chronology). For a breach-checking service whose threat model is "the corpus must not leak from inside Microsoft," HE-PSI offers a clean cryptographic argument that does not depend on any TEE's silicon-level security claims. The MSR Cryptography and Privacy group had been publishing the relevant HE-PSI papers since 2017 and shipping the SEAL library publicly since 2018, so the substrate was in-house. The cost is real (orders of magnitude more compute than an SGX enclave) but tractable at the sharded scale Edge Password Monitor operates at. The trade is reasonable, and it is documented in the MSR blog [@msr-password-monitor-2021].
</FAQItem>

<FAQItem question="Why was the PoC originally in .NET 3.5?">
AMSI evasion. The Antimalware Scan Interface scans .NET 4.8+ assemblies before execution; .NET 3.5 predates AMSI's API surface entirely. A C# program targeting .NET 3.5 will run on any modern Windows with the legacy framework installed (which is most of them, because .NET 3.5 is shipped as a Windows feature) and will not be subject to the same managed-runtime scanning that 4.8+ assemblies are. The current GitHub README says ".NET Framework 4.8.1 (changed from 3.5 originally)" [@ronning-github] -- likely to ease running on a clean modern Windows -- but the original .NET 3.5 framing was the deliberate AMSI-evasion choice. The sibling AMSI post in this series explains the scanning architecture in detail.
</FAQItem>

<FAQItem question="Does Chrome or Brave have the same problem?">
Per the researcher's claim and the PCWorld relay, no -- see §7 for the decrypt-on-autofill contrast and Chrome's App-Bound Encryption hardening [@pcworld-pippig-2026][@google-chrome-abe-2024]. The observable difference is direct: a `ReadProcessMemory`-based scrape of an idle Chrome process returns markedly less than the same scrape of an idle Edge process.
</FAQItem>

<FAQItem question="Is 'by design' a reasonable response?">
Yes (with caveats). See §7's MSRC-servicing-criteria Aside for the full framing [@msrc-servicing-criteria]: the short answer is that the position is internally consistent with a decade of MSRC policy and with the §9 architectural lower bound, but it concedes the same-user LCE threat model and shifts defence onto endpoint controls (antivirus, application-control policies, PPL on antimalware processes only) that may not exist on the user's machine. The architectural primitive that would close the gap (an OS broker) exists on Windows but is not wired into Chromium.
</FAQItem>

</FAQ>

The PSI on the wire is real. The plaintext-RAM concession is also real. Both are statements about which threat model the Edge product team is defending against, and the apparent contradiction in the title disappears once you read them as such.

<StudyGuide slug="edges-two-password-cryptographies" keyTerms={[
  { term: "Private Set Intersection (PSI)", definition: "A two-party cryptographic protocol that computes the intersection of two sets without revealing anything else." },
  { term: "Oblivious Transfer (OT)", definition: "A primitive in which a sender holds two messages, a receiver picks one, and neither learns the other's choice or the unsent message." },
  { term: "OT extension", definition: "Two-phase protocol that turns kappa public-key OTs into m symmetric-cost OTs, collapsing per-OT cost by orders of magnitude." },
  { term: "Oblivious Pseudorandom Function (OPRF)", definition: "Two-party protocol where the receiver learns F_k(x) without revealing x to the sender or learning k." },
  { term: "Pseudorandom Correlation Generator (PCG)", definition: "Primitive that locally expands a short shared seed into long correlated random strings, used to make Silent OT communication-free post-seed." },
  { term: "Homomorphic encryption (HE / SWHE / FHE)", definition: "Encryption supporting operations on ciphertexts that decrypt to operations on plaintexts; SWHE is bounded depth, FHE is unbounded via bootstrapping." },
  { term: "Cuckoo hashing", definition: "Hashing with k candidate bins per element and displacement, achieving O(1) lookup at high load -- the partitioning trick under CLR17 and CHLR18." },
  { term: "k-anonymity (password monitoring)", definition: "A precise small information leak: each query is consistent with at least k possible passwords sharing the bucket prefix." },
  { term: "Data Protection API (DPAPI)", definition: "Windows facility that wraps blobs under user-derived keys; an at-rest control, not an in-process-memory control." },
  { term: "App-Bound Encryption (Chrome, July 2024)", definition: "Chrome control that binds DPAPI unwrap of saved data to the verified Chrome process identity, blocking same-user impersonation attacks." }
]} questions={[
  { q: "Why does the DH meet-in-the-middle PSI protocol fail at breach-checking scale?", a: "It costs O(|S_B|) group exponentiations per query, leaks set cardinality on both sides, and provides no labeled-PSI variant." },
  { q: "What three engineering moves let CLR17 revive FNP04's polynomial-roots PSI?", a: "(1) BFV SWHE replaces Paillier for slot-packed homomorphic evaluation, (2) Cuckoo hash partitioning splits the giant polynomial into per-bin polynomials, (3) partition-and-evaluate bounds server work to O(|S_S| log |S_R|)." },
  { q: "What does the OPRF preprocessing layer add to Edge Password Monitor's bare HE-PSI?", a: "It prevents a malicious client from brute-forcing the server's corpus offline; the client cannot evaluate F_k(x) without server interaction." },
  { q: "What does the EdgeSavedPasswordsDumper PoC require to read Edge passwords as cleartext?", a: "Same-user OpenProcess + ReadProcessMemory on the parent msedge.exe. No kernel exploit, no admin (against same-user processes), no DPAPI bypass." },
  { q: "Why is 'no cryptographic primitive closes the plaintext-RAM gap' the structural claim of section 9?", a: "Using a plaintext value requires holding it; the only escape hatch is moving the holder to a higher-privileged broker process, which is an architectural choice, not a cryptographic one." }
]} />

```
---WRITER METRICS---
Word count: 12625
Citations: 104 inline `@id`-style references across 53 unique sources (frontmatter expanded with PSZ14, four SGX disclosure pages, MSRC servicing criteria, three Microsoft Learn OS-broker primitives, Paillier 1999, Pagh-Rodler 2001, AMSI .NET 4.8, and Wikipedia TLS in Stage 11 iter-1 resolution)
Mermaid diagrams: 6
Definitions: 9
Sidenotes: 8
FAQ questions: 8
---END WRITER METRICS---
```
