Skip to content

Security: manderse21/claude-powershell-lsp

SECURITY.md

Security Policy

How to report a security vulnerability in powershell-lsp, what is in scope, and what to expect after you report. For the full trust and supply-chain posture (downloads, pinned hashes, SBOM, provenance, signing status, allow-listing), see TRUST.md.

Supported versions

Security fixes are issued for the latest released version only. This is a single-maintainer project (see TRUST.md); backporting to older releases is not promised. Upgrade to the latest release to receive security fixes.

Version Supported
Latest release (1.x) Yes
Any earlier release No (please upgrade)

Reporting a vulnerability

Please do NOT open a public GitHub issue for a security vulnerability. Public issues disclose the problem before a fix is available.

Report privately through GitHub Private Vulnerability Reporting, which is enabled on this repository:

When you report, please include as much as you can:

  • a description of the vulnerability and its impact;
  • the affected version (and platform / PowerShell host, if relevant);
  • step-by-step reproduction, a proof-of-concept, or the offending code path;
  • any suggested remediation.

Scope

In scope -- the code in this repository and what it does at runtime:

  • the plugin hook scripts (scripts/*.ps1) and shared library (scripts/lib/*.ps1);
  • the first-run bootstrap: the download, SHA-256 verification, and vendoring of the pinned dependencies (ensure-pses.ps1, ensure-pssa.ps1);
  • the per-session daemon, its named-pipe IPC, and the diagnostics surface;
  • the release tooling (SBOM generation, provenance) under release/.

Out of scope -- report these to their own projects:

  • PowerShell Editor Services and PSScriptAnalyzer themselves (Microsoft open-source dependencies this plugin downloads). Report upstream: PowerShellEditorServices and PSScriptAnalyzer. A flaw in how this plugin downloads, verifies, or invokes them is in scope; a flaw inside them is not.
  • Claude Code itself and its plugin/hook mechanism. Report to the claude-code project.
  • Findings that require an already-compromised local machine or administrator access (the plugin runs with the user's own privileges and trusts the local environment).

What to expect

  • Acknowledgement: best-effort within 7 days. This is a solo-maintained project, so response is best-effort, not a contractual SLA.
  • Triage and fix: once confirmed, a fix is prioritized over feature work. The timeline depends on severity and complexity; we will keep you updated in the private advisory.
  • Disclosure: we prefer coordinated disclosure -- we will agree on a disclosure date with you, publish the fix in a release, and credit you in the advisory and CHANGELOG unless you ask to remain anonymous.
  • No bug bounty: there is no monetary reward program. Credit and our thanks are what we can offer.

How a fix reaches you

The section above is what a reporter can expect. This section is the other half: how a confirmed fix actually ships. The acknowledgement window and the coordinated-disclosure posture are the ones stated under What to expect above -- they are not restated here.

A security fix takes the normal release path, and is not exempt from any gate. There is no expedited lane that skips validation, because the checks that would be skipped are the ones that keep a hurried fix from shipping broken:

  1. The fix is a pull request, like any other change, and must be green on the four CI legs (windows-pwsh, windows-powershell, ubuntu-pwsh, macos-pwsh). Those four are required status checks on main, so this is enforced rather than intended.
  2. The release runs the pipeline's six gates -- merged to main, tag free, version lockstep, CI green on every leg, tree-vs-published parity, and a rehearsal dry run on the same commit. Each refuses rather than proceeds. The gates are documented in docs/RELEASING.md.
  3. The fix ships as a new release, not a backport -- see Supported versions above.
  4. Then the advisory is published, with credit in the advisory and the CHANGELOG unless you asked to stay anonymous.

The two recorded bypasses, named rather than hidden. Neither is a security shortcut, and both leave a permanent trace:

  • skip_dry_check=true bypasses the dry-run gate and logs SKIPPED-BY-INPUT on the run forever (docs/RELEASING.md).
  • The manual fallback exists only for a broken pipeline, and a hand-cut release is unsigned and carries no provenance -- it cannot produce the keyless artifacts that need the workflow's server-issued OIDC identity (docs/RELEASING.md).

What limits this in practice. Triage, fix, review, and release all rest on one maintainer (see MAINTAINERS.md and CONTINUITY.md). That is the real constraint on response time -- not the pipeline, which is fast once a fix exists. It is stated here so the timeline above is read as best-effort by a solo maintainer rather than as a staffed on-call rotation.

Verifying release integrity

Every tagged release is produced by this repository's gated release pipeline, which publishes a SLSA v1.0 build-provenance attestation over the release archive. The attestation is signed through GitHub's OIDC identity (Sigstore keyless) -- there is no maintainer-held signing key to leak or compromise -- so anyone can verify a release independently with the GitHub CLI.

1. Download the release archive for the version you want:

gh release download v1.17.0 --repo manderse21/claude-powershell-lsp --pattern "*.tar.gz"

2. Verify its build provenance:

gh attestation verify powershell-lsp-1.17.0.tar.gz --repo manderse21/claude-powershell-lsp

gh fetches the attestation from GitHub, checks the archive's SHA-256 digest against it, and enforces that the signing identity is this repository's release workflow. On success it prints Verification succeeded! and exits 0; on any mismatch -- a tampered byte, the wrong repository, an unexpected workflow -- it exits non-zero and the archive should not be trusted.

The real v1.17.0 verification confirmed the following (abbreviated and illustrative -- not gh's exact console layout):

Verification succeeded!
  predicate type   https://slsa.dev/provenance/v1
  OIDC issuer      https://token.actions.githubusercontent.com
  build / signer   .github/workflows/powershell-lsp-release.yml@refs/heads/main
  subject digest   sha256:bfb2ba3f0c165f6c538682dc605e3ae5433f88a7eeef7950957805b4ee23c339

A successful check proves the archive was built by this repository's release workflow (workflow identity), is byte-identical to what was signed (the digest match), and carries SLSA v1.0 build provenance -- with no maintainer-held key anywhere in the trust path.

What the attestation does and does not cover

This is build provenance and integrity over the downloadable source archive: it proves the published powershell-lsp-<version>.tar.gz came untampered from this repository's pipeline. It is deliberately not Windows Authenticode and does not assert a Windows verified-publisher identity -- there is no SmartScreen reputation and no signed-script guarantee, because the plugin is distributed by git clone, not as a signed Windows binary. The integrity of the normal /plugin install path therefore rests on the git commit and tag themselves, not on the archive attestation.

This boundary is intentional and matches the maintainer-facing release process. See docs/RELEASING.md for what the provenance covers, and TRUST.md for the SBOM, the pinned dependency hashes, and the current (pending -- not signed) code-signing status.

There aren't any published security advisories