diff --git a/.github/SECURITY.md b/.github/SECURITY.md
new file mode 100644
index 0000000..d3035c3
--- /dev/null
+++ b/.github/SECURITY.md
@@ -0,0 +1,52 @@
+# Security policy
+
+release-creator is a command-line tool that validates news fragments, links them to pull requests and authors, renders
+changelog sections into GitHub Release notes, and checks published JetBrains plugin archives. This policy says how to
+report a security problem and how we decide whether a report is one.
+
+## Reporting a vulnerability
+
+**Do not open a public issue for a security problem.** Use
+[GitHub's private vulnerability reporting](https://github.com/tox-dev/release-creator/security/advisories/new). If
+neither works for you, email [gaborjbernat@gmail.com](mailto:gaborjbernat@gmail.com).
+
+Include what the attacker controls and what they gain, the steps or a proof of concept, and the versions and platform
+you tested. Write the report yourself; unreviewed tool or model output takes longer to triage.
+
+## What to expect
+
+Volunteers maintain release-creator, with no on-call rotation. We aim to acknowledge a report within **5 working days**
+and assess it within **15 working days**. Fixes are developed in a private fork attached to the draft advisory, ship in
+a new release, and the advisory, with a CVE requested through GitHub, goes out with that release. The default embargo is
+**90 days** from the report; we agree any change with the reporter. We credit reporters in the advisory under the name
+they choose, or not at all. There is no bug bounty.
+
+## Supported versions
+
+Only the latest release receives fixes. Confirm the problem reproduces on it before reporting.
+
+## Vulnerability or bug
+
+A report is a vulnerability when an attacker who controls only an input that the [threat model](THREAT_MODEL.md) lists
+as untrusted breaks a guarantee release-creator makes. A report that first needs control of something the threat model
+trusts, such as the repository's Git history, the GitHub API answers `gh` returns, or the caller's options, is a bug: we
+fix it in the open and publish no advisory. Classify by who supplies the dangerous input, not by how bad the outcome
+sounds.
+
+**In scope**
+
+- A fragment from a pull request passing `validate-news` while it carries a hand-written author credit or pull request
+ link, so release notes credit or link someone the history does not show.
+- Fragment or changelog text breaking out of its section in rendered notes, for example to add a fake `New Contributors`
+ or `Full Changelog` entry.
+- A plugin ZIP comparison reporting a match when member contents, types or permissions differ.
+- Data from Git or GitHub reaching a GraphQL query or a command as anything but data.
+
+**Out of scope**
+
+- The wording of a fragment: maintainers review it before it merges, as they review code.
+- The token `gh` uses and what that token may do.
+- Mentions in rendered notes that GitHub turns into notifications.
+- Correctness of `towncrier` itself.
+
+If you cannot tell which side a finding falls on, report it privately and we will decide.
diff --git a/.github/THREAT_MODEL.md b/.github/THREAT_MODEL.md
new file mode 100644
index 0000000..bcea3a1
--- /dev/null
+++ b/.github/THREAT_MODEL.md
@@ -0,0 +1,102 @@
+# Threat model
+
+This model says what release-creator trusts, where untrusted input enters, and which guarantees hold at each boundary,
+so a report can be classified as a vulnerability or a bug. [SECURITY.md](SECURITY.md) covers reporting; if the two
+disagree, SECURITY.md wins and we fix this file.
+
+## How release-creator works
+
+In a pull request, `validate-news` checks each changed fragment against the Towncrier categories and rejects
+hand-written credits and pull request links. When a release is prepared, `fragments` finds each fragment's squash-merged
+pull request through `git log` and `gh api graphql`, writes the link and the commit authors, and Towncrier builds the
+changelog. `notes` renders one tagged changelog section into a GitHub Release body with package and comparison links.
+`marketplace` downloads a published JetBrains plugin and compares its members, by SHA-256, type and permissions, with
+the local archive. The `anchors`, `changelog`, `contributors` and `tags` commands add Markdown anchors, preview the
+changelog, look up contributors and calculate tags from the same trusted history. Every command runs `git` and `gh` with
+argument lists, never a shell.
+
+```mermaid
+flowchart LR
+ pr[("PR fragments
(untrusted until merged)")] -->|"validate-news"| rc["release-creator"]
+ git[("Git history
(trusted)")] --> rc
+ gh["gh api graphql
(trusted answers)"] --> rc
+ rc -->|"links, credits"| cl[("Changelog")]
+ cl -->|"notes"| body["GitHub Release body"]
+ mk[("Marketplace ZIP")] -->|"marketplace"| rc
+ classDef trusted fill:#cfe4ff,stroke:#1f6feb,color:#0b1f3a;
+ classDef boundary fill:#ffe3a3,stroke:#d29200,color:#3a2c00;
+ class git,gh,rc trusted;
+ class pr,cl,body,mk boundary;
+```
+
+## Compared with similar tools
+
+We drew the boundary where comparable projects in other ecosystems draw theirs. The shared rule, stated by the
+[Node.js threat model](https://github.com/nodejs/node/blob/main/SECURITY.md#the-nodejs-threat-model), is that a report
+which first needs a trusted element compromised is out of scope; the first triage question, as
+[DOMPurify](https://github.com/cure53/DOMPurify/blob/main/SECURITY.md#what-we-consider-a-vulnerability) puts it, is what
+the attacker controls.
+
+| Project | Language | Where it draws the line |
+| ------------------------------------------------------------------------------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
+| [GoReleaser](https://github.com/goreleaser/goreleaser/security/policy) | Go | Release automation; in scope is anything that compromises the confidentiality, integrity or availability of GoReleaser or its users. |
+| [release-please](https://github.com/googleapis/release-please/security/policy) | TypeScript | Changelog and release PR automation; reports go through Google's vulnerability intake. |
+| [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator/security/policy) | GitHub Actions | Reusable workflows that hold signing identity; help tuning a caller's workflow is not a vulnerability. |
+| [Towncrier](https://github.com/twisted/towncrier) | Python | Builds the changelog from fragments release-creator validated; it follows the Twisted project's security process. |
+
+## Trusted
+
+An attacker who controls any of these already has what release-creator could give them:
+
+- The repository's Git history and the merged changelog.
+- Answers from the GitHub API through `gh`, and the token it uses.
+- The command-line options, including the repository, tag and artifact URLs.
+
+## Untrusted inputs
+
+| Input | Comes from | What release-creator guarantees |
+| ---------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------- |
+| Fragments in a pull request | Any contributor | Category, name and content are validated; hand-written credits and pull request links are rejected. |
+| A downloaded Marketplace ZIP | The Marketplace, after recompression | Members are hashed in 1 MiB chunks; duplicate member names are rejected. |
+
+## Threats and controls
+
+| STRIDE | Threat | Control |
+| --------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
+| Spoofing | A fragment credits a maintainer for a contribution they did not make. | Credits come from the merge commit's authors; hand-written ones fail validation. |
+| Tampering | Changelog text forges a section in the release body. | Report any text that escapes its section. |
+| Tampering | A GraphQL query is altered by repository data. | Owner and name are JSON-encoded; commit SHAs come from `git`. |
+
+## Release chain
+
+Releases run on the shared [tox-dev/github-workflows](https://github.com/tox-dev/github-workflows) pipeline. A release
+App, not a person, pushes the release commit and tag; the build installs its tools from a hash-checked `pylock.toml`
+resolved with a seven-day upload cooldown by default; PyPI receives the files through
+[trusted publishing](https://docs.pypi.org/trusted-publishers/) with attestations, and the GitHub Release is immutable.
+Every workflow pins third-party actions to a commit SHA.
+
+## Vulnerability or bug
+
+| Report | Verdict | Why |
+| ---------------------------------------------------------- | ------------------- | -------------------------------------- |
+| A PR fragment with `by @maintainer` passes `validate-news` | Vulnerability | Hand-written credits must be rejected. |
+| A merged fragment says something misleading | Not a vulnerability | Maintainers reviewed and merged it. |
+| The ZIP check passes although a member's mode changed | Vulnerability | Comparison must cover mode. |
+| `notes` mis-renders a nested list | Bug | Rendering only. |
+
+## Severity
+
+- **High:** pull request data reaches a shell, a GraphQL query or a command as code, or the plugin ZIP comparison
+ reports a match for differing contents, types or permissions.
+- **Medium:** a fragment with a hand-written credit or link passes `validate-news`, or fragment text forges a section of
+ the rendered notes.
+- **Low:** a crash on unusual history or changelog text instead of a clean error.
+
+## Accepted risks
+
+- Release notes mention GitHub users, and GitHub may notify them.
+
+## Keeping this current
+
+Revisit this model when release-creator gains a new input source, network access, a new way to run code, or a new place
+it writes to, and whenever an advisory is published.