[{"data":1,"prerenderedAt":578},["ShallowReactive",2],{"blog-posts":3},[4,114,253,436,448,553,565],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"heading":11,"date":12,"minutes":13,"series":14,"part":15,"parts":15,"summary":16,"short":17,"body":18,"_type":108,"_id":109,"_source":110,"_file":111,"_stem":112,"_extension":113},"\u002Fblog\u002Fextension-ceiling-3-the-incognito-bypass","blog",false,"","The extension ceiling, part 3: the incognito bypass","Part 1 needed a missing API. Part 2 needed a signed-in account. This one needs Ctrl+Shift+N. Open an incognito window and every extension the user has not individually allowed in is gone: no content scripts, no webRequest listeners, no DLP.","The incognito bypass","2026-05-28",5,"The extension ceiling",3,"Every extension-based DLP I tested loses sight of the user the moment an incognito window opens. The mechanism, and why policy can't fully close it.","Extensions are off in incognito unless the user opts each one in, and no enterprise policy flips that switch for them. Every extension-based control on the machine is one keyboard shortcut from blind.",{"type":19,"children":20,"toc":102},"root",[21,28,35,40,45,51,81,86,92,97],{"type":22,"tag":23,"props":24,"children":25},"element","p",{},[26],{"type":27,"value":10},"text",{"type":22,"tag":29,"props":30,"children":32},"h2",{"id":31},"the-mechanism",[33],{"type":27,"value":34},"The mechanism",{"type":22,"tag":23,"props":36,"children":37},{},[38],{"type":27,"value":39},"Extensions are disabled in incognito by default. The opt-in is a per-extension toggle, Allow in Incognito on the chrome:\u002F\u002Fextensions page, and it belongs to the user. Force-installing the extension by policy does not flip it. Pinning the version, blocking uninstall, hiding the toolbar icon, none of that flips it either. Chrome's position is the same one from part 1, applied consistently: incognito is a promise made to the user, and silently installing a watcher inside it would break the promise, even for an administrator.",{"type":22,"tag":23,"props":41,"children":42},{},[43],{"type":27,"value":44},"So the coverage of your security product is a user preference. That sentence is worth sitting with during a vendor evaluation, because every extension-based DLP I tested behaves exactly this way, and none of the datasheets mention it.",{"type":22,"tag":29,"props":46,"children":48},{"id":47},"the-obvious-fix-and-what-lines-up-behind-it",[49],{"type":27,"value":50},"The obvious fix, and what lines up behind it",{"type":22,"tag":23,"props":52,"children":53},{},[54,56,63,65,71,73,79],{"type":27,"value":55},"The standard answer is ",{"type":22,"tag":57,"props":58,"children":60},"code",{"className":59},[],[61],{"type":27,"value":62},"IncognitoModeAvailability",{"type":27,"value":64}," set to disabled, kill the feature entirely. It works, and then the gaps queue up behind it. Guest mode needs ",{"type":22,"tag":57,"props":66,"children":68},{"className":67},[],[69],{"type":27,"value":70},"BrowserGuestModeEnabled",{"type":27,"value":72}," set to false, it is a fresh profile with no extensions. Adding new profiles needs ",{"type":22,"tag":57,"props":74,"children":76},{"className":75},[],[77],{"type":27,"value":78},"BrowserAddPersonEnabled",{"type":27,"value":80}," set to false, same reason. And once this browser is fully sealed, the user opens Edge, or Firefox, or the Chrome they unzipped into their home directory, none of which carry your extension at all.",{"type":22,"tag":23,"props":82,"children":83},{},[84],{"type":27,"value":85},"Each closure is real and worth doing. The sum of them is also an admission: the enforcement boundary was never the extension. It was the inventory of browsers you can keep people inside, which is an endpoint problem, not a browser problem, and the extension was never going to solve it.",{"type":22,"tag":29,"props":87,"children":89},{"id":88},"what-it-looks-like-when-you-own-the-browser",[90],{"type":27,"value":91},"What it looks like when you own the browser",{"type":22,"tag":23,"props":93,"children":94},{},[95],{"type":27,"value":96},"A fork does not have an incognito problem, it has an incognito decision. The private window is your code. Policy can state plainly what a corporate session allows: incognito exists and DLP stays active in it, disclosed in the window itself. Or incognito is unavailable for managed profiles. Or it works untouched for personal browsing and corporate sites simply refuse to load in it. Any of those is a defensible design. The difference is that the choice is made by policy and disclosed to the user, instead of being made by a toggle the user controls and the admin cannot even see.",{"type":22,"tag":23,"props":98,"children":99},{},[100],{"type":27,"value":101},"That closes the series. The ceiling is not one missing API, it is a pattern. Pixels in part 1, the sync channel in part 2, the private window here. Extensions are guests, and Chrome is a good host that protects its users from its guests. When the requirement needs the host's keys, the requirement is a browser.",{"title":8,"searchDepth":103,"depth":103,"links":104},2,[105,106,107],{"id":31,"depth":103,"text":34},{"id":47,"depth":103,"text":50},{"id":88,"depth":103,"text":91},"markdown","content:blog:extension-ceiling-3-the-incognito-bypass.md","content","blog\u002Fextension-ceiling-3-the-incognito-bypass.md","blog\u002Fextension-ceiling-3-the-incognito-bypass","md",{"_path":115,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":116,"description":117,"heading":118,"date":119,"minutes":120,"series":14,"part":103,"parts":15,"summary":121,"short":122,"body":123,"_type":108,"_id":250,"_source":110,"_file":251,"_stem":252,"_extension":113},"\u002Fblog\u002Fextension-ceiling-2-chrome-sync-and-mdm-scoping","The extension ceiling, part 2: Chrome sync and MDM scoping","Part 1 was about a capability extensions visibly lack. This one is quieter. Nothing fails, nothing prompts, nobody notices anything. Chrome sync just does its job, and its job is moving browser state off the machine.","Chrome sync and MDM scoping","2026-04-09",6,"Chrome sync will happily carry corporate state into personal profiles. What the MDM scoping rules actually cover, item by item.","Chrome sync moves passwords, history, and open tabs to whatever Google account is signed in, corporate or not. The policies that scope it manage the profile, not the person, and an extension cannot see the channel at all.",{"type":19,"children":124,"toc":244},[125,129,135,140,145,151,156,205,217,223,228,234,239],{"type":22,"tag":23,"props":126,"children":127},{},[128],{"type":27,"value":117},{"type":22,"tag":29,"props":130,"children":132},{"id":131},"what-sync-actually-carries",[133],{"type":27,"value":134},"What sync actually carries",{"type":22,"tag":23,"props":136,"children":137},{},[138],{"type":27,"value":139},"Sync is not one stream, it is a set of typed channels: bookmarks, history, open tabs, passwords, autofill including addresses and payment cards, extensions, settings, and a handful of smaller types. Sign into Chrome with any Google account and every enabled type starts flowing to that account. Encrypted to Google by default, end to end only if the user sets a passphrase, which almost nobody does.",{"type":22,"tag":23,"props":141,"children":142},{},[143],{"type":27,"value":144},"Now picture the standard mixed setup: a corporate machine, a managed work profile, and an employee who signs a personal Gmail into that profile, or just uses the personal profile sitting one click away in the profile switcher. The passwords saved against internal apps, the history of every internal hostname, the open tabs with ticket numbers in their titles, all of it syncs up to the personal account and back down to a personal laptop at home. No upload event, no file, nothing a DLP rule would classify as exfiltration. The traffic is TLS to google.com, which every allowlist on earth permits.",{"type":22,"tag":29,"props":146,"children":148},{"id":147},"the-policies-item-by-item",[149],{"type":27,"value":150},"The policies, item by item",{"type":22,"tag":23,"props":152,"children":153},{},[154],{"type":27,"value":155},"Chrome Enterprise has real controls here, and they are narrower than people assume.",{"type":22,"tag":157,"props":158,"children":159},"ul",{},[160,172,183,194],{"type":22,"tag":161,"props":162,"children":163},"li",{},[164,170],{"type":22,"tag":57,"props":165,"children":167},{"className":166},[],[168],{"type":27,"value":169},"SyncDisabled",{"type":27,"value":171}," kills sync for the profiles it reaches. Total and blunt, and users notice their bookmarks stopped following them.",{"type":22,"tag":161,"props":173,"children":174},{},[175,181],{"type":22,"tag":57,"props":176,"children":178},{"className":177},[],[179],{"type":27,"value":180},"SyncTypesListDisabled",{"type":27,"value":182}," turns off individual types. Most teams disable passwords and autofill, keep bookmarks, and call it scoped.",{"type":22,"tag":161,"props":184,"children":185},{},[186,192],{"type":22,"tag":57,"props":187,"children":189},{"className":188},[],[190],{"type":27,"value":191},"BrowserSignin",{"type":27,"value":193}," can block browser sign-in entirely, or force it so the profile is always managed.",{"type":22,"tag":161,"props":195,"children":196},{},[197,203],{"type":22,"tag":57,"props":198,"children":200},{"className":199},[],[201],{"type":27,"value":202},"RestrictSigninToPattern",{"type":27,"value":204}," is the precise one: a pattern over which accounts may sign in, usually anchored to the corporate domain.",{"type":22,"tag":23,"props":206,"children":207},{},[208,210,215],{"type":27,"value":209},"The catch is scope. A policy attaches to whatever is managed: the device, the browser install, or the account. Applied at the machine or browser level, ",{"type":22,"tag":57,"props":211,"children":213},{"className":212},[],[214],{"type":27,"value":202},{"type":27,"value":216}," does reach every profile on that install, and that is the strict setup. Applied through the managed account, it governs that account's profile and says nothing about the personal profile next to it. BYOD, unmanaged home installs of the same browser, and half-enrolled fleets fall through exactly this gap. The data follows the account, and the account is the one thing MDM does not own.",{"type":22,"tag":29,"props":218,"children":220},{"id":219},"where-the-extension-sits",[221],{"type":27,"value":222},"Where the extension sits",{"type":22,"tag":23,"props":224,"children":225},{},[226],{"type":27,"value":227},"Below all of it. There is no extensions API for sync. An extension can read bookmarks and history, but it cannot tell synced from local, cannot see the sync queue, and cannot observe a personal account attaching itself to the profile. Extension-based DLP does not have a degraded view of this channel. It has none.",{"type":22,"tag":29,"props":229,"children":231},{"id":230},"closing-it-for-real",[232],{"type":27,"value":233},"Closing it for real",{"type":22,"tag":23,"props":235,"children":236},{},[237],{"type":27,"value":238},"Strict policy gets you most of the way if you are willing to pay for it: force managed sign-in, restrict the pattern at the browser level, disable secondary profiles, accept the tickets. In our fork we went one layer further, because we could reach the layer policy cannot: the sync client itself. The browser knows which profile is corporate, so it can refuse to start typed channels for the wrong account, log what would have left, and leave personal Chrome on the same machine alone. That is not cleverness, it is just owning the code that runs.",{"type":22,"tag":23,"props":240,"children":241},{},[242],{"type":27,"value":243},"Part 3 needs no account and no API gap at all, only a keyboard shortcut: the incognito window.",{"title":8,"searchDepth":103,"depth":103,"links":245},[246,247,248,249],{"id":131,"depth":103,"text":134},{"id":147,"depth":103,"text":150},{"id":219,"depth":103,"text":222},{"id":230,"depth":103,"text":233},"content:blog:extension-ceiling-2-chrome-sync-and-mdm-scoping.md","blog\u002Fextension-ceiling-2-chrome-sync-and-mdm-scoping.md","blog\u002Fextension-ceiling-2-chrome-sync-and-mdm-scoping",{"_path":254,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":255,"description":256,"heading":257,"date":258,"minutes":259,"series":14,"part":260,"parts":15,"summary":261,"short":262,"body":263,"_type":108,"_id":433,"_source":110,"_file":434,"_stem":435,"_extension":113},"\u002Fblog\u002Fextension-ceiling-1-mandatory-screen-recording","The extension ceiling, part 1: mandatory screen recording","A buyer asks this question in every enterprise browser evaluation: can we record the screen for high-risk sessions. Not screenshots on a violation, recording, mandatory, for contractors and offshore teams. If your security tooling lives in an extension, the honest answer is no, and the dishonest answers are worth understanding.","Mandatory screen recording","2026-02-17",7,1,"If your security tool needs to watch the screen to do its job, you have already left the extension model. The mechanics of why.","Extensions cannot record the screen without per-session user consent. The workarounds are partial reconstructions, and managed policy cannot consent on the user's behalf. If recording is mandatory, the requirement is a browser, not an extension.",{"type":19,"children":264,"toc":427},[265,269,275,296,301,307,312,392,398,411,417,422],{"type":22,"tag":23,"props":266,"children":267},{},[268],{"type":27,"value":256},{"type":22,"tag":29,"props":270,"children":272},{"id":271},"what-the-extension-apis-actually-allow",[273],{"type":27,"value":274},"What the extension APIs actually allow",{"type":22,"tag":23,"props":276,"children":277},{},[278,280,286,288,294],{"type":27,"value":279},"Chrome gives an extension two routes to pixels. ",{"type":22,"tag":57,"props":281,"children":283},{"className":282},[],[284],{"type":27,"value":285},"chrome.desktopCapture",{"type":27,"value":287}," shows the user a picker and waits for consent, every session. ",{"type":22,"tag":57,"props":289,"children":291},{"className":290},[],[292],{"type":27,"value":293},"chrome.tabCapture",{"type":27,"value":295}," needs the user to invoke the extension first, and it sees one tab, not the desktop. Both die with the service worker in Manifest V3, so \"always on\" means keeping a worker alive that Chrome is actively trying to put to sleep.",{"type":22,"tag":23,"props":297,"children":298},{},[299],{"type":27,"value":300},"There is no silent path. That is not an oversight, it is the contract. An extension is a guest in someone else's browser, and Chrome treats pixels as the most user-owned resource there is.",{"type":22,"tag":29,"props":302,"children":304},{"id":303},"what-vendors-ship-instead",[305],{"type":27,"value":306},"What vendors ship instead",{"type":22,"tag":23,"props":308,"children":309},{},[310],{"type":27,"value":311},"The workaround industry is real. DOM snapshots streamed on a timer. MutationObserver diffs reassembled server-side into something that plays back like video. Canvas readback where the page allows it. It demos well. Then you deploy it and find what it misses: cross-origin iframes, native file dialogs, the address bar, PDFs in the built-in viewer, every other app on the desktop, and the user who drags the tab into a new window.",{"type":22,"tag":313,"props":314,"children":315},"table",{},[316,335],{"type":22,"tag":317,"props":318,"children":319},"thead",{},[320],{"type":22,"tag":321,"props":322,"children":323},"tr",{},[324,330],{"type":22,"tag":325,"props":326,"children":327},"th",{},[328],{"type":27,"value":329},"The policy asks for",{"type":22,"tag":325,"props":331,"children":332},{},[333],{"type":27,"value":334},"An extension can see",{"type":22,"tag":336,"props":337,"children":338},"tbody",{},[339,353,366,379],{"type":22,"tag":321,"props":340,"children":341},{},[342,348],{"type":22,"tag":343,"props":344,"children":345},"td",{},[346],{"type":27,"value":347},"The whole desktop",{"type":22,"tag":343,"props":349,"children":350},{},[351],{"type":27,"value":352},"One tab, with consent, per session",{"type":22,"tag":321,"props":354,"children":355},{},[356,361],{"type":22,"tag":343,"props":357,"children":358},{},[359],{"type":27,"value":360},"Native dialogs and pickers",{"type":22,"tag":343,"props":362,"children":363},{},[364],{"type":27,"value":365},"Nothing",{"type":22,"tag":321,"props":367,"children":368},{},[369,374],{"type":22,"tag":343,"props":370,"children":371},{},[372],{"type":27,"value":373},"Cross-origin iframes",{"type":22,"tag":343,"props":375,"children":376},{},[377],{"type":27,"value":378},"A hole in the snapshot",{"type":22,"tag":321,"props":380,"children":381},{},[382,387],{"type":22,"tag":343,"props":383,"children":384},{},[385],{"type":27,"value":386},"Recording that survives a restart",{"type":22,"tag":343,"props":388,"children":389},{},[390],{"type":27,"value":391},"A service worker Chrome wants to sleep",{"type":22,"tag":29,"props":393,"children":395},{"id":394},"cant-policy-just-force-it",[396],{"type":27,"value":397},"Can't policy just force it?",{"type":22,"tag":23,"props":399,"children":400},{},[401,403,409],{"type":27,"value":402},"Admins ask the reasonable next question: we manage these machines, can't policy grant the permission. Policy can force-install the extension, pin its version, hide the uninstall button. It cannot grant capture consent on the user's behalf. The picker is rendered by the browser, above the extension's reach, deliberately. There are narrow loosenings, kiosk modes, allowlisted origins for ",{"type":22,"tag":57,"props":404,"children":406},{"className":405},[],[407],{"type":27,"value":408},"getDisplayMedia",{"type":27,"value":410},", and none of them add up to a silent, always-on recorder driven by an extension.",{"type":22,"tag":29,"props":412,"children":414},{"id":413},"what-it-actually-takes",[415],{"type":27,"value":416},"What it actually takes",{"type":22,"tag":23,"props":418,"children":419},{},[420],{"type":27,"value":421},"Recording is a compositor-level capability. To make it a policy decision instead of a user decision, you have to own the compositor, which means owning the browser. On a Chromium fork the capture pipeline is yours: gated by enterprise policy, scoped to the profiles and sites the policy names, with a consent surface you design and disclose honestly. That is the line between an extension product and a browser product, and recording is usually the first requirement that makes a buyer cross it.",{"type":22,"tag":23,"props":423,"children":424},{},[425],{"type":27,"value":426},"None of this is extension-bashing. For most policy an extension is the right tool, cheaper to deploy and easier to trust. The ceiling is real for the rest. Part 2 is Chrome sync and MDM scoping, where the failure is quieter and the data walks out the front door.",{"title":8,"searchDepth":103,"depth":103,"links":428},[429,430,431,432],{"id":271,"depth":103,"text":274},{"id":303,"depth":103,"text":306},{"id":394,"depth":103,"text":397},{"id":413,"depth":103,"text":416},"content:blog:extension-ceiling-1-mandatory-screen-recording.md","blog\u002Fextension-ceiling-1-mandatory-screen-recording.md","blog\u002Fextension-ceiling-1-mandatory-screen-recording",{"_path":437,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":438,"description":8,"heading":438,"date":439,"minutes":13,"summary":440,"body":441,"_type":108,"_id":445,"_source":110,"_file":446,"_stem":447,"_extension":113},"\u002Fblog\u002Fwhat-enterprise-browser-productivity-numbers-really-mean","What enterprise browser productivity numbers really mean","2025-12-03","Vendors quote hours saved per user per week. How those numbers get made, and which ones survive contact with a real deployment.",{"type":19,"children":442,"toc":443},[],{"title":8,"searchDepth":103,"depth":103,"links":444},[],"content:blog:what-enterprise-browser-productivity-numbers-really-mean.md","blog\u002Fwhat-enterprise-browser-productivity-numbers-really-mean.md","blog\u002Fwhat-enterprise-browser-productivity-numbers-really-mean",{"_path":449,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":450,"description":451,"heading":452,"date":453,"minutes":120,"summary":454,"short":455,"body":456,"_type":108,"_id":550,"_source":110,"_file":551,"_stem":552,"_extension":113},"\u002Fblog\u002Fgo-vs-rust-for-proxy-workloads","Go vs Rust for proxy workloads: the choice and why","When we started the gateway under Ulaa, the language question was real, not a forum debate. A secure web gateway terminates TLS, inspects, re-encrypts, and forwards, for every user, all day. Tail latency is the product. We prototyped the data plane in both Go and Rust and pushed real traffic through each before committing.","Go vs Rust for proxy workloads","2025-09-24","We pushed serious TLS traffic through both. The decision came down to GC pauses you can budget for versus lifetimes you pay for daily.","We prototyped the gateway data plane in both. Rust won the benchmarks by less than expected, Go won the product, and the difference was whose costs show up on whose schedule.",{"type":19,"children":457,"toc":544},[458,462,468,473,478,484,489,502,508,513,518,523,528,534,539],{"type":22,"tag":23,"props":459,"children":460},{},[461],{"type":27,"value":451},{"type":22,"tag":29,"props":463,"children":465},{"id":464},"what-a-proxy-actually-stresses",[466],{"type":27,"value":467},"What a proxy actually stresses",{"type":22,"tag":23,"props":469,"children":470},{},[471],{"type":27,"value":472},"A forward proxy is a memory churn machine: accept, handshake, parse, copy between two sockets, tear down, thousands of times a second. Three costs dominate. Allocation pressure from connection buffers. Handshake CPU. And whatever your runtime does at the worst possible moment.",{"type":22,"tag":23,"props":474,"children":475},{},[476],{"type":27,"value":477},"Goroutine-per-connection maps onto this shape so directly that the Go prototype was passing traffic in about a week. The tokio version took close to a month, and most of that month was spent convincing the borrow checker about connection state shared between the read half and the write half across await points. That is not a complaint about Rust, it is a measurement of where the effort goes.",{"type":22,"tag":29,"props":479,"children":481},{"id":480},"what-the-numbers-said",[482],{"type":27,"value":483},"What the numbers said",{"type":22,"tag":23,"props":485,"children":486},{},[487],{"type":27,"value":488},"Rust was faster, and by less than the discourse promises. Throughput landed within roughly 10 percent once the Go version pooled its buffers. The visible difference was the tail: Go's p99.9 showed the garbage collector, Rust's did not.",{"type":22,"tag":23,"props":490,"children":491},{},[492,494,500],{"type":27,"value":493},"But the GC story is budgetable. Pauses themselves have been sub-millisecond since Go 1.8. The real cost is assist work surfacing as jitter when allocation pressure climbs, and that you can engineer against: ",{"type":22,"tag":57,"props":495,"children":497},{"className":496},[],[498],{"type":27,"value":499},"sync.Pool",{"type":27,"value":501}," over connection buffers, preallocated TLS record scratch space, and a rule that nothing in the per-request path allocates. That work cut our tail by an order of magnitude, and after it, the two prototypes were close enough that no customer on a real network would ever tell them apart through normal jitter.",{"type":22,"tag":29,"props":503,"children":505},{"id":504},"what-actually-decided-it",[506],{"type":27,"value":507},"What actually decided it",{"type":22,"tag":23,"props":509,"children":510},{},[511],{"type":27,"value":512},"The deciding costs were daily, not benchmark.",{"type":22,"tag":23,"props":514,"children":515},{},[516],{"type":27,"value":517},"A gateway's job is mostly policy, and policy changes constantly. The DLP rule engine, ICAP hooks, header rewrites for the dozen apps that do something weird, every one of those is a feature someone has to write under deadline. In Go, anyone on the team ships those. In Rust, the connection-state lifetimes we fought in the prototype were going to be fought again inside every feature that touched the hot path, forever.",{"type":22,"tag":23,"props":519,"children":520},{},[521],{"type":27,"value":522},"Profiling matters as much. pprof against a production binary, live, answered every performance question we had during load testing. The Rust tooling is good and getting better, it was not that, not then.",{"type":22,"tag":23,"props":524,"children":525},{},[526],{"type":27,"value":527},"And hiring is a real input. We can interview for Go and find people who are productive in a month. The Rust hiring pool for systems-with-deadlines work was a fraction of that, in Chennai, in that year.",{"type":22,"tag":29,"props":529,"children":531},{"id":530},"where-rust-would-have-won",[532],{"type":27,"value":533},"Where Rust would have won",{"type":22,"tag":23,"props":535,"children":536},{},[537],{"type":27,"value":538},"If we were building the shared core that other teams embed, counted in microseconds, where every consumer pays our overhead on every call, Rust, no argument. Same if the workload were CPU-bound transformation instead of policy and plumbing. The general rule we took away: Rust when the cost of the runtime is paid by your users, Go when the cost of the language is paid by your roadmap.",{"type":22,"tag":23,"props":540,"children":541},{},[542],{"type":27,"value":543},"We shipped Go, with a short list of enforced rules about allocation in the hot path. The p99 has not been the thing a customer escalated yet. The roadmap has shipped every quarter. That is the trade, and I would make it again.",{"title":8,"searchDepth":103,"depth":103,"links":545},[546,547,548,549],{"id":464,"depth":103,"text":467},{"id":480,"depth":103,"text":483},{"id":504,"depth":103,"text":507},{"id":530,"depth":103,"text":533},"content:blog:go-vs-rust-for-proxy-workloads.md","blog\u002Fgo-vs-rust-for-proxy-workloads.md","blog\u002Fgo-vs-rust-for-proxy-workloads",{"_path":554,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":555,"description":8,"heading":555,"date":556,"minutes":120,"summary":557,"body":558,"_type":108,"_id":562,"_source":110,"_file":563,"_stem":564,"_extension":113},"\u002Fblog\u002Fmerging-the-browser-and-the-sase-stack","Merging the browser and the SASE stack","2025-06-18","Consolidation slideware says one agent, one policy. The enforcement plumbing underneath says otherwise. What merging actually requires.",{"type":19,"children":559,"toc":560},[],{"title":8,"searchDepth":103,"depth":103,"links":561},[],"content:blog:merging-the-browser-and-the-sase-stack.md","blog\u002Fmerging-the-browser-and-the-sase-stack.md","blog\u002Fmerging-the-browser-and-the-sase-stack",{"_path":566,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":567,"description":8,"heading":567,"date":568,"minutes":13,"tag":569,"summary":570,"body":571,"_type":108,"_id":575,"_source":110,"_file":576,"_stem":577,"_extension":113},"\u002Fblog\u002Fprompt-injection-from-the-enforcement-side","Prompt injection, from the enforcement side","2025-03-05","Byline","What a gateway can and cannot do about prompt injection, written for people who have to sign off on AI tools this quarter.",{"type":19,"children":572,"toc":573},[],{"title":8,"searchDepth":103,"depth":103,"links":574},[],"content:blog:prompt-injection-from-the-enforcement-side.md","blog\u002Fprompt-injection-from-the-enforcement-side.md","blog\u002Fprompt-injection-from-the-enforcement-side",1781170135300]