1
0
mirror of https://github.com/janeczku/calibre-web synced 2026-05-09 15:02:12 +00:00

4746 Commits

Author SHA1 Message Date
Ozzie Isaacs 6cbba6d170 Merge remote-tracking branch 'fix/commentxss' into Develop 2026-05-09 10:30:59 +02:00
Ozzie Isaacs 888ab4dc8f Update requirements 2026-05-09 10:28:12 +02:00
Ozzie Isaacs 753c19e700 Merge remote-tracking branch 'py314/py3.14-janeczku' into Develop 2026-05-09 10:24:58 +02:00
Ozzie Isaacs 4f9390332a Merge remote-tracking branch 'fix/attr' into Develop 2026-05-09 10:20:45 +02:00
Ozzie Isaacs ffddd85800 Merge remote-tracking branch 'fix/fixlter' into Develop 2026-05-09 10:19:57 +02:00
Ozzie Isaacs 652b0f20e0 Merge remote-tracking branch 'fix/token' into Develop 2026-05-09 10:17:57 +02:00
Ozzie Isaacs 598f08b916 Merge branch 'master' into Develop 2026-05-09 10:17:48 +02:00
Jacob Chapman 55cedba693 bump lxml to v6 for python 3.14 2026-04-29 22:05:40 -05:00
Jacob Chapman 10caf68d8b fix manifest reference 2026-04-29 22:05:40 -05:00
Ozzie Isaacs f4ed816f6e Fixes from testrun 2026-04-26 07:27:06 +02:00
Ozzie Isaacs ba77f41325 Merge remote-tracking branch 'fixes/notrace' 2026-04-25 16:04:51 +02:00
Ozzie Isaacs ea567fcbf0 Updated translation 2026-04-25 13:26:40 +02:00
Ozzie Isaacs edb05abcbe Merge remote-tracking branch 'tmp-orphan-on-download/fix-calibredb-cover-sibling' 2026-04-25 13:25:34 +02:00
Ozzie Isaacs 46811219ca Updated Requirements 2026-04-25 13:20:25 +02:00
Ozzie Isaacs 0aab0cac73 Merge remote-tracking branch 'tmp-orphan-on-download/fix-tmp-orphan-on-download' 2026-04-25 13:13:36 +02:00
Ozzie Isaacs 3257a36892 Merge remote-tracking branch 'ko/ko-translate-update' 2026-04-25 13:11:14 +02:00
limeade23 f10b680b0e Update Korean language 2026-04-23 17:41:46 +09:00
Ozzie Isaacs c2b1950cd5 Merge remote-tracking branch 'opds_date_update/fix-opds-atom-updated-reflects-modifications' 2026-04-20 15:55:24 +02:00
Ozzie Isaacs 00c8ff8ac4 Merge remote-tracking branch 'metadata-provider-none-crash/fix/metadata-provider-none-crash' 2026-04-20 15:49:26 +02:00
walrusec 0ca6e86177 Fix metadata search crash when ComicVine or Douban return None on error
Both comicvine.py and douban.py return None instead of [] when an HTTP
error occurs during a metadata search. The consumer in search_metadata.py
iterates the result directly, which raises TypeError: 'NoneType' object
is not iterable and crashes the server on single-threaded deployments.

Fixes #3606
2026-04-19 08:54:47 -04:00
haraldpdl ab17992ebb fix(opds): atom:updated reflects last modification, not date added
Books.atom_timestamp returned Books.timestamp (date added), which is
set at import and never changes. OPDS clients use atom:updated to
decide whether a book has changed on the server, so cover swaps,
metadata edits, and any other post-import change were invisible to
sync clients; they would keep serving the stale cover and title
until a manual refresh.

Atom RFC 4287 defines updated as "the most recent instant in time
when an entry or feed was modified", and Calibre already tracks that
field as last_modified, bumping it on every metadata and cover edit.
Switching the property to return last_modified (with a fallback to
timestamp when last_modified is NULL) aligns Calibre-Web's behaviour
with the Atom contract.

