From be888e2bd8b87dd3c5d1fb58085c9a677a307921 Mon Sep 17 00:00:00 2001 From: aloui ikram Date: Fri, 10 Jul 2026 14:55:51 +0100 Subject: [PATCH 1/3] docs: Adopt GitHub Private Vulnerability Reporting Workflow Implements the reference version of goharbor/community#292 on harbor-next: - SECURITY.md: supported-versions table, concrete response targets (ack 3 business days, triage 7 days, critical fix 14 business days, disclosure within 90 days), reporter expectations (advisory collaboration, CVE, credit), fallback for reporters without a GitHub account, and a known-CVE deflection rule. - docs/security-process.md: maintainer runbook covering intake, triage with CVSS severity ladder, embargoed fix in a temporary private fork, in-band CVE request via GitHub as CNA, coordinated disclosure, release-note conventions, and a per-advisory checklist. - .github/ISSUE_TEMPLATE/bug_report.yml: warning at the top telling reporters not to file security vulnerabilities as public issues. - .github/workflows/codeql.yml: CodeQL scanning for Go and TypeScript (build-mode none, security-extended queries). - .typos.toml: allow the CNA acronym. Signed-off-by: aloui ikram --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 + .github/workflows/codeql.yml | 52 +++++++++++ .typos.toml | 2 + SECURITY.md | 47 +++++++--- docs/security-process.md | 122 ++++++++++++++++++++++++++ 5 files changed, 215 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/codeql.yml create mode 100644 docs/security-process.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1d282d51aa..415496c01e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -8,6 +8,8 @@ body: value: | Thanks for taking the time to fill out this bug report! + **If this is a security vulnerability, do NOT file a public issue.** Report it privately via [GitHub private vulnerability reporting](https://github.com/container-registry/harbor-next/security/advisories/new). See [SECURITY.md](https://github.com/container-registry/harbor-next/blob/main/SECURITY.md) for the full disclosure policy. + **Before submitting**, please search [existing issues](https://github.com/container-registry/harbor-next/issues) to avoid duplicates. - type: textarea diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..089b16ece4 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,52 @@ +# CodeQL static analysis for the Go backend and the Angular/TypeScript portal. +# Results appear under Security -> Code scanning. +# build-mode: none scans Go without compiling, so no toolchain setup is needed. + +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '25 3 * * 2' + +permissions: read-all + +concurrency: + group: codeql-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + permissions: + security-events: write + + strategy: + fail-fast: false + matrix: + include: + - language: go + build-mode: none + - language: javascript-typescript + build-mode: none + + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + queries: security-extended + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + with: + category: "/language:${{ matrix.language }}" diff --git a/.typos.toml b/.typos.toml index 243920871c..799e5a65b2 100644 --- a/.typos.toml +++ b/.typos.toml @@ -22,6 +22,8 @@ intoto = "intoto" # Common Go abbreviations referenced in docs cfg = "cfg" ctx = "ctx" +# Security terminology (CVE Numbering Authority) +CNA = "CNA" [files] extend-exclude = [ diff --git a/SECURITY.md b/SECURITY.md index 3713a69008..138a379d1e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,18 +6,29 @@ Harbor Next is maintained independently from the upstream `goharbor/harbor` proj ## Supported Versions -Security fixes are provided for actively maintained Harbor Next releases. If you are unsure whether a version is supported, report the issue anyway and include the affected version, commit, image tag, and deployment details. Maintainers will determine affected versions and whether backports are feasible based on severity and release status. +| Version | Supported | +| ------- | --------- | +| Latest stable release line (currently `2.15.x`) | Yes — security fixes and patch releases | +| `main` (next release) | Yes — fixes land here first | +| Older release lines | No — best effort only, for Critical issues | + +If you are unsure whether a version is supported, report the issue anyway and include the affected version, commit, image tag, and deployment details. Maintainers will determine affected versions and whether backports are feasible based on severity and release status. ## Reporting a Vulnerability **Do not open a public GitHub issue for security vulnerabilities.** -Report vulnerabilities privately through either of these GitHub flows: +Report vulnerabilities privately through GitHub private vulnerability reporting: + +- Open a private vulnerability report directly at [Report a vulnerability](https://github.com/container-registry/harbor-next/security/advisories/new). +- Or go to the repository **Security** tab and click **Report a vulnerability**. +- Or go to [New Issue](https://github.com/container-registry/harbor-next/issues/new/choose) and select **Security Vulnerability**, which routes to the same private form. + +Reporting requires a GitHub account. If you cannot use GitHub, contact a maintainer listed in [OWNERS.md](OWNERS.md) through any private channel and ask them to open the report on your behalf. -- Open a private vulnerability report directly at [New GitHub Security Advisory](https://github.com/container-registry/harbor-next/security/advisories/new). -- Go to [New Issue](https://github.com/container-registry/harbor-next/issues/new/choose) and select **Security Vulnerability**. The option is labeled **Report Security Vulnerabilities privately** and routes to the private GitHub Security Advisory flow. +Private vulnerability reports are visible only to project maintainers, who will coordinate with the reporter during investigation and remediation. The maintainer-side handling process is documented in [docs/security-process.md](docs/security-process.md). -Private vulnerability reports are visible to project maintainers, who will coordinate with the reporter during investigation and remediation. +**If the vulnerability already has a public CVE or is already publicly disclosed** (for example, a scanner finding in one of our dependencies), open a normal [public issue](https://github.com/container-registry/harbor-next/issues/new/choose) instead — there is nothing left to keep private. ## What to Include @@ -40,17 +51,33 @@ Report privately when: - You believe Harbor Next has a potential security vulnerability. - You suspect a vulnerability but are unsure whether it impacts Harbor Next. -- You know of a publicly disclosed vulnerability that may affect Harbor Next or one of its dependencies. +- You know of a not-yet-public vulnerability in a dependency that may affect Harbor Next. For non-security bugs, feature requests, and proposals, use the public [GitHub issue templates](https://github.com/container-registry/harbor-next/issues/new/choose). -## Response and Disclosure +## Response Targets + +| Step | Target | +| ---- | ------ | +| Acknowledge your report | Within **3 business days** | +| Triage decision (accepted / declined) and initial severity | Within **7 calendar days** | +| Status updates while a fix is in progress | At least every **14 days** | +| Fix and advisory for **Critical** issues | Within **14 business days** of triage | +| Coordinated public disclosure | Within **90 days** of the report, or earlier once a fix is released | + +These are targets, not guarantees. Complex issues can take longer; if a vulnerability is already public or actively exploited, maintainers may disclose and ship a fix faster. + +## What Reporters Can Expect -Maintainers aim to acknowledge private vulnerability reports within 3 business days. The project will investigate the report, determine impact and severity, identify mitigations or workarounds when available, and coordinate a fix. +- Your report is handled through a private GitHub security advisory. You are added as a collaborator on the advisory and can follow and participate in the discussion and the fix. +- Maintainers score severity with CVSS (using the advisory's built-in calculator) and share the assessment with you. +- For confirmed vulnerabilities, maintainers request a **CVE** through GitHub inside the advisory. +- You receive **credit** in the published advisory unless you prefer to stay anonymous. +- If the report is declined, maintainers will explain the reason and may ask that it be re-filed as a public issue if appropriate. -If the issue is confirmed, maintainers will coordinate public disclosure with the reporter after a mitigation or patch is available, unless the vulnerability is already public or active exploitation requires faster disclosure. Public disclosure is normally published through [GitHub Security Advisories](https://github.com/container-registry/harbor-next/security/advisories). +## Disclosure Policy -If the report is not considered a security vulnerability, maintainers will explain the reason and may ask that it be re-filed as a public issue if appropriate. +Maintainers coordinate public disclosure with the reporter after a mitigation or patch is available. Public disclosure happens through [GitHub Security Advisories](https://github.com/container-registry/harbor-next/security/advisories), the release notes of the fixed release, and the CVE record. Fixes for embargoed issues are developed in a temporary private fork and are not visible in the public repository until the advisory is published. ## Security Priorities diff --git a/docs/security-process.md b/docs/security-process.md new file mode 100644 index 0000000000..5ccc2ea814 --- /dev/null +++ b/docs/security-process.md @@ -0,0 +1,122 @@ +# Security Response Process (Maintainer Runbook) + +This document describes how Harbor Next maintainers handle private vulnerability reports, from intake to public disclosure. The reporter-facing policy is [SECURITY.md](../SECURITY.md). + +The whole process happens inside **one GitHub artifact**: the private report becomes the draft security advisory, the fix is developed in the advisory's temporary private fork, the CVE is requested inside the advisory, and publishing the advisory is the disclosure. Nothing is re-transcribed between systems. + +This process follows the workflow proposed for upstream Harbor in [goharbor/community#292](https://github.com/goharbor/community/pull/292). Harbor Next acts as the reference implementation. + +## Roles + +- **Security responders**: maintainers with admin access to the repository, or members of a GitHub team with the **security manager** role on the org. They see incoming private reports and receive notifications for them. +- **Advisory lead**: the responder who accepts a report. They own the advisory through publication: triage, severity, fix coordination, CVE request, and disclosure. + +Every incoming report needs exactly one advisory lead. If you accept a report, you are the lead until you explicitly hand it over. + +## 1. Receiving a report + +Reports arrive at **Security → Advisories** as `Proposed` advisories: + +Notifications for new private reports go to repo admins and org security managers only. **Check the queue at least weekly** even if you saw no notification. + +Within **3 business days** of a report arriving: + +1. Reply in the advisory thread to acknowledge receipt. The reporter can see comments on the advisory; nothing else is needed to keep them informed. +2. Do a first sanity check: + - **Spam or clearly invalid** → close the report with a short explanation. Anyone with a GitHub account can file, so expect noise; closing politely and quickly is part of the job. + - **Already public** (existing CVE, public scanner finding, already-disclosed dependency issue) → ask the reporter to re-file as a public issue and close the report. + - **Dependency vulnerability, not exploitable in Harbor Next** → treat as a normal dependency update (Dependabot / `zero-cve` workflow), not a Harbor Next advisory. Explain and close. + - **Wrong repo** (e.g. an upstream `goharbor/harbor` issue that does not affect Harbor Next code) → point the reporter to the right project's security policy and close. + - **Plausible product vulnerability** → continue to triage. + +## 2. Triage + +Within **7 calendar days** of the report: + +1. Reproduce the issue, or establish why reproduction isn't needed (e.g. obvious by code inspection). Ask the reporter for missing details in the advisory thread. +2. If confirmed, click **Accept and open as draft**. The report converts into a draft security advisory — same object, no copying. +3. Fill in the draft advisory fields: + - **Affected products/versions**: ecosystem, package, affected version ranges, and patched versions (fill patched versions in once known). + - **CWE** classification. + - **Severity**: use the built-in **CVSS calculator** (v3.1 or v4.0). Score it yourself; do not just accept the reporter's score, but do share and discuss your assessment with them. +4. If declined, explain why in the thread and close the advisory. + +Severity drives urgency: + +| CVSS | Severity | Handling | +| ---- | -------- | -------- | +| 9.0–10.0 | Critical | Drop other work. Fix + advisory target: **14 business days**. Patch release for the supported release line. | +| 7.0–8.9 | High | Fix in the next patch release; target within 30 days. | +| 4.0–6.9 | Medium | Fix in a regular upcoming release. | +| 0.1–3.9 | Low | Fix opportunistically; may be handled as a public issue after agreeing with the reporter. | + +While a fix is in progress, post a status update in the advisory thread at least every **14 days** — the reporter has no other visibility into progress. + +## 3. Embargoed fix (temporary private fork) + +Do **not** develop the fix in the public repository. Public commits, branches, or PRs leak the vulnerability before disclosure. + +1. In the draft advisory, click **Start a temporary private fork**. GitHub creates `harbor-next-ghsa-xxxx-xxxx-xxxx`, visible only to advisory collaborators. +2. Add collaborators as needed via the advisory's collaborator list. The reporter is already a collaborator; add only the maintainers actually working the fix. Access is scoped to this one advisory and cleaned up automatically. +3. Develop and review the fix as PRs inside the private fork. Keep the commit message neutral — it becomes public on disclosure, but should not read as a public spoiler if seen early. +4. **CI does not run on private forks.** Run the test suite locally (`task test:quick`, `task test:ci`) and record in the advisory thread what was run and the results. Do not merge an untested fix. +5. Do not merge the private fork's PR into the public repo until publication time (step 6). + +## 4. CVE request + +For confirmed vulnerabilities in Harbor Next code: + +1. In the draft advisory, choose **Request CVE**. GitHub (acting as CNA) reviews the request, usually within **72 hours**, and reserves a CVE ID bound to the advisory. The CVE is published to MITRE only when the advisory is published. +2. If the affected component is covered by another CNA (e.g. the vulnerability is really in a vendored/upstream component), GitHub may decline; coordinate with that component's security team instead and reference their CVE in our advisory. +3. Vulnerabilities inherited from upstream `goharbor/harbor` normally get their CVE through upstream's process; our advisory then references the upstream CVE rather than requesting a new one. + +## 5. Pre-disclosure coordination + +1. Agree on a disclosure date with the reporter in the advisory thread. Default: as soon as the fixed release is available; at most **90 days** from the report. +2. Prepare the patch release: the fix will need to land on `main` and be backported to the supported `release-X.Y` branch (see [SECURITY.md](../SECURITY.md) supported versions). +3. If the issue affects known downstream distributors or operators, notify them under embargo before publication (currently ad hoc — see "Open items" below). +4. Prefer publishing on a **weekday, not Friday**, so operators can respond during working hours. + +## 6. Publish and release + +Order matters — the fix must be available when the advisory goes public: + +1. Merge the fix from the temporary private fork (the advisory's **Merge pull request** flow pushes the commits to the public repo). +2. Cut the patch release(s) through the normal release process. Release notes must mention the advisory: `Fixes GHSA-xxxx-xxxx-xxxx (CVE-YYYY-NNNNN)` with severity and a one-line description — no exploit details beyond the advisory. +3. Fill in the advisory's **patched versions** field. +4. Add **credits**: the reporter (with the appropriate role, e.g. *reporter* / *analyst*), who must accept the credit for it to display. Ask first if they want anonymity. +5. Click **Publish advisory**. This makes the advisory public, publishes the CVE to MITRE, and submits it to the GitHub Advisory Database (review can take up to 72h; Dependabot alerts then reach downstream Go-module consumers). +6. The temporary private fork is deleted automatically after publication. + +Note: Dependabot alerts only reach consumers of Harbor Next **Go modules**, not users running container images. Image users learn about the fix from the advisory, the release notes, and the registry tags — which is why step 2's release-note convention is mandatory. + +## 7. After disclosure + +- Verify the advisory appears under [published advisories](https://github.com/container-registry/harbor-next/security/advisories) and the CVE record is live. +- Post-mortem (optional but encouraged for High/Critical): what allowed the bug, whether a test/linter/scanner could catch the class, and file follow-up issues. +- If the issue also affects upstream `goharbor/harbor`, make sure upstream's security team was informed **before** our disclosure, not after. + +## Checklist (copy into the advisory thread) + +```text +- [ ] Acknowledged reporter (≤3 business days) +- [ ] Triaged: reproduced / declined (≤7 days) +- [ ] Accepted as draft advisory; CWE + CVSS filled in +- [ ] Temporary private fork created; collaborators scoped +- [ ] Fix developed + reviewed in private fork +- [ ] Tests run locally, results recorded (no CI on private forks!) +- [ ] CVE requested via GitHub +- [ ] Disclosure date agreed with reporter +- [ ] Backport(s) prepared for supported release line(s) +- [ ] Release notes reference GHSA/CVE +- [ ] Credits added and accepted +- [ ] Advisory published; patched versions filled in +- [ ] Upstream goharbor/harbor informed (if affected) +``` + +## Open items (need org-level decisions) + +- **Security responder roster**: create a GitHub team with the org **security manager** role instead of relying on repo admins, so the roster is explicit and auditable. +- **Distributor/operator embargo list**: upstream Harbor uses `cncf-harbor-distributors-announce`; Harbor Next has no equivalent yet. Decide if/when one is needed. +- **Fallback intake for reporters without a GitHub account**: currently "contact a maintainer privately"; a dedicated alias would be cleaner. +- **security.txt**: publish `/.well-known/security.txt` on the project website pointing at the GitHub report form (requires a website/domain decision, plus a yearly `Expires` refresh). From cef37c90cbefaf974d8502e74bd965248518f87f Mon Sep 17 00:00:00 2001 From: aloui ikram Date: Sun, 19 Jul 2026 17:56:06 +0100 Subject: [PATCH 2/3] ci: Fix CodeQL Go Build Mode, Job Permissions, And Typos Key - Go does not support build-mode none (fails on CodeQL 2.26.1); use autobuild for Go, keep none for JS/TS. - Job-level permissions override workflow read-all: add actions: read and contents: read alongside security-events: write. - typos lowercases words before dictionary lookup: extend-words key must be lowercase (cna). Signed-off-by: aloui ikram --- .github/workflows/codeql.yml | 6 ++++-- .typos.toml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 089b16ece4..b8bac8149f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,6 +1,6 @@ # CodeQL static analysis for the Go backend and the Angular/TypeScript portal. # Results appear under Security -> Code scanning. -# build-mode: none scans Go without compiling, so no toolchain setup is needed. +# Go requires a build for analysis (autobuild); JS/TS is scanned without one. name: CodeQL @@ -23,6 +23,8 @@ jobs: name: Analyze (${{ matrix.language }}) runs-on: ubuntu-latest permissions: + actions: read + contents: read security-events: write strategy: @@ -30,7 +32,7 @@ jobs: matrix: include: - language: go - build-mode: none + build-mode: autobuild - language: javascript-typescript build-mode: none diff --git a/.typos.toml b/.typos.toml index 799e5a65b2..cd714a8975 100644 --- a/.typos.toml +++ b/.typos.toml @@ -23,7 +23,7 @@ intoto = "intoto" cfg = "cfg" ctx = "ctx" # Security terminology (CVE Numbering Authority) -CNA = "CNA" +cna = "CNA" [files] extend-exclude = [ From cfdcc0c66f8bbfad4c6d8454b059de2d7f6d095b Mon Sep 17 00:00:00 2001 From: aloui ikram Date: Sun, 19 Jul 2026 18:08:59 +0100 Subject: [PATCH 3/3] ci: Revert Typos Key To Uppercase CNA The lowercase key made typos treat cna as a typo with correction CNA, flagging every legitimate CNA occurrence (error: CNA should be CNA). The uppercase form passed CI on the first run; restore it. Signed-off-by: aloui ikram --- .typos.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.typos.toml b/.typos.toml index cd714a8975..799e5a65b2 100644 --- a/.typos.toml +++ b/.typos.toml @@ -23,7 +23,7 @@ intoto = "intoto" cfg = "cfg" ctx = "ctx" # Security terminology (CVE Numbering Authority) -cna = "CNA" +CNA = "CNA" [files] extend-exclude = [