Harden the public release: API exposure, path handling, cookie export, contributor address - #38
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Harden the public release: API exposure, path handling, cookie export, contributor address
Four independent items from the release audit, each with regression tests that fail
without the fix.
An unauthenticated API was reachable from the network
AuthConfig(enabled=True)existed but its only consumer was ato_dict()mask — nothingenforced it, and no middleware or dependency was wired anywhere in
web/. The shippedconfigs bound
0.0.0.0. That combination publishedPOST /api/llm/proxy— which takes anarbitrary prompt and streams it through the operator's own API keys — plus read/write
access to every knowledge base, to anyone who could reach the port.
The guard has two halves, in
web/auth.py:configured. This is what protects the default install; the dangerous configuration now
fails loudly instead of serving. Escape hatch:
auth.allow_insecure_network_bind, forwhen a reverse proxy in front already authenticates callers.
/api/*requiresAuthorization: Bearer <token>.GET /api/healthstays open so liveness probes work.With no token and a loopback bind — the new default — nothing changes.
Shipped configs move from
0.0.0.0to127.0.0.1, and the docs that described a bearerscheme which did not exist now describe the one that does.
A BibTeX
filefield could read any PDF on the serverThree sites parsed the
fileentry of an uploaded.bibdirectly, bypassing thevalidate_local_pathallow-list the local-docs routes already used.file = {/…/private.pdf}made the server parse that file and store its text as a KB chunk, which whoever uploaded the
.bibcould then read back through search.All three now go through one helper that validates against
local_docs.allowed_roots. Itfails soft: a rejected path skips the local-PDF shortcut and lets the DOI download proceed,
rather than failing the import.
import-browser-cookiesdumped the whole jar by defaultWith no
--domainthe command wrote every cookie the browser held — mail, bank, everything— to a plaintext file. Its own help string said "NOT recommended" and did it anyway. A
domain filter is now required, with
--all-domainsas the explicit opt-in.A contributor's address shipped in two config presets
configs/embedders/code_kb.ymlandopenai_large.ymlcarried a real address asunpaywall_email, which is transmitted to Unpaywall and PubMed on every request — so everyuser of those presets impersonated them. Both are placeholders now.
tests/unit/test_repo_hygiene.pykeeps this from drifting back, and also guards againstre-introducing a shadow-library reference into the tracked tree.
Behaviour changes to be aware of
server.host: "0.0.0.0"need127.0.0.1, a token, or the opt-out flag.local_docs.allowed_rootsto cover the PDFlocation. Outside it, the entry falls through to the DOI download path and logs why.
Not changed
CORSMiddlewareis still not instantiated. That is the safe state — browsers blockcross-origin by default, no user-facing doc claims otherwise, and adding a permissive
policy would be a regression.
Verification
indiciumhidden andci.yml's ignore/deselect list applied:2503 passed, 8 skipped, 17 deselected, 0 failed.