You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: SECURITY.md
+11-18Lines changed: 11 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,7 +34,7 @@ You can expect an acknowledgement within 48 hours and a resolution or status upd
34
34
| Adversary | Goal | Primary controls |
35
35
|---|---|---|
36
36
| Malicious paste / shared link | Trigger XSS via crafted SAML or JWT content rendered in the DOM | Svelte's default text escaping, `esc()` in the XML highlighter, CSP (`default-src 'self'`, no `unsafe-inline`, hash-pinned inline scripts) |
37
-
| Compromised npm package | Inject malicious code into the build or CI environment | GuardDog, OSV-Scanner, Grype, `npm audit`, SHA-pinned actions, `npm ci` lockfile enforcement |
37
+
| Compromised npm package | Inject malicious code into the build or CI environment | GuardDog, `npm audit`, Grype, Dependency Review, SHA-pinned actions, `npm ci` lockfile enforcement |
38
38
| Compromised upstream GitHub Action | Substitute malicious CI code via a tampered version tag | All actions pinned to commit SHA, Dependabot rotates pins daily |
39
39
| SSRF via OIDC proxy | Use the discovery Worker to reach internal infrastructure |`redirect: 'error'`, 5-second timeout, 100 KB cap, response validation |
40
40
| Compromised maintainer account | Push unsigned or unreviewed code to `main`| Required commit signatures, branch protection, CODEOWNERS review, scoped API tokens |
@@ -137,7 +137,6 @@ Current pins in `.github/workflows/ci.yml`:
@@ -160,13 +159,9 @@ Dependabot is configured to open daily PRs when new versions of these actions ar
160
159
161
160
### Minimal token permissions
162
161
163
-
All workflows use explicit `permissions` blocks rather than relying on GitHub's write-all default. The CI workflow sets the following at the workflow level, which serves as the baseline for all jobs:
162
+
All workflows use explicit `permissions` blocks rather than relying on GitHub's write-all default. The CI workflow sets `contents: read` at the workflow levelas the baseline for all jobs.
164
163
165
-
-`actions: read` — required for the OSV-Scanner reusable workflow (GitHub constrains reusable workflow callers: the calling workflow must include any permissions granted to the called workflow)
166
-
-`contents: read`
167
-
-`security-events: write` — required for SARIF upload to GitHub Code Scanning across multiple jobs; also needed at workflow level for the OSV-Scanner reusable workflow call
168
-
169
-
Individual jobs override this baseline to the minimum they require. The deploy job additionally requests `deployments: write` (Cloudflare Pages action), `id-token: write` (OIDC for sigstore attestation), and `attestations: write` (GitHub attestation API). No job can write to the repository, create issues, or make API calls beyond what is explicitly declared.
164
+
Individual jobs add only what they require — the `GuardDog Supply Chain Scan` and `SBOM & Grype Scan` jobs each request `security-events: write` for their own SARIF upload. The deploy job additionally requests `deployments: write` (Cloudflare Pages action), `id-token: write` (OIDC for sigstore attestation), and `attestations: write` (GitHub attestation API). No job can write to the repository, create issues, or make API calls beyond what is explicitly declared.
170
165
171
166
### No secrets in PR workflows
172
167
@@ -180,7 +175,9 @@ The deploy job targets a GitHub Environment named `production`. This provides a
180
175
181
176
### Dependency auditing
182
177
183
-
The CI workflow runs `npm audit --audit-level=moderate` on every push and pull request. The build fails if any moderate, high, or critical vulnerabilities are present in the transitive dependency tree. Dependencies are installed with `npm ci` (not `npm install`), which installs exactly what is recorded in `package-lock.json` and fails if there is any discrepancy — preventing lockfile drift and ensuring reproducible installs.
178
+
`npm audit --audit-level=moderate` runs in a dedicated `Dependency Audit` job that fails the build if any moderate, high, or critical vulnerability is present anywhere in the transitive dependency tree. This job runs on push to `main`, on a weekly schedule (Mondays 06:00 UTC), and on manual dispatch — but **not** on pull requests. The rationale: a freshly-published advisory in build/test tooling that a PR never touched should not block every open pull request at once. Pull requests are vulnerability-gated by Dependency Review (scoped to the dependencies the diff introduces) and GuardDog; Dependabot alerts and auto-PRs drive remediation; and the push-to-`main` run still gates the production deploy, so deploy protection is unchanged.
179
+
180
+
Dependencies are installed with `npm ci` (not `npm install`), which installs exactly what is recorded in `package-lock.json` and fails if there is any discrepancy — preventing lockfile drift and ensuring reproducible installs.
184
181
185
182
### Secret scanning
186
183
@@ -208,25 +205,21 @@ A CodeQL workflow runs on every push and pull request to `main`, and weekly on M
208
205
209
206
GuardDog runs entirely within the CI runner — no data is sent to any external service. Findings are reported as SARIF and uploaded to the GitHub code scanning dashboard. The job must pass before deploy is allowed.
210
207
211
-
### OSV-Scanner
212
-
213
-
[OSV-Scanner](https://google.github.io/osv-scanner/) (Google, Apache 2.0) runs on every push and pull request via Google's official reusable workflow. It queries the [Open Source Vulnerabilities](https://osv.dev) database, which aggregates CVE, GitHub Security Advisories (GHSA), and OSV records — a broader set of sources than npm's advisory feed alone. Findings are automatically uploaded to the GitHub code scanning dashboard as SARIF. The job must pass before deploy is allowed.
214
-
215
208
### SBOM and Grype
216
209
217
-
On every pushand pull request:
210
+
Alongside the `Dependency Audit` job (push, weekly schedule, and manual dispatch — not pull requests):
218
211
219
212
-**Syft** ([anchore/sbom-action](https://github.com/anchore/sbom-action), Apache 2.0) generates a Software Bill of Materials in SPDX-JSON format and uploads it as a workflow artifact. This provides an auditable inventory of every package in the build and supports compliance requirements that expect a machine-readable SBOM.
220
213
221
-
-**Grype** ([anchore/scan-action](https://github.com/anchore/scan-action), Apache 2.0) scans the Syft-generated SBOM for known vulnerabilities at medium severity or higher. Findings are uploaded to the GitHub code scanning dashboard as SARIF. The job must pass before deploy is allowed.
214
+
-**Grype** ([anchore/scan-action](https://github.com/anchore/scan-action), Apache 2.0) scans the Syft-generated SBOM for known vulnerabilities at medium severity or higher and uploads findings to the GitHub code scanning dashboard as SARIF. Grype runs in non-blocking mode (`fail-build: false`): `npm audit` in the `Dependency Audit` job is the single blocking CVE gate, while Grype contributes a second, independent vulnerability database to the Security tab.
222
215
223
216
### Dependency Review
224
217
225
-
The [dependency-review-action](https://github.com/actions/dependency-review-action) runs on pull requests only. It compares the dependency diff introduced by the PR against GitHub's vulnerability database and fails the check if any newly added package carries a moderate or higher CVE. This catches vulnerable dependencies at PR time, before they land in `main`, complementing the full-tree scans that run on push.
218
+
The [dependency-review-action](https://github.com/actions/dependency-review-action) runs on pull requests only. It compares the dependency diff introduced by the PR against GitHub's vulnerability database and fails the check if any newly added package carries a moderate or higher CVE. This is the pull-request-time vulnerability gate: it catches vulnerable dependencies a PR would *introduce*, before they land in `main`, while the full-tree `npm audit` and Grype scans run on push and the weekly schedule. A PR is therefore never blocked by a pre-existing, tree-wide advisory in a dependency the PR did not touch.
226
219
227
220
### GitHub Code Scanning
228
221
229
-
All SARIF-producing tools (CodeQL, GuardDog, OSV-Scanner, Grype, OSSF Scorecard) upload their findings to GitHub's code scanning dashboard (Security → Code scanning). This provides a single triage surface across all scanners, with per-file, per-line annotation on pull requests. Each tool registers under its own `category` so findings are de-duplicated and attributable to their source.
222
+
All SARIF-producing tools (CodeQL, GuardDog, Grype, OSSF Scorecard) upload their findings to GitHub's code scanning dashboard (Security → Code scanning). This provides a single triage surface across all scanners, with per-file, per-line annotation on pull requests. Each tool registers under its own `category` so findings are de-duplicated and attributable to their source.
230
223
231
224
### OSSF Scorecard
232
225
@@ -242,7 +235,7 @@ This means the provenance of every deployed bundle is verifiable: given the arti
242
235
243
236
The `main` branch is protected with the following rules enforced for all contributors:
244
237
245
-
-**Required status checks** — `Build & Test`, `GuardDog Supply Chain Scan`, `OSV Scanner / osv-scan`, `SBOM & Grype Scan`, and `Dependency Review` must all pass before any merge is allowed; the branch must be up to date with `main` before merging (strict mode)
238
+
-**Required status checks** — `Build & Test`, `GuardDog Supply Chain Scan`, `Dependency Review`, and `CodeQL` must all pass before any merge is allowed; the branch must be up to date with `main` before merging (strict mode). The whole-tree scans (`Dependency Audit`, `SBOM & Grype Scan`) run on push and the weekly schedule rather than on pull requests, so they are not pull-request status checks — they gate the production deploy instead
246
239
-**Required signatures** — every commit merged to `main` must carry a verified cryptographic signature
247
240
-**Required pull request review** — at least one approval is required; stale approvals are dismissed on new pushes; code owner review is required
248
241
-**No force pushes** — force-pushing to `main` is blocked
0 commit comments