This change only affects the OPDS feed's atom:updated element. Kobo
sync uses its own last_modified comparison path, so it is unaffected.
2026-04-19 10:51:45 +02:00
haraldpdl 570371cc82 Don't write a cover sibling per download (--dont-save-cover)
calibredb export writes <uuid>.jpg next to <uuid>.<format> by
default, leaving an unused cover image in /tmp/calibre_web for
every download that goes through do_calibre_export. The cover
file is never read by calibre-web (cover serving uses a separate
path), so it is pure waste of disk space and IO.

Pass --dont-save-cover, paired with the existing --dont-write-opf,
to skip the unwanted side-effect at the source. Verified that
none of the three do_calibre_export call sites (download via
do_download_file, email via tasks/mail.py, kepubify via
tasks/convert.py) read the cover sibling.
2026-04-18 07:27:33 +02:00
haraldpdl 674b47bdbd Remove staged download from /tmp/calibre_web after response is sent
When config_embed_metadata is enabled with config_binariesdir or
config_kepubifypath set, do_download_file stages a copy of every
downloaded book under get_temp_dir() but never removes it. A bulk
OPDS or Kobo sync can fill the host filesystem in minutes; the
effect is amplified for comic formats (CBZ/CBR), where each
staged file can run to hundreds of MB or several GB. Once the
disk fills, downloads silently 404 and a container restart does
not recover the space.

Add an after_this_request hook that removes the staged copy after
the response is sent, gated on filename == get_temp_dir() so the
non-embed and gdrive-direct paths are untouched.
2026-04-18 07:12:38 +02:00
jvoisin 8cff413c4d Clean atributes as well in clean_string
`<img src=x onerror=alert(1)>` womp womp
2026-04-15 23:30:49 +02:00
jvoisin fd744af75d Don't give non-admin users a full stacktrace on 500
As `traceback.format_exc()` might contain internal file paths, library versions,
function names, and variable values.
2026-04-15 23:28:27 +02:00
jvoisin 6208d5e264 Correctly filter results kobo API
Multiple Kobo API endpoints use calibre_db.get_book_by_uuid() at db.py:748-749,
which performs a raw unfiltered query, meaning that common_filters() isn't
applied, so tag-based ACLs, language restrictions, and archived-book filtering
are all bypassed.
2026-04-15 23:14:09 +02:00
jvoisin 42dc36cc10 Escape comment columns names
Custom columns of type comments are rendered with `|safe` (disabling Jinja2
auto-escaping) and no `clean_string` sanitization. Compare with regular book
comments which correctly use `{{ entry.comments[0].text|clean_string|safe }}`.

Any user with edit permissions can set a custom comment column to
`<script>alert(document.cookie)</script>` and it will execute for every user who
views the book detail page or the OPDS feed. This is stored XSS with no
authentication barrier beyond edit permission.
2026-04-15 23:03:30 +02:00
jvoisin c23d35db4a Use 128 bits of entropy instead of only 32 in csp/ub.py
Remote login tokens are generated from only 4 bytes of randomness (32 bits = ~4
billion possibilities, 8 hex characters). The /ajax/verify_token endpoint at
remotelogin.py:98 has no rate limiting. The token is valid for 10 minutes.

At even modest request rates (10,000 req/sec), an attacker can test ~6 million
tokens during the 10-minute window , which isn't enough to exhaust the full
space, sure, but combined with multiple concurrent login sessions (each
generating a new token), or if the attacker can trigger the victim to initiate
remote login, the attack becomes more feasible. Compare with the Kobo auth
token which uses urandom(16) (128 bits).
2026-04-15 22:47:35 +02:00
Ozzie Isaacs fca580505c Fix typo 2026-04-15 20:31:40 +02:00
Ozzie Isaacs 19da54a7ae Merge remote-tracking branch 'fixes/escape_ldap' 2026-04-15 19:37:31 +02:00
Ozzie Isaacs 9c87f0fbde Merge remote-tracking branch 'fixes/fix_gdrive_md5' 2026-04-15 19:36:56 +02:00
Ozzie Isaacs e21f943712 Merge remote-tracking branch 'fixes/oauth_relink' 2026-04-15 19:36:48 +02:00
Ozzie Isaacs 4bb553f51d Merge remote-tracking branch 'fixes/noxxe' 2026-04-15 19:35:40 +02:00
Ozzie Isaacs 0615637f58 Merge remote-tracking branch 'fixes/nodebugleak' 2026-04-15 19:33:06 +02:00
Ozzie Isaacs a6c55deac6 Merge remote-tracking branch 'fixes/accessbp' 2026-04-15 19:31:29 +02:00
Ozzie Isaacs 2de8df7e0d Merge remote-tracking branch 'fixes/fix_kobo' 2026-04-15 19:28:55 +02:00
Ozzie Isaacs 4c1d7a9f6b Merge remote-tracking branch 'fixes/permshelf' 2026-04-15 19:28:12 +02:00
Ozzie Isaacs 9489905602 Merge remote-tracking branch 'fixes/chm' 2026-04-15 19:24:12 +02:00
Ozzie Isaacs 5e7c0c9d34 Merge remote-tracking branch 'fixes/sqlidb' 2026-04-15 19:23:01 +02:00
jvoisin b5da0df42a Prevent SQLI via dbpath
This is reachable only by the admin users, but is still a straightforward RCE
vector, if only via SQLite's `ATTACH DATABASE` trick
2026-04-14 23:23:12 +02:00
jvoisin 0959f84fd5 Use a sane permission for the encryption key file
The typical Linux umask of 0022, meaning the encrypted file is world-readable
(-rw-r--r--). Any OS-level user on the same system can read the key and decrypt
the encrypted credentials from app.db.
2026-04-14 23:08:35 +02:00
jvoisin 84777319d7 Fix access bypass on /show/ (serve_book)
The `serve_book` function uses `get_book()` which performs no access filtering:
it simply fetches by ID. Compare with `read_book` at web.py:1562 which
correctly uses `get_filtered_book()`. The `common_filters()` function enforces
per-user tag restrictions, language restrictions, and hidden-book rules.
2026-04-14 23:05:18 +02:00
jvoisin d85bef6c38 Don't leak credentials in debug_info
No need to dump Gmail OAuth client_secret, refresh_token, and
access_token in the debug ZIP in plaintext.
2026-04-14 22:55:08 +02:00
jvoisin 8ad9f4e3b7 Fix a dumb type condition in gdrive.py
hashlib.md5(dbpath) returns a hash object, not a hex string. Comparing a string
(md5Checksum) to a hash object with != always returns True. This means the
DB-replacement code path is always entered, allowing an attacker who sends a
forged notification (with the known static token) to trigger an arbitrary
metadata.db download from GDrive, replacing the live database.
2026-04-14 22:51:36 +02:00
jvoisin cde3888e17 Prevent LDAP injection in bind_user>get_object_details 2026-04-14 22:35:13 +02:00
jvoisin 387678a771 Prevent OAuth relinking.
When an OAuth provider_user_id is already linked to User A, and User B
authenticates with the same OAuth identity, User B is silently logged in as
User A. This is by design for single-user OAuth, but in a multi-user
environment it means: if an attacker gains access to the same OAuth provider
account (e.g., a shared GitHub org account, or by compromising the OAuth
provider), they can log in as the linked Calibre-Web user with no password
needed.
2026-04-14 22:28:06 +02:00
jvoisin c451daad3c Don't allow users to edit shelves they don't have permission to edit. 2026-04-14 22:25:36 +02:00
jvoisin 224915bba1 Prevent XXE in epub/fb2/goodreads API
The lxml.etree.fromstring() function use the default XML parser, which resolves
external entities because XML handling defaults in Python sucks. There is no
need for such dangerous misfeatures in calibre-web, so let's disable it.

A user able to upload epub/fb2 could add something like this to the file:

```xml
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<container><rootfiles><rootfile full-path="&xxe;"/></rootfiles></container>
```

and obtain the content of the `/etc/passwd` file, which is bad™.
2026-04-14 22:12:57 +02:00
jvoisin d598054195 Fix an IDOR in kobo tokens
Authenticated users shouldn't be able to generate/delete kobo auth tokens for
other users if they're not admin.
2026-04-14 22:10:30 +02:00
Ozzie Isaacs 088778969d Better error handling on series display in basic view 2026-04-06 15:28:10 +02:00