Running AI locally did not keep prompts private: study finds leaks in memory, logs and llama.cpp slots
A 16 September preprint recovered prompts from runtime memory, an LM Studio log and another client's saved llama.cpp session, while seeing nothing leave the machine. Local is where a model runs, not a promise about who else can read the prompt.
By Parminder Kumar Sharma · · 19 min read

200 out of 200, with a different key
In 200 of 200 controlled trials, a client holding one valid API key for a llama.cpp server restored the saved conversation state of a second client holding a different valid key. That is the sharpest measurement in The Illusion of Local Privacy: Confidentiality Boundary Failures in Consumer LLM Serving Systems, an arXiv preprint submitted on 16 September 2026 by Youssef Hamdi Zafan Ibrahim, Muhammad Ikram of Macquarie University and Mohammed Khalaf Salama. Treating those trials as a sample, the two-sided 95% Wilson score interval I computed runs from 98.1% to 100%. This was not an intermittent race condition.
Here is what that number does not establish. Saving and restoring slot state only exists when an operator starts llama-server with --slot-save-path, which the current server documentation lists as disabled by default. The attack needs at least two clients sharing one server process, which is not how a person running a model on their own laptop usually works. The paper did not test the flaw against any real or internet-facing server, reports no CVE, and I found no public advisory, issue or pull request for it in the llama.cpp repository. And llama.cpp's own security policy puts multi-tenant isolation on the operator and says that "none of the topics under Using llama.cpp securely are considered vulnerabilities". Whether the maintainers would classify this as a vulnerability at all is an open question.
The finding still matters, and so do the paper's other results, because together they test an assumption behind a great deal of workplace advice about AI: if the model runs on your own machine, your prompts are private. The authors recovered prompts from process memory after inference, from an LM Studio log file days after the conversation, and from another client's saved session, while observing no prompt leaving the machine over the network. Their conclusion is that "locality is a deployment property, not a confidentiality guarantee".
A declaration of interest belongs here. This site runs a free tool, Can I run AI locally, which recommends Ollama or LM Studio and offers a Private assistant workload described as kept on your device. That description is true about where computation happens. This briefing is partly a correction to what it can be read to promise.
What the researchers actually tested
The paper is a 20-page preprint that its authors describe as under review for IEEE Transactions on Information Forensics and Security. It has not been peer reviewed. The authors built a measurement framework they call LLAnalyzer and used it to split a local LLM stack into four boundaries a prompt crosses: loading the model file, living in runtime memory, being written to storage by the desktop application, and passing through a serving interface that more than one client can reach.
The method is the strongest part of the work. Every test prompt carries a freshly generated UUIDv4 canary, which has 122 random bits, and the harness checks that the canary is absent from the evidence source before the experiment starts. A later exact match can then be tied to one specific request rather than inferred from similar-looking text. The authors define three adversaries:
- A1, a local process: an unprivileged program running under the same operating-system user account as the model server, which the paper illustrates with browser extensions, IDE plugins and utilities.
- A2, a network client: an authenticated client limited to the published serving interface, with no access to memory, files or the operating system.
- A3, a malicious model provider: someone who can supply a crafted GGUF model file to an otherwise unmodified engine.
The main experiments ran on one bare-metal Ubuntu 24.04.4 LTS workstation (kernel 7.0.0-29, Intel Core i7-9850H, 16 GB of RAM, a CUDA-capable GPU with 8 GB of VRAM). All four models were GGUF files at Q4_K_M quantisation from the lmstudio-community organisation on Hugging Face: NVIDIA Nemotron-3-Nano 4B, Qwen3.5 9B, Gemma-4-E4B-it and Phi-4-reasoning-plus 14B. The software under test is in the table below, exactly as the paper names it.
Software and versions named in the paper's Table 10, with the role each played. Source: arXiv 2609.18526, Appendix A.1.
| Component | Version tested | Used for |
|---|---|---|
| llama.cpp and llama-server | Commit 388d39f3e | Runtime memory and serving-interface tests |
| LM Studio | 0.4.21 (Build 2) | Wrapper logging and network behaviour |
| Ollama | 0.20.5 | Wrapper logging and network behaviour |
| SGLang | 0.5.13.post1 | Reproduction check for GGUF and Jinja hardening |
| glibc allocator | 2.39 | Heap residue and allocator experiments |
Notice what is not in that list. The paper does not test whether any tool binds to all network interfaces, whether a local API answers without authentication, or whether a web page in the user's browser can reach the server. Those are the exposure questions most people have in mind when they worry about local AI, and they are covered later in this briefing from the tools' own documentation, not from the paper.
Four boundaries, four different answers
Model loading held. Every one of an 80-case malformed-input battery and a 21-file corpus of broken GGUF headers was rejected before model initialisation. A 24-hour AFL++ fuzzing campaign with AddressSanitizer and UndefinedBehaviorSanitizer ran more than 12 million parser executions (1.2 x 10^7) with no crash, no sanitiser violation and no malformed model loaded. The authors are careful to call this a bounded negative result: undiscovered parser bugs may exist outside the explored inputs. The llama.cpp security advisory list shows why that caution is warranted: CVE-2026-27940 and CVE-2026-33298, both GGUF parsing heap overflows rated high, were published in March 2026.
Runtime memory did not. Immediately after a response, each measured inference left 13 to 14 recoverable plaintext copies of the prompt in process memory. When twelve tenants ran one after another through the same server process, prompts from 11 of the 12 were still recoverable afterwards: 110 copies and about 10.8 MB of data. Debugger tracing attributed this to two stages. Ordinary request handling makes many copies (JSON parsing, chat-template expansion, request construction and repeated std::string reallocation), and glibc's allocator then keeps released buffers for reuse without clearing them.
The authors patched the engine to clear selected buffers and zero KV-cache cells after use. Copies fell from 110 to 78 and plaintext from 10,834 KB to 3,352 KB, reductions of 29% and 69% by my arithmetic. The tenant-level outcome did not move: 11 of 12 tenants were still recoverable. Moving the model onto the GPU did not help either. With Qwen3.5 9B partially offloaded to CUDA, nine canaries were recoverable from host memory after one request, all sixteen after two more requests, and the same nine after ten seconds idle. After the server process was terminated, none were found in the memory regions the tool examined, which the paper explicitly says is not evidence of secure erasure.
Desktop application storage depended on one setting. Under what the paper calls the evaluated LM Studio default configuration, canary-tagged prompts were recovered from a wrapper-managed plaintext log, and prompts from earlier sessions were still there days later. The configuration showed logSensitiveData enabled. After the researchers disabled it in http-server-config.json and restarted, the same test found no canaries in the files examined. Ollama 0.20.5 left no canary in the files the tool examined. Neither application sent prompts out: across 205 monitored Ollama inference sessions in an isolated network namespace there were no external connection attempts attributable to inference, and the LM Studio run likewise showed no outbound prompt transmission.
The serving interface failed in two independent ways. First, the slot restoration flaw. With --slot-save-path enabled, the /slots save and restore operations required a valid API key, but the paper observed no check binding saved state to the key that created it. Tenant B restored Tenant A's state in 200 of 200 trials, 50 per model, which the authors map to CWE-862 (Missing Authorization) and CWE-639 (Authorization Bypass Through User-Controlled Key). Asked to continue the restored conversation, the model repeated A's secret in 126 of 200 trials (63%): 50 of 50 for Gemma and Qwen, 25 of 50 for Nemotron and 1 of 50 for Phi-4-reasoning-plus. The paper stresses that the lower figure is not partial protection, because the state had already crossed between tenants in every trial.
Second, a timing side channel that needs no saved state at all. Because the server reuses cached prompt prefixes, a prompt whose opening has been processed before returns its first token faster. Across 50 cached and 50 uncached requests per model, a threshold classifier separated the two with an AUC of 1.000 for all four models. An attacker with ordinary access could therefore test whether a candidate prompt prefix has been seen by the shared server. Removing the slot restoration path would not close this channel.
Each boundary, what the paper measured and what that measurement does not establish. Source: arXiv 2609.18526, sections 4.1 to 4.4, with interval and percentage arithmetic by pk-sharma.com.
| Boundary | What the paper measured | What it does not establish |
|---|---|---|
| Integrity (model loading) | No crash, sanitiser violation or malformed load in over 12 million fuzzing executions | That the GGUF parser is safe; two high-severity parser CVEs were published in March 2026 |
| Lifetime (process memory) | 11 of 12 tenants recoverable; sanitisation cut copies 29% and bytes 69% but not tenants | How a same-user process would read that memory under default Linux ptrace restrictions |
| Persistence (application storage) | LM Studio plaintext log with logSensitiveData on; none found when off; none found for Ollama | Behaviour of current versions, other log files, chat history, or retention period |
| Isolation (serving interface) | 200 of 200 cross-tenant restores; timing AUC 1.000 for all four models | Exposure on real deployments, how often slot saving is enabled, or WAN figures |
| Network egress | No external connections attributable to inference in 205 Ollama sessions | Anything about cloud features, updates or other versions |
Three comforting labels that are not controls
Local. Ollama's FAQ says: "We don't see your prompts or data when you run locally." LM Studio's offline documentation says nothing you enter when chatting with models leaves your device. The paper's network measurements are consistent with both statements. They are statements about transmission to the vendor, though, and the paper's point is that transmission is only one boundary. A plaintext log that any program running as the same user can open, or a prompt sitting in freed heap memory, never leaves the device either. LM Studio's own documentation also states that conversations are stored as JSON under ~/.lmstudio/conversations/, a persistence surface the paper did not examine.
Authenticated. An API key answers the question of whether a request may reach the server. It does not answer which saved state that request may touch. The current llama-server documentation describes --api-key as accepting multiple keys as a comma-separated list and describes slot restore as taking a filename in the save directory. Nothing in the documentation I read binds a saved slot to the key that created it. Handing each team or application its own key on one shared server therefore looks like separation without providing it, on the paper's evidence.
Sanitised. A patch that removes 69% of recoverable prompt bytes sounds like a fix. Measured by the question that matters, whether an earlier user's prompt can still be recovered, it changed nothing in the paper's test: 11 of 12 tenants before, 11 of 12 after. The same logic applies to GPU acceleration, which the paper found should not be treated as a memory-confidentiality mechanism because prompt handling still happens on the host.
Where the paper's text runs ahead of its numbers
The research is careful in most places, and several of its negative results are more honest than papers usually manage. A close reading still turns up claims without reported support, experiments without reported results, and a few inconsistencies. None of them overturns the main findings, but a reader deciding how much weight to put on each number should know about them.
Scope and support in the published text of arXiv 2609.18526 (HTML, PDF and TeX source v1). Arithmetic and repository checks by pk-sharma.com.
| Topic | Stated in the paper | Not stated or not supported |
|---|---|---|
| Remote timing over a WAN | Abstract and introduction say cached prefixes stay distinguishable under WAN conditions | No WAN latency, route, load or sample figures; the AUC is reported for the evaluated conditions |
| Memory acquisition | A1 is an unprivileged same-user process; gdb and cuda-gdb were used | How snapshots were taken relative to Ubuntu's default ptrace restriction |
| Platforms | Bare-metal Ubuntu 24.04.4; section 3.5 also mentions WSL2 | macOS or Windows results; which runs, if any, used WSL2 |
| GPU | Partial CUDA offload with Qwen3.5 9B | Full offload or other GPU serving stacks |
| Allocator settings | MALLOC_ARENA_MAX=1 and MALLOC_PERTURB_=165 were evaluated | Any result for either setting |
| Further experiments | Table 12 lists 200-trial stealth KV backdoor and concurrent slot manipulation runs | Their results |
| Internet exposure | Appendix describes passive search-engine counts of Ollama and llama.cpp hosts | Any count |
| Tested llama.cpp revision | Commit 388d39f3e | That commit does not resolve in the public ggml-org repository |
| Latency cost of zeroisation | Below approximately 0.5% of mean latency | Table 7 gives 0.59% for Gemma and 0.56% for Nemotron |
| Vendor disclosure | Vulnerabilities responsibly disclosed to affected maintainers | Dates, channels, recipients or responses |
Two of those rows deserve a sentence each. The latency discrepancy is small and does not change the conclusion that zeroisation is cheap, but it is the kind of rounding a reviewer will catch. The ptrace row matters more for anyone assessing real risk. Ubuntu documents that since release 10.10, users cannot ptrace processes that are not descendants of the debugger, controlled by the kernel.yama.ptrace_scope setting. Reading another process's memory normally goes through that permission check. If the snapshots were taken with a debugger that launched the server, with root, or with the restriction relaxed, a same-user program on a default Ubuntu desktop may find the residue harder to reach than the A1 adversary implies. That is my inference from the documentation; the paper does not say either way.
Disclosure: asserted, not documented
The paper lists responsible disclosure to the affected maintainers as one of its contributions, and its ethics statement says the authors followed coordinated vulnerability disclosure practices. It gives no dates, no channel, no recipient and no vendor response for any finding.
Two public records make that gap worth asking about. First, llama.cpp's SECURITY.md says its private security disclosure programme is disabled until further notice, that fixes should be submitted as public pull requests, and that emails will be ignored. The repository history shows that change landing on 1 June 2026, in pull request 23963. The usual private route for reporting a llama.cpp vulnerability was therefore closed throughout the 107 days between that change and the paper's submission. I searched the repository's issues and pull requests for slot restore authorisation, cross-tenant state and KV-cache zeroisation and found nothing matching the paper's findings.
Second, the paper's Open Science section links to the authors' artifact repository on GitHub, created on 8 September 2026. It contains a disclosure plan dated 23 June 2026 whose status line reads "Not yet sent". That plan covers two findings, the LM Studio logging default and KV-cache residue in llama.cpp, and does not mention the slot restoration flaw. The same repository, not the paper, is the source for further detail about LM Studio: a log location under ~/.lmstudio/server-logs/, the configuration file under ~/.lmstudio/.internal/, no GUI control for the setting, and 30-day retention. I could not confirm any of that in LM Studio's documentation, which does not mention logSensitiveData, and I have not repeated the authors' tests.
This is a question about the record, not an accusation about conduct. The plan is 85 days older than the paper and may simply be stale; disclosure may well have happened by email or through a channel that leaves no public trace. But the paper asks readers to accept that vendors were told, and neither the paper nor its artifacts show when, how or with what result. I have not published the repository link here because it contains attack reproduction material; the paper links it for anyone who needs it.
On interests: the authors are two independent researchers and one Macquarie University academic, and they sell nothing that benefits from local AI looking unsafe. LM Studio and Ollama are commercial products whose privacy statements are part of their appeal. And, as noted at the top, this site runs a tool that points people towards those products.
What the tools' documentation says today
Because the paper does not test network exposure or browser access, the table below comes from each project's current documentation, read on 17 September 2026. The good news is that all three bind to the loopback address by default. The less good news is that authentication is off by default everywhere, and browser access defaults differ widely.
Documented defaults on 17 September 2026. Sources: llama.cpp tools/server/README.md and SECURITY.md; Ollama docs faq.mdx and api/authentication.mdx; LM Studio docs for server settings, authentication and lms server start.
| Setting | llama-server | Ollama | LM Studio |
|---|---|---|---|
| Default bind address | 127.0.0.1, port 8080 (--host) | 127.0.0.1, port 11434 (OLLAMA_HOST) | 127.0.0.1 for lms server start (--bind); app switch to serve on local network |
| Authentication | None unless --api-key is set; several keys allowed | Local API does not require authentication | Off by default; API tokens from 0.4.0 |
| Browser cross-origin access | Reflects any Origin with credentials allowed, unless --cors-origins is set | Allows 127.0.0.1 and 0.0.0.0 origins; more via OLLAMA_ORIGINS | CORS off unless enabled |
| Settings the paper's findings touch | --slot-save-path off by default; prompt cache on; /slots monitoring on | None identified | logSensitiveData not documented |
The llama-server cross-origin default is recent. Pull request 25655, merged on 14 July 2026, added the --cors-* flags. Its description says the server previously always allowed any origin, which was acceptable because endpoints were stateless and read-only, and it keeps the permissive behaviour as the default while restricting it to localhost when the new agent tools are enabled. Because the paper's llama.cpp commit cannot be found in the public repository, I cannot tell which side of that change it tested.
My inference, not tested by the paper or by me: slot save and restore are state-changing operations, so the maintainers' own rationale for permissive cross-origin access does not obviously cover a server started with --slot-save-path and no API key. On such a server, a web page open in the user's browser is another potential client. Browsers apply their own, evolving restrictions on public pages calling local addresses, and I have not checked how those interact with these endpoints.
Version drift between the paper's tested versions and the latest releases found on 17 September 2026. Sources: arXiv 2609.18526 Table 10; GitHub releases API for Ollama and llama.cpp; LM Studio changelog. Day counts by pk-sharma.com.
| Tool | Tested | Latest found | Drift |
|---|---|---|---|
| Ollama | 0.20.5, released 9 April 2026 | 0.34.1, 14 September 2026 (0.34.2-rc1 in pre-release) | 158 days and 14 minor versions |
| LM Studio | 0.4.21 Build 2 (0.4.21 dated 12 August 2026) | 0.4.24, 9 September 2026 | Three releases; changelogs do not mention logging defaults |
| llama.cpp | Commit 388d39f3e | Build b11012, 17 September 2026 | Not computable; commit not found publicly |
Drift cuts both ways. Newer versions may have changed the behaviour the paper measured, and the paper cannot tell you whether today's installs are affected. Equally, I found nothing in the public changelogs or repository that fixes any of the four findings. Test the versions you run.
What to do, in order
The list below runs from cheapest and widest to narrowest. It stays within what the paper measured and what the tools document. If your organisation treats local models as the approved route for sensitive text, the first four items belong in that policy.
Take this with you
Local LLM confidentiality checklist
- Inventory which local model servers run on managed machines and which address each listens on. Anything bound to 0.0.0.0 or a LAN address is a network service and needs the controls of one.
- Keep the bind address at 127.0.0.1. If other machines genuinely need access, put the server behind a reverse proxy that enforces authentication, and firewall the port so only the proxy can reach it.
- Turn on authentication even for local use: --api-key for llama-server, Require Authentication with API tokens in LM Studio. Ollama documents no local authentication, so rely on the loopback bind and a proxy.
- Treat one shared llama-server process as one trust domain. Do not enable --slot-save-path on a server used by more than one person or application, and run separate server processes per tenant rather than separate API keys.
- Where mutually distrusting clients must share a server, consider --no-cache-prompt, accepting the speed cost, because the paper shows shared prefix caching acts as a timing oracle. Consider --no-slots to disable the slots monitoring endpoint.
- Narrow browser access: set --cors-origins on llama-server to localhost or your own front end, keep CORS off in LM Studio unless needed, and avoid wildcard browser-extension patterns in OLLAMA_ORIGINS.
- In LM Studio, check whether logSensitiveData is enabled in http-server-config.json, turn it off if you do not need request logging, restart, and then deal with log files already written, which the paper did not test.
- Bring model logs and chat histories into your retention, backup and endpoint data-loss rules, including LM Studio's documented conversations folder, as you would any file containing the text people type.
- On multi-user or shared machines, give each person a separate operating-system account, keep Linux ptrace_scope at 1 or higher, and restart long-running servers between sensitive workloads, remembering the paper's caveat that termination is not secure erasure.
- Do not rely on GPU offload or allocator tweaks for memory confidentiality; the paper found offload left host residue and reported no result for allocator settings.
- Record the versions you run and re-test after updates, because every tool in the paper has moved on since it was tested.
# Which local model servers are listening, and on which address
# (8080 llama-server default, 11434 Ollama default, 1234 used in LM Studio docs)
ss -ltnp | grep -E ':(8080|11434|1234) ' # Linux
lsof -nP -iTCP -sTCP:LISTEN | grep -E ':(8080|11434|1234) ' # macOS
# LM Studio: is sensitive-data logging switched on?
# File name from the paper; directory from the authors' repository
grep -rH logSensitiveData ~/.lmstudio/.internal/ 2>/dev/null
# Linux: same-user ptrace restriction (1 or higher restricts attaching)
cat /proc/sys/kernel/yama/ptrace_scope
The question to ask
"It runs locally" answers where the computation happens. It does not answer the question a data protection or security review actually needs: once the answer has come back, where does the prompt still exist, who on this machine or this server can reach it, and for how long? In this paper the honest answers were process memory until restart, a log file for days, and any other key holder on a shared server.
And for the authors, one question would settle the part of the paper that rests on assertion: with llama.cpp's private reporting closed since 1 June and a disclosure plan in their own repository marked not yet sent, when were LM Studio and the llama.cpp maintainers told, through which channel, and what did they say?
Key facts
Sources
- PrimaryAbstract page: authors, submission date 16 September 2026, review statusarXivaccessed 2026-09-17
- PrimaryFull paper HTML (read in full with the PDF and TeX source): methods, all results, Tables 1 to 12, appendicesarXivaccessed 2026-09-17
- Primaryllama-server documentation: --host, --api-key, --cors-origins, --slots, --slot-save-path and /slots endpointsggml-org/llama.cppaccessed 2026-09-17
- PrimarySecurity policy: private disclosure disabled, multi-tenant isolation and scope of vulnerabilitiesggml-org/llama.cppaccessed 2026-09-17
- PrimaryPull request disabling private security disclosures, merged 1 June 2026ggml-org/llama.cppaccessed 2026-09-17
- PrimaryPull request adding --cors-* options and describing the previous always-on CORS behaviour, merged 14 July 2026ggml-org/llama.cppaccessed 2026-09-17
- PrimaryPublished security advisories, used to check for any advisory on slot restoration and to cite GGUF parser CVEsggml-org/llama.cppaccessed 2026-09-17
- PrimaryFAQ: default bind address, OLLAMA_ORIGINS defaults, statement on prompts when running locallyOllamaaccessed 2026-09-17
- PrimaryAuthentication docs: the local API does not require authenticationOllamaaccessed 2026-09-17
- PrimaryRelease dates for 0.20.5 and 0.34.1, used for version driftOllamaaccessed 2026-09-17
- PrimaryServer settings: Require Authentication, Serve on Local Network, Enable CORSLM Studioaccessed 2026-09-17
- PrimaryAuthentication: API tokens from 0.4.0, not required by defaultLM Studioaccessed 2026-09-17
- Primarylms server start: --bind default 127.0.0.1, CORS disabled unless setLM Studioaccessed 2026-09-17
- PrimaryOffline operation statement that chat input does not leave the deviceLM Studioaccessed 2026-09-17
- PrimaryChat docs: conversations stored as JSON in ~/.lmstudio/conversationsLM Studioaccessed 2026-09-17
- PrimaryChangelog: 0.4.21 to 0.4.24 release dates and contentsLM Studioaccessed 2026-09-17
- PrimaryUbuntu security features: default ptrace scope restrictionUbuntuaccessed 2026-09-17
- PrimaryYama ptrace_scope modes 0 to 3Linux kernel documentationaccessed 2026-09-17


