This release includes 3 security fixes for security teams reviewing exposed deployments.
Topics
+14 more
Affected surfaces
ReleasePort's take
Moderate signalRelease v1.6.11 blocks cloud‑metadata IP in Apprise plugin schemes and redacts Google Gemini API keys from error logs.
Why it matters: Security hardening now prevents unauthorized metadata access via Apprise and eliminates exposed Gemini credentials; no measurable adoption metric provided.
Summary
AI summaryExtended cloud‑metadata IP block to Apprise plugin schemes and redacted Google Gemini API key from logs.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Medium |
Suppressed CVE-2026-8328 (ftplib.ftpcp SSRF) until Python 3.14.6. Suppressed CVE-2026-8328 (ftplib.ftpcp SSRF) until Python 3.14.6. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: high |
— |
| Security | Medium |
Extended cloud-metadata IP absolute-block to Apprise plugin schemes in NotificationURLValidator. Extended cloud-metadata IP absolute-block to Apprise plugin schemes in NotificationURLValidator. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
| Security | Medium |
Redacted Google Gemini API key from list_models_for_api error log. Redacted Google Gemini API key from list_models_for_api error log. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
| Breaking | Medium |
JavaScript rendering disabled by default in production Docker image; new web.enable_javascript_rendering setting (default false). JavaScript rendering disabled by default in production Docker image; new web.enable_javascript_rendering setting (default false). Source: granite4.1:8b-q6_K@2026-05-21 Confidence: high |
— |
| Feature | Medium |
Embeddings now work against OpenAI-compatible local servers (LM Studio, vLLM, llama.cpp). Embeddings now work against OpenAI-compatible local servers (LM Studio, vLLM, llama.cpp). Source: granite4.1:8b-q6_K@2026-05-21 Confidence: high |
— |
| Feature | Medium |
Enriched AI release notes and rendered changelog in release flow. Enriched AI release notes and rendered changelog in release flow. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Added statistical functions module for benchmarks. Added statistical functions module for benchmarks. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Surface WAL-dispose failures and documented LDR_APP_DEBUG sensitivity. Surface WAL-dispose failures and documented LDR_APP_DEBUG sensitivity. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
| Dependency | Medium |
Pinned towncrier to exact version and bumped Python to 3.14.5. Pinned towncrier to exact version and bumped Python to 3.14.5. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
| Performance | Medium |
Added timeout=8 to Docker HEALTHCHECK urllib.request.urlopen call. Added timeout=8 to Docker HEALTHCHECK urllib.request.urlopen call. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: high |
— |
| Bugfix | Medium |
"Start Research" button no longer silently does nothing for non-multiple-of-512 context window values. "Start Research" button no longer silently does nothing for non-multiple-of-512 context window values. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: high |
— |
| Bugfix | Medium |
Chinese/Japanese/Korean text now renders in exported PDFs. Chinese/Japanese/Korean text now renders in exported PDFs. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: high |
— |
| Bugfix | Medium |
Cross-engine filtering now keeps LLM ranking fallbacks within the subset of results the model actually evaluated. Cross-engine filtering now keeps LLM ranking fallbacks within the subset of results the model actually evaluated. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: high |
— |
| Bugfix | Medium |
Fixed file-descriptor leak (`anon_inode:[eventpoll]`) in `_close_base_llm` when invoked while an asyncio loop is running. Fixed file-descriptor leak (`anon_inode:[eventpoll]`) in `_close_base_llm` when invoked while an asyncio loop is running. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
| Refactor | Medium |
Refactored environment settings to use specialized exception classes. Refactored environment settings to use specialized exception classes. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
| Other | Medium |
Added a "Testing a Release Candidate (Prerelease Image)" subsection to the developer guide. Added a "Testing a Release Candidate (Prerelease Image)" subsection to the developer guide. Source: granite4.1:8b-q6_K@2026-05-21 Confidence: low |
— |
Full changelog
🔒 Security
- Extended the cloud-metadata IP absolute-block in
NotificationURLValidatorto Apprise plugin schemes (signal, gotify, ntfy/ntfys, mattermost, rocketchat, matrix, json, xml, form, mailto). Previously only the http/https branch ran the IMDS guard, so a notification URL likesignal://169.254.169.254/...would round-trip to Apprise even though Apprise translates it into a plain HTTP request against that host. LAN/loopback reach for self-hosted plugin endpoints (the #4006 use case) is unchanged. - Fix Google Gemini API key leak in
list_models_for_apierror log. The
URL constructed at request time embeds the key as a?key=...query
parameter (per Google's documented API), so when the underlying request
failed, therequestsexception message — and therefore the
logger.exception(...)traceback — contained the full URL with the key.
The except handler now redacts the key from the message and uses
logger.warning(no exception chain).
🐛 Bug Fixes
-
JavaScript rendering disabled by default in the production Docker image (#3826). The headless-browser fallback in the content fetcher (Crawl4AI/Playwright) was previously attempted on every fetch even though the default Docker production image ships without a Chromium binary - each attempt failed loudly and contributed to the memory growth reported in issue #3826. A new
web.enable_javascript_renderingsetting (defaultfalse) gates the fallback. In limited (mostly accidental) internal benchmark comparisons - between dev instances that happened to have Chromium installed and routine Docker runs that did not - JS rendering did not measurably improve research quality, and most regular benchmark runs are on Docker without Chromium anyway, so the change does not regress observed quality. To enable: install Chromium in the runtime environment (playwright install --with-deps chromium) and toggle the setting in the UI. (#3826) -
Embeddings now work against OpenAI-compatible local servers (LM Studio, vLLM, llama.cpp). Previously the OpenAI embeddings provider only listed itself as available when an API key was configured, and the relevant
embeddings.openai.*settings were not registered for the UI to surface — so users who ran an OpenAI-compatible local server had no way to point the embeddings tab at it. The provider now also reports available when onlyembeddings.openai.base_urlis set, substitutes a placeholder API key for keyless endpoints (matching the LM Studio LLM provider's behavior), and ships a newsettings_openai_embeddings.jsondefaults file that registersembeddings.openai.api_key,embeddings.openai.base_url,embeddings.openai.model, andembeddings.openai.dimensions. The model-list lookup now routes through the configuredbase_urlso model discovery also targets the local server. (#3883) -
"Start Research" button no longer silently does nothing for users with a non-multiple-of-512 context window value. The hidden
context_windowinput on the research form had astep="512"constraint, so any stored value not aligned to that grid (e.g.25000) failed HTML5 form validation. Because the input lives inside adisplay:nonecontainer that is only shown for local providers, the browser could not focus the invalid field to report the error, so submission was aborted with no visible message and no log line — the click appeared to do nothing. Relaxed the step to1so any in-range integer is accepted; the value is still bounded bymin/maxand persisted unchanged. (#3909) -
Chinese/Japanese/Korean text now renders in exported PDFs. The default PDF stylesheet hard-coded a Latin-only font stack, so any CJK characters in the research result were dropped silently from the download even though they displayed correctly in the browser. The minimal CSS now includes a broad CJK fallback chain (Noto Sans CJK, PingFang, Hiragino, Apple SD Gothic Neo, Microsoft YaHei/JhengHei, Yu Gothic, Malgun Gothic, SimSun) covering Windows, macOS, and Linux desktops out of the box, and the Docker image now installs
fonts-noto-cjkso the slim base image has glyph coverage. Linux pip/server installs still need a CJK font package on the host — see install-pip.md and the FAQ for the per-distro commands. (#4055) -
Cross-engine filtering now keeps LLM ranking fallbacks within the subset of results the model actually evaluated, preventing unevaluated search results from leaking into downstream synthesis.
-
Fix file-descriptor leak (
anon_inode:[eventpoll]) in_close_base_llmwhen invoked while an asyncio loop is running. The previous code path skipped the async-client close in that case and documented that the "loop owner" would close instead — but no loop-owner cleanup actually exists in the project, so the innerhttpx.AsyncClient(and itsepoll_createFD) was silently abandoned. The same skip-path fires under the defaultlanggraph-agentstrategy because LangGraph dispatches some tool steps via asyncio internally, so close calls reached from a syncfinallycan still land inside a live loop. Cleanup now runs in a brief daemon thread that owns its own loop, soasyncio.run(aclose())works regardless of the caller's loop state; a bounded 5-secondjoinkeeps it from holding up shutdown if the Ollama server is unresponsive. This is the gap left by #3855's coverage of #3816 — same leak class, different code path.Also fixes a smaller secondary leak in the Docker
HEALTHCHECK:urllib.request.urlopen('http://localhost:5000/api/v1/health')had notimeout=argument, so when the app slowed down (FD exhaustion or otherwise) Docker's 10s healthcheck timeout SIGKILL'd thesh -cwrapper but the python child got reparented to PID 1 and hung forever, each contributing apidfdand a TCP socket against the app. Addingtimeout=8lets the child return/raise before Docker's wall so it exits cleanly and gets reaped.
📝 Other Changes
- Added a "Testing a Release Candidate (Prerelease Image)" subsection to the developer guide (
docs/developing.md) covering both the floating:prereleaseand immutableprerelease-vX.Y.Z-<sha>Docker Hub tags, with a side-by-side compose snippet that runs the RC on port 5001 with isolated volumes so a broken migration cannot affect a production instance. - Pool-dispose failures in the periodic WAL/SHM handle-release workaround (ADR-0004) now log at
WARNINGinstead ofDEBUGso silent drift becomes visible. Documented indocs/CONFIGURATION.mdthatLDR_APP_DEBUG=truealso enables Logurudiagnose=True, which can materialise sensitive locals into exception traces — do not enable in production. - Refactored environment settings to use specialized exception classes, improving error observability and alignment with
TRY003standards.
What's Changed
🔒 Security Updates
- fix(security): pin towncrier to exact version and bump Python to 3.14.5 by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4046
- ci(security): close zizmor artipacked finding + dismiss platform-conditional CVE by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4050
- test(security): SSRF edge-case coverage and weak-test cleanup by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4062
- fix(security): extend IMDS absolute-block to Apprise plugin schemes by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4063
- chore(security): suppress CVE-2026-8328 (ftplib.ftpcp SSRF) until 3.14.6 by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4072
- fix(security): redact Google API key from list_models error log by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4070
✨ New Features
- fix(release): enrich AI release notes + render changelog in release flow by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4035
- feat(benchmarks): add statistical functions module by @ishitta-iyer in https://github.com/LearningCircuit/local-deep-research/pull/4029
- chore(observability): surface WAL-dispose failures + document LDR_APP_DEBUG sensitivity by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4042
- Improve UI tests + CI: artifact uploads, WebKit skip narrowing, settle-wait migrations by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4061
- test(ui): chunk mobile-nav overlap DOM walk; drop WebKit skip (#4060) by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4076
🐛 Bug Fixes
- fix(embeddings): correct OpenAIEmbeddingsProvider.requires_api_key to… by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4036
- fix(llm,docker): close ChatOllama async httpx client when called from a running loop + healthcheck timeout by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4047
- fix(ci): drop environment: ci from reusable workflow by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4049
- fix(research-form): relax context_window step so Start Research submits (#3909) by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4051
- fix(pdf): render CJK characters in exported PDFs (#4055) by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4058
- fix(content-fetcher): disable JS rendering by default (#3826) by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/3971
- fix(release): set towncrier name to skip package import by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4071
- fix(ui-tests): match create/new/add buttons with word boundaries by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4069
🗄️ Database Changes
- test(migrations): pin invariants from PR #4000 multi-round review by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4033
- chore(alembic-runner): drop stale isolation_level="IMMEDIATE" references by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4039
📚 Documentation
- docs(developing): add prerelease Docker image testing section by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4034
- follow-up to #4047: hoist asyncio+threading imports + document Wave 7 in resource-cleanup.md by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4048
- docs(resource-cleanup): expand Wave 7 with full audit ledger by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4054
🔧 CI/CD & Maintenance
- 🤖 Update dependencies by @github-actions[bot] in https://github.com/LearningCircuit/local-deep-research/pull/4031
- 🤖 Update dependencies by @github-actions[bot] in https://github.com/LearningCircuit/local-deep-research/pull/4043
- chore: bump patch version to 1.6.11 by @github-actions[bot] in https://github.com/LearningCircuit/local-deep-research/pull/3961
🧹 Code Quality & Refactoring
- test(e2e): tolerate brief LLM output in research export test by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4053
- chore(labels): add 'code-ready' as a human-only signal label by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4068
🧪 Tests
- test(e2e): regression test for #3909 hidden context_window blocking submit by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4059
- test(scheduler): credential lifecycle coverage and weak-test cleanup by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4065
- test(error_handling): pin load-bearing branches in openai_compat_errors by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4074
- test(llm_utils): pin daemon-thread contract for in-loop async close by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4078
Other Changes
- feat(errors): friendly runtime messages for OpenAI-compatible endpoints by @voidborne-d in https://github.com/LearningCircuit/local-deep-research/pull/4027
- fix(embeddings): allow OpenAI-compatible local endpoints (#3883) by @SuperMarioYL in https://github.com/LearningCircuit/local-deep-research/pull/4026
- fix(search): keep cross-engine filter fallback within evaluated context by @qWaitCrypto in https://github.com/LearningCircuit/local-deep-research/pull/3866
- Feat/deepseek provider by @kwhyte7 in https://github.com/LearningCircuit/local-deep-research/pull/3432
- fix(notifications): allow signal:// Apprise scheme (#4006) by @therahul-yo in https://github.com/LearningCircuit/local-deep-research/pull/4056
- refactor: use specialized exception classes in settings module by @RinZ27 in https://github.com/LearningCircuit/local-deep-research/pull/3838
- chore(ci): cut workflow-status.md regen diff noise by @LearningCircuit in https://github.com/LearningCircuit/local-deep-research/pull/4066
New Contributors
- @voidborne-d made their first contribution in https://github.com/LearningCircuit/local-deep-research/pull/4027
- @qWaitCrypto made their first contribution in https://github.com/LearningCircuit/local-deep-research/pull/3866
- @therahul-yo made their first contribution in https://github.com/LearningCircuit/local-deep-research/pull/4056
- @RinZ27 made their first contribution in https://github.com/LearningCircuit/local-deep-research/pull/3838
Full Changelog: https://github.com/LearningCircuit/local-deep-research/compare/v1.6.10...v1.6.11
Security Fixes
- Extended cloud-metadata IP absolute‑block in `NotificationURLValidator` to cover Apprise plugin schemes (signal, gotify, ntfy/ntfys, mattermost, rocketchat, matrix, json, xml, form, mailto).
- Redacted Google Gemini API key from error log messages and changed logging level to warning.
- CVE-2026-8328
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About Local Deep Research
AI-powered deep research tool with multi-source search (arXiv, PubMed, web)
Related context
Related tools
Beta — feedback welcome: [email protected]