diff --git a/.github/actions/scan-app/action.yml b/.github/actions/scan-app/action.yml new file mode 100644 index 000000000..f4c9d5e74 --- /dev/null +++ b/.github/actions/scan-app/action.yml @@ -0,0 +1,41 @@ +name: Scan Application +description: Scans the Dangerzone application code for vulnerabilities +inputs: + path: + description: Path to scan + required: true + default: "." + severity-cutoff: + description: Severity cutoff for the scan + required: false + default: critical + upload-sarif: + description: Whether to upload the SARIF report + required: false + default: false + sarif-category: + description: Category for the SARIF report + required: false +runs: + using: composite + steps: + - name: Scan application + uses: anchore/scan-action@v7 + id: scan + with: + path: ${{ inputs.path }} + fail-build: true + only-fixed: false + severity-cutoff: ${{ inputs.severity-cutoff }} + + - name: Upload application scan report + if: ${{ inputs.upload-sarif && !cancelled() }} + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: ${{ steps.scan.outputs.sarif }} + category: ${{ inputs.sarif-category }} + + - name: Inspect application scan report + if: always() + shell: bash + run: cat ${{ steps.scan.outputs.sarif }} diff --git a/.github/actions/scan-container/action.yml b/.github/actions/scan-container/action.yml new file mode 100644 index 000000000..82cce396f --- /dev/null +++ b/.github/actions/scan-container/action.yml @@ -0,0 +1,40 @@ +name: Scan Container +description: Scans a Dangerzone container image for vulnerabilities +inputs: + image: + description: Image to scan + required: true + severity-cutoff: + description: Severity cutoff for the scan + required: false + default: critical + upload-sarif: + description: Whether to upload the SARIF report + required: false + default: false + sarif-category: + description: Category for the SARIF report + required: false +runs: + using: composite + steps: + - name: Scan container image + uses: anchore/scan-action@v7 + id: scan + with: + image: ${{ inputs.image }} + fail-build: true + only-fixed: false + severity-cutoff: ${{ inputs.severity-cutoff }} + + - name: Upload container scan report + if: ${{ inputs.upload-sarif && !cancelled() }} + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: ${{ steps.scan.outputs.sarif }} + category: ${{ inputs.sarif-category }} + + - name: Inspect container scan report + if: always() + shell: bash + run: cat ${{ steps.scan.outputs.sarif }} diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 4cc0dc360..cf8b0b896 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -34,28 +34,17 @@ jobs: --debian-archive-date $(date "+%Y%m%d") \ --runtime docker docker load -i share/container.tar + - name: Get image tag id: tag run: echo "tag=$(cat share/image-id.txt)" >> $GITHUB_OUTPUT - # NOTE: Scan first without failing, else we won't be able to read the scan - # report. - - name: Scan container image (no fail) - uses: anchore/scan-action@v7 - id: scan_container - with: - image: "ghcr.io/freedomofpress/dangerzone/v1:${{ steps.tag.outputs.tag }}" - fail-build: false - only-fixed: false - severity-cutoff: critical - - name: Inspect container scan report - run: cat ${{ steps.scan_container.outputs.sarif }} - - name: Scan container image - uses: anchore/scan-action@v7 + + - name: Scan container + uses: ./.github/actions/scan-container with: image: "ghcr.io/freedomofpress/dangerzone/v1:${{ steps.tag.outputs.tag }}" - fail-build: true - only-fixed: false severity-cutoff: critical + upload-sarif: false security-scan-app: strategy: @@ -67,22 +56,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v6 - # NOTE: Scan first without failing, else we won't be able to read the scan - # report. - - name: Scan application (no fail) - uses: anchore/scan-action@v7 - id: scan_app - with: - path: "." - fail-build: false - only-fixed: false - severity-cutoff: critical - - name: Inspect application scan report - run: cat ${{ steps.scan_app.outputs.sarif }} + - name: Scan application - uses: anchore/scan-action@v7 + uses: ./.github/actions/scan-app with: - path: "." - fail-build: true - only-fixed: false severity-cutoff: critical + upload-sarif: false diff --git a/.github/workflows/scan_released.yml b/.github/workflows/scan_released.yml index 71f983d77..4aaeb10b2 100644 --- a/.github/workflows/scan_released.yml +++ b/.github/workflows/scan_released.yml @@ -4,6 +4,11 @@ on: - cron: '0 0 * * *' # Run every day at 00:00 UTC. workflow_dispatch: +env: + # Severity cutoff is 'critical' by default, except for the 5th and 20th of + # month (i.e., biweekly), where we turn it to 'high'. + SEVERITY_CUTOFF: ${{ github.event_name == 'schedule' && (github.triggering_actor == 'schedule' && (format('{0}', github.event.schedule) == '0 0 5 * *' || format('{0}', github.event.schedule) == '0 0 20 * *')) && 'high' || 'critical' }} + jobs: security-scan-container: strategy: @@ -17,30 +22,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@v6 - # NOTE: Scan first without failing, else we won't be able to read the scan - # report. - - name: Scan container image (no fail) - uses: anchore/scan-action@v7 - id: scan_container - with: - image: "ghcr.io/freedomofpress/dangerzone/v1:latest" - fail-build: false - only-fixed: false - severity-cutoff: critical - - name: Upload container scan report - uses: github/codeql-action/upload-sarif@v4 - with: - sarif_file: ${{ steps.scan_container.outputs.sarif }} - category: container-${{ matrix.arch }} - - name: Inspect container scan report - run: cat ${{ steps.scan_container.outputs.sarif }} - - name: Scan container image - uses: anchore/scan-action@v7 + + - name: Scan container + uses: ./.github/actions/scan-container with: image: "ghcr.io/freedomofpress/dangerzone/v1:latest" - fail-build: true - only-fixed: false - severity-cutoff: critical + severity-cutoff: ${{ env.SEVERITY_CUTOFF }} + upload-sarif: true + sarif-category: container-${{ matrix.arch }} security-scan-app: strategy: @@ -54,35 +43,23 @@ jobs: uses: actions/checkout@v6 with: fetch-depth: 0 + - name: Checkout the latest released tag run: | # Grab the latest Grype ignore list before git checkout overwrites it. cp .grype.yaml .grype.yaml.new + # Grab the scan code for the GitHub action. + cp -r .github/actions/scan-app .github/actions/scan-app.new VERSION=$(curl https://api.github.com/repos/freedomofpress/dangerzone/releases/latest | jq -r '.tag_name') git checkout $VERSION # Restore the newest Grype ignore list. mv .grype.yaml.new .grype.yaml - # NOTE: Scan first without failing, else we won't be able to read the scan - # report. - - name: Scan application (no fail) - uses: anchore/scan-action@v7 - id: scan_app - with: - path: "." - fail-build: false - only-fixed: false - severity-cutoff: critical - - name: Upload application scan report - uses: github/codeql-action/upload-sarif@v4 - with: - sarif_file: ${{ steps.scan_app.outputs.sarif }} - category: app - - name: Inspect application scan report - run: cat ${{ steps.scan_app.outputs.sarif }} + # Restore the GHA action. + mv .github/actions/scan-app.new .github/actions/scan-app + - name: Scan application - uses: anchore/scan-action@v7 + uses: ./.github/actions/scan-app with: - path: "." - fail-build: true - only-fixed: false - severity-cutoff: critical + severity-cutoff: ${{ env.SEVERITY_CUTOFF }} + upload-sarif: true + sarif-category: app diff --git a/CHANGELOG.md b/CHANGELOG.md index a99bbb03a..35fc07d71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,19 +15,21 @@ since 0.4.1, and this project adheres to [Semantic Versioning](https://semver.or ### Added -- Dangerzone is able to function without a bundled `container.tar` file +- Dangerzone is able to function without a bundled `container.tar` file ([#1400](https://github.com/freedomofpress/dangerzone/pull/1400)) - Look for desktop entries in `XDG_DATA_DIRS` paths on Linux ([#1413](https://github.com/freedomofpress/dangerzone/issues/1413)) - It is now possible to convert another set of documents after a first batch ([#549](https://github.com/freedomofpress/dangerzone/issues/549)) -- OCR tasks are now queued, resulting in up to x6 speedup +- OCR tasks are now queued, resulting in up to x6 speedup ([#1329](https://github.com/freedomofpress/dangerzone/issues/1329)) - +- Add a security policy for our project + ([#1278](https://github.com/freedomofpress/dangerzone/issues/1278)) ### Development changes - Run macOS Intel CI tests only on scheduled/manual runs to reduce PR CI time ([#1338](https://github.com/freedomofpress/dangerzone/issues/1338)) - +- Set the severity cutoff of our code scans from Critical to High, on a biweekly basis + ([#1438](https://github.com/freedomofpress/dangerzone/issues/1438)) ## [0.10.0](https://github.com/freedomofpress/dangerzone/compare/v0.10.0...0.9.1) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..b7e1f3dde --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,60 @@ +# Security Policy + +The Dangerzone team welcomes feedback from security researchers and the general +public to help improve our security. If you believe you have discovered a +security issue, we want to hear from you. This policy outlines steps for +reporting vulnerabilities to us, what we expect, what you can expect from us. + +## Reporting a vulnerability + +**Please do not report security vulnerabilities through public GitHub issues.** + +Our preferred communication channels are: +* **Signal:** TKTK. +* **Email:** support@dangerzone.rocks. + +A member of our team should acknowledge your report **within 2 weeks**. If we +fail to do so, please use a different communication channel. + +Once we have acknowledged the report, we ask for **at least 6 weeks** to +investigate, implement, and release a fix before any public disclosure, unless +we mutually agree on a different timeline. During that time we will keep you +updated as we make progress, and we will be available for any question you may +have. If we determine that a coordinated public disclosure is necessary before a +fix is ready, we will work with you on messaging and timing. + +## What's in scope + +Dangerzone has two main security goals: +* Malicious documents should not infect the user's device, or communicate with + other machines. +* All metadata should be destroyed after the conversion process. + +Any vulnerability that undermines these two goals **is considered critical** and +we advise you to report it via Signal. Other vulnerabilt + +### About CVEs in our container image + +Dangerzone uses several third-party tools to sanitize documents, such as +[LibreOffice](https://www.libreoffice.org/) and [PyMuPDF](https://pymupdf.io/). +Because these tools have a large attack surface, Dangerzone operates under the +assumption that a 0-day vulnerability probably exists for them. For this reason, +Dangerzone's primary defense is to isolate these tools within unprivileged, +networkless containers using [gVisor](https://gvisor.dev/). Read more in +[our blog](https://dangerzone.rocks/news/2024-09-23-gvisor/). + +Our second line of defense is to make sure our container image is not affected +by known vulnerabilities, i.e., CVEs. We have nightly security scans for +Critical CVEs, and biweekly security scans for High CVEs. We aim for a 4 week +update cadence of our container image, or earlier, if a security finding +necessitates it. + +If you have encountered a CVE in our container image that violates the above +policy, please report it to us. + +## Security Advisories + +When necessary, we have [issued CVEs](https://github.com/freedomofpress/dangerzone/security/advisories) +for Dangerzone and [security advisories](https://github.com/freedomofpress/dangerzone/tree/main/docs/advisories) +to our users. We are committed to transparency and will continue to issue +CVEs and security advisories whenever a finding warrants it.