Files
FabledCurator/SECURITY.md
T
bvandeusenandClaude Opus 5 dbc4e8b0c6
CI / lint (push) Successful in 2s
CI / extension-version (push) Successful in 3s
Build images / sign-extension (push) Successful in 4s
Build images / build-ml (push) Successful in 6s
Build images / build-agent (push) Successful in 8s
Build images / build-web (push) Successful in 7s
CI / frontend-build (push) Successful in 20s
CI / backend-lint-and-test (push) Successful in 31s
CI / integration (push) Successful in 3m52s
docs: AGPL-3.0, plus SECURITY and CONTRIBUTING (#3269)
The repo had no LICENSE, which meant all rights reserved by default:
nobody could legally run or modify it, and "public availability" was a
contradiction no amount of install documentation could fix. This is the
hard blocker in milestone 328; everything else in it is quality.

AGPL-3.0, at the operator's explicit choice, for the reason the operator
gave: this should not become something another party runs as a hosted
proprietary service. Section 13 is what makes it fit — for a self-hosted
web app, distribution otherwise never happens, so the GPL's obligation
would never actually bite. AGPL reaches the case that matters here:
running a MODIFIED copy as a service for others.

LICENSE is the FSF text fetched from gnu.org and verified byte-identical
(34,523 bytes, 661 lines, §13 "Remote Network Interaction" present), not
retyped. README's old "Personal project; use at your own discretion" said
nothing legally and is replaced with what the licence actually asks —
including the part worth being clear about, that running an unmodified
copy for yourself carries no obligation whatsoever.

SECURITY.md names what this software actually holds, because that is what
makes a report serious here: live third-party session cookies for
accounts with payment methods attached, the extension API key, the
multi-user sharing ACL, and arbitrary downloaded media that gets decoded
and fed to models. It also states the plain-HTTP posture up front, so
"served over HTTP" and "no HSTS" are understood as the documented design
rather than filed as findings.

There is no private disclosure channel yet, so the reporting instruction
is to open an issue containing NOTHING but the fact that a report exists,
and wait for a private contact. Awkward on purpose: an issue tracker is
public the moment it is written to, and every self-hosted instance stays
vulnerable until its operator can update. Worth replacing with a real
contact address — that decision is the operator's, since it publishes one.

CONTRIBUTING records the two things that actually catch people: ruff's
order-by-type import sorting, and that a model change and its migration
belong in the same commit. The second is not style — the models and the
chain silently diverged for a long time (#3275) and autogenerate was
unsafe as a result.

Pre-publication scan, since the repo is about to get attention:
.env.example is placeholders only (`changeme_*`), `.env` is gitignored
with an `!.env.example` exception, no credential-shaped literals are
committed, and there are no private IPs or operator home paths. The only
hostnames are the project's own forge, which is public by design.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017QHszn9H8VBvx5Ke8x1hvw
2026-08-31 14:53:06 -04:00

2.9 KiB

Security Policy

Reporting a vulnerability

Please do not put vulnerability details in a public issue.

This project has no private disclosure channel yet. Until it does, open an issue on the repository that says only that you have a security report — no reproduction steps, no affected endpoint, no payload — and a maintainer will reply with a private contact to send the details to.

That is a deliberately awkward first step, and it exists because the alternative is worse: an issue tracker is public the moment it is written to, and every self-hosted instance stays vulnerable until its operator has had a chance to update.

Please include, once you have a private channel:

  • what an attacker can do, and what access they need to start
  • the version or commit you tested
  • reproduction steps

Scope — what this software actually handles

FabledCurator is self-hosted and holds things worth stating plainly, because they shape what counts as a serious bug here:

  • Platform credentials. The app captures and stores session cookies for third-party subscription sites (Patreon, SubscribeStar, Pixiv) so it can download on the operator's behalf. These are live credentials for accounts that usually carry a payment method. Anything that discloses them, decrypts them, or lets one user of a shared instance read another's is high severity.
  • An extension API key. The Firefox extension authenticates to the backend with a shared key. Anything that leaks it or lets it be bypassed is a way in.
  • A multi-user sharing ACL. Instances can be shared. A bug that lets one account see content another has not shared is an access-control failure, not a cosmetic one.
  • Arbitrary media from the internet. Downloaded files are decoded, hashed, thumbnailed and fed to ML models. Anything that turns a hostile file into code execution is in scope.

Deployment posture — read this before reporting

FabledCurator is designed to run inside a private network, over plain HTTP. It does not terminate TLS, redirect to HTTPS, or set HSTS; if you want transport security, terminate it at your reverse proxy. This is a documented design decision, not an oversight.

Reports that reduce to "the application is served over HTTP" or "there is no HSTS header" describe that decision rather than a vulnerability. Reports that an authenticated operator can cause the software to do something destructive are usually also by design — the operator is the administrator of their own instance.

What remains in scope is everything that crosses a boundary the software is supposed to hold: between one user and another, between an unauthenticated visitor and any of it, and between untrusted downloaded content and the host.

Supported versions

Fixes land on the main branch and reach the :latest image. There are no maintained release branches — the supported version is the current one, and the remedy for a security issue is to update.