From 5f65d8086a5976e289db528cf790061abb77dbed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Wed, 28 Oct 2026 00:47:58 -0700 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=93=9D=20docs(security):=20add=20a=20?= =?UTF-8?q?threat=20model=20and=20align=20the=20policy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/SECURITY.md | 54 ++++++++++++++++++++++----- .github/THREAT_MODEL.md | 81 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 .github/THREAT_MODEL.md diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 6c38e29..d58b9dc 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,13 +1,49 @@ -# Security Policy +# Security policy -## Supported Versions +PyVenvManage is a JetBrains IDE plugin that marks virtual environment folders in the project view and sets one as the +project or module interpreter on request. This policy says how to report a security problem and how we decide whether a +report is one. -| Version | Supported | -| ------- | ------------------ | -| 2.x | :white_check_mark: | -| \<2 | :x: | +## Reporting a vulnerability -## Reporting a Vulnerability +**Do not open a public issue for a security problem.** Use +[GitHub's private vulnerability reporting](https://github.com/tox-dev/PyVenvManage/security/advisories/new). If you do +not have a GitHub account, or you are a Tidelift subscriber, report through the +[Tidelift security contact](https://tidelift.com/security) instead; Tidelift coordinates the fix and the disclosure with +us. If neither works for you, email [gaborjbernat@gmail.com](mailto:gaborjbernat@gmail.com). -To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift -will coordinate the fix and disclosure. +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 PyVenvManage, 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 PyVenvManage makes. A report that first needs control of something the threat model +trusts, such as the IDE, the open project, or the user's choice of interpreter, 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** + +- The plugin setting or changing an interpreter without the user choosing the action. +- The plugin running a program while it decorates the project view; decoration reads `pyvenv.cfg` only. +- Crafted `pyvenv.cfg` content making the plugin read or write outside the environment folder. + +**Out of scope** + +- What the IDE does with an interpreter after the user selects it: indexing and running it is the IDE's behavior. +- A malicious interpreter inside a project's virtual environment the user chose to use. +- Vulnerabilities in the IntelliJ Platform or the Python plugin. + +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..e696627 --- /dev/null +++ b/.github/THREAT_MODEL.md @@ -0,0 +1,81 @@ +# Threat model + +This model says what PyVenvManage 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 PyVenvManage works + +PyVenvManage scans the project view for folders that hold a `pyvenv.cfg` and a Python executable, and decorates them +with the environment type and the Python version read from `pyvenv.cfg`. When the user right-clicks such a folder and +chooses an action, it registers that interpreter as an SDK and sets it for the project or module. It starts no process +and opens no network connection of its own. + +```mermaid +flowchart LR + user["User action
(trusted)"] --> pvm["PyVenvManage"] + proj[("Project folders,
pyvenv.cfg (untrusted)")] -->|"read version, type"| pvm + pvm -->|"register SDK, set interpreter"| ide["IDE, Python plugin"] + classDef trusted fill:#cfe4ff,stroke:#1f6feb,color:#0b1f3a; + classDef boundary fill:#ffe3a3,stroke:#d29200,color:#3a2c00; + class user,pvm,ide trusted; + class proj 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 | +| ------------------------------------------------------------------------------------------------ | --------------- | --------------------------------------------------------------------------------------------------- | +| [JetBrains project trust](https://www.jetbrains.com/help/idea/project-security.html) | Kotlin and Java | A project opened in safe mode runs no build scripts or run configurations until the user trusts it. | +| [VS Code Workspace Trust](https://code.visualstudio.com/docs/editing/workspaces/workspace-trust) | TypeScript | Extensions disable features that run workspace code until the user trusts the folder. | +| [IntelliJ Platform](https://github.com/JetBrains/intellij-community/security/policy) | Kotlin and Java | Vulnerabilities in the IDE platform itself go to JetBrains, not to plugin authors. | + +## Trusted + +An attacker who controls any of these already has what PyVenvManage could give them: + +- The user and the actions they choose. +- The IDE, the Python plugin and the SDK table. + +## Untrusted inputs + +| Input | Comes from | What PyVenvManage guarantees | +| ------------------------------ | ---------------- | ------------------------------------------------- | +| `pyvenv.cfg` and folder layout | A cloned project | Read as text to label the folder; never executed. | + +## Threats and controls + +| STRIDE | Threat | Control | +| ---------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------- | +| Tampering | A crafted `pyvenv.cfg` points the plugin outside the project. | The interpreter path comes from the folder the user clicked, not from `pyvenv.cfg`. | +| Elevation of privilege | Opening a project silently switches to a malicious interpreter. | Interpreters change only on an explicit action. | + +## Release chain + +Releases run on the shared [tox-dev/github-workflows](https://github.com/tox-dev/github-workflows) pipeline. A release +App pushes the release commit and tag, the plugin ZIP is signed before it reaches the +[JetBrains Marketplace](https://plugins.jetbrains.com/docs/marketplace/plugin-signing.html), and the immutable GitHub +Release carries the same ZIP with GitHub's release attestation. Every workflow pins third-party actions to a commit SHA. + +## Vulnerability or bug + +| Report | Verdict | Why | +| ----------------------------------------------------------------- | ------------------- | --------------------------------------- | +| Opening a project sets its `.venv` as interpreter without a click | Vulnerability | Interpreter changes need a user action. | +| The user picks a malicious `.venv` and the IDE runs it | Not a vulnerability | The user chose it. | +| A folder shows the wrong Python version | Bug | Label only. | + +## Accepted risks + +- The plugin does not consult the IDE's trusted-project state; it reads `pyvenv.cfg` in untrusted projects too. + +## Keeping this current + +Revisit this model when PyVenvManage 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. From 7b933d0db3190405f3bc1dc12a222b8ece86743c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Wed, 28 Oct 2026 07:10:11 -0700 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9D=20docs(security):=20check=20th?= =?UTF-8?q?e=20threat=20model=20against=20the=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/SECURITY.md | 4 ++-- .github/THREAT_MODEL.md | 29 ++++++++++++++++++----------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index d58b9dc..9ca680a 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -37,8 +37,8 @@ publish no advisory. Classify by who supplies the dangerous input, not by how ba **In scope** - The plugin setting or changing an interpreter without the user choosing the action. -- The plugin running a program while it decorates the project view; decoration reads `pyvenv.cfg` only. -- Crafted `pyvenv.cfg` content making the plugin read or write outside the environment folder. +- The plugin running a program while it decorates the project view; decoration only reads files. +- Crafted `pyvenv.cfg` or marker content making the plugin read or write outside the environment folder. **Out of scope** diff --git a/.github/THREAT_MODEL.md b/.github/THREAT_MODEL.md index e696627..b677582 100644 --- a/.github/THREAT_MODEL.md +++ b/.github/THREAT_MODEL.md @@ -7,9 +7,10 @@ SECURITY.md wins and we fix this file. ## How PyVenvManage works PyVenvManage scans the project view for folders that hold a `pyvenv.cfg` and a Python executable, and decorates them -with the environment type and the Python version read from `pyvenv.cfg`. When the user right-clicks such a folder and -chooses an action, it registers that interpreter as an SDK and sets it for the project or module. It starts no process -and opens no network connection of its own. +with the Python version read from `pyvenv.cfg` and an environment type guessed from markers in the folder (a +`conda-meta` directory, a Hatch `.gitignore`, the user's Poetry and Pipenv locations). When the user right-clicks such a +folder and chooses an action, it registers that folder's interpreter as an SDK and sets it for the project or module. It +starts no process and opens no network connection of its own. ```mermaid flowchart LR @@ -30,11 +31,11 @@ which first needs a trusted element compromised is out of scope; the first triag [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 | -| ------------------------------------------------------------------------------------------------ | --------------- | --------------------------------------------------------------------------------------------------- | -| [JetBrains project trust](https://www.jetbrains.com/help/idea/project-security.html) | Kotlin and Java | A project opened in safe mode runs no build scripts or run configurations until the user trusts it. | -| [VS Code Workspace Trust](https://code.visualstudio.com/docs/editing/workspaces/workspace-trust) | TypeScript | Extensions disable features that run workspace code until the user trusts the folder. | -| [IntelliJ Platform](https://github.com/JetBrains/intellij-community/security/policy) | Kotlin and Java | Vulnerabilities in the IDE platform itself go to JetBrains, not to plugin authors. | +| Project | Language | Where it draws the line | +| ------------------------------------------------------------------------------------------------ | --------------- | ---------------------------------------------------------------------------------------------------- | +| [JetBrains project trust](https://www.jetbrains.com/help/idea/project-security.html) | Kotlin and Java | A project opened in Safe Mode restricts executing code, builds and scripts until the user trusts it. | +| [VS Code Workspace Trust](https://code.visualstudio.com/docs/editing/workspaces/workspace-trust) | TypeScript | Extensions disable features that run workspace code until the user trusts the folder. | +| [IntelliJ Platform](https://github.com/JetBrains/intellij-community/security/policy) | Kotlin and Java | JetBrains' reporting policy for the platform the plugin runs on. | ## Trusted @@ -45,9 +46,9 @@ An attacker who controls any of these already has what PyVenvManage could give t ## Untrusted inputs -| Input | Comes from | What PyVenvManage guarantees | -| ------------------------------ | ---------------- | ------------------------------------------------- | -| `pyvenv.cfg` and folder layout | A cloned project | Read as text to label the folder; never executed. | +| Input | Comes from | What PyVenvManage guarantees | +| -------------------------------------------- | ---------------- | ------------------------------------------------- | +| `pyvenv.cfg`, marker files and folder layout | A cloned project | Read as text to label the folder; never executed. | ## Threats and controls @@ -71,6 +72,12 @@ Release carries the same ZIP with GitHub's release attestation. Every workflow p | The user picks a malicious `.venv` and the IDE runs it | Not a vulnerability | The user chose it. | | A folder shows the wrong Python version | Bug | Label only. | +## Severity + +- **High:** the plugin runs a program, or sets an interpreter, without the user choosing the action. +- **Medium:** crafted project content makes the plugin read or write outside the environment folder. +- **Low:** a crash or wrong label on a malformed environment folder. + ## Accepted risks - The plugin does not consult the IDE's trusted-project state; it reads `pyvenv.cfg` in untrusted projects too.