Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ In-scope components include:
- release packaging and update metadata
- archive extraction, durable storage, and process-execution boundaries
- privacy sanitization and browser-side injection defenses
- nonce, replay, transaction-idempotency, and mutation rate-limit controls
- installed runtime integrity and privacy-safe security audit verification

## Package Verification

Expand All @@ -49,6 +51,11 @@ GitHub releases also publish GitHub artifact attestations for build provenance a
the CycloneDX SBOM. Verification steps and the trust model are documented in
[`docs/security/PACKAGE_TRUST.md`](../docs/security/PACKAGE_TRUST.md).

The runtime request model is documented in
[`docs/security/REQUEST_SECURITY.md`](../docs/security/REQUEST_SECURITY.md), and
post-install verification is documented in
[`docs/security/RUNTIME_INTEGRITY.md`](../docs/security/RUNTIME_INTEGRITY.md).

Out-of-scope:

- Unraid core vulnerabilities
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Initialize CodeQL
uses: github/codeql-action/init@3b0bd1d116c0bde30213346b22d4f634d96a2fb0 # v3
uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4
with:
languages: javascript
queries: security-extended,security-and-quality

- name: Autobuild
uses: github/codeql-action/autobuild@3b0bd1d116c0bde30213346b22d4f634d96a2fb0 # v3
uses: github/codeql-action/autobuild@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@3b0bd1d116c0bde30213346b22d4f634d96a2fb0 # v3
uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4
33 changes: 33 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Dependency Review

on:
pull_request:
branches:
- dev
- main

permissions:
contents: read

concurrency:
group: folderview-plus-dependency-review-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Review dependency changes
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5
with:
fail-on-severity: high
license-check: true
allow-licenses: Apache-2.0, BSD-3-Clause, BlueOak-1.0.0, ISC, MIT, MPL-2.0
retry-on-snapshot-warnings: true
warn-only: false
52 changes: 52 additions & 0 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: OpenSSF Scorecard

on:
branch_protection_rule:
schedule:
- cron: '29 7 * * 2'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: folderview-plus-scorecard
cancel-in-progress: false

jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
actions: read
contents: read
id-token: write
security-events: write

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Run OpenSSF Scorecard
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
with:
results_file: results.sarif
results_format: sarif
publish_results: true

- name: Upload Scorecard results to code scanning
uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4
with:
sarif_file: results.sarif

- name: Retain Scorecard report
if: ${{ always() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: openssf-scorecard
path: results.sarif
if-no-files-found: error
retention-days: 5
Binary file removed archive/folderview.plus-2026.07.23.13.txz
Binary file not shown.
1 change: 0 additions & 1 deletion archive/folderview.plus-2026.07.23.13.txz.sha256

This file was deleted.

Binary file added archive/folderview.plus-2026.07.28.05.txz
Binary file not shown.
1 change: 1 addition & 0 deletions archive/folderview.plus-2026.07.28.05.txz.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
91a62bc1615c939ce7deba43247a095594c6bc7b2f09e102c11d1f779616eaf4 folderview.plus-2026.07.28.05.txz
9 changes: 8 additions & 1 deletion docs/codeql-triage.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ The baseline predates the changes on `dev`; it is retained here so alert reducti

## Enforcement

CodeQL runs for pushes and pull requests targeting both `dev` and `main`, plus the weekly scheduled scan. Repository rules require CodeQL to report no new high-or-higher security findings before a protected branch can be merged. Code-quality findings remain part of CI and triage without being mislabeled as security vulnerabilities.
CodeQL Action v4 runs for pushes and pull requests targeting both `dev` and
`main`, plus the weekly scheduled scan. Repository rules require CodeQL to report
no new high-or-higher security findings before a protected branch can be merged.
Dependency Review separately rejects pull requests that introduce high-or-critical
known vulnerabilities or licenses outside the repository's approved quality-tooling
set. OpenSSF Scorecard publishes a scheduled supply-chain posture report to code
scanning. Code-quality findings remain part of CI and triage without being
mislabeled as security vulnerabilities.

## Review Procedure

Expand Down
48 changes: 48 additions & 0 deletions docs/releases/2026.07.28.05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# FolderView Plus 2026.07.28.05

This security update adds continuous runtime assurance, replay-resistant
mutations, auditable security events, and stronger repository supply-chain
checks without exporting sensitive request or system data.

## Request and mutation security

- Security: Require short-lived, target-bound, one-time nonces for shared API
requests and reject expired, mismatched, or reused mutation authorization.
- Security: Reject replayed mutation transaction identifiers, apply bounded
endpoint-specific rate limits, and return standards-based retry guidance.
- Security: Remove the legacy GET backup-download path and route downloads
through the guarded POST request client.
- Security: Add a dedicated nonce bootstrap endpoint with explicit API-contract
metadata and fail-closed endpoint, action, content-type, and request-size
enforcement.

## Runtime integrity and diagnostics

- Security: Generate a deterministic SHA-256 runtime integrity manifest inside
every plugin package and verify expected files, permissions, and unexpected
executable content at runtime.
- Security: Record a bounded HMAC hash-chained audit trail for security decisions
using only sanitized action metadata, random trace identifiers, status, and
timestamps.
- Diagnostics: Include sanitized runtime-integrity and security-audit health in
diagnostics and support bundles without exposing payloads, names, paths,
addresses, tokens, nonces, or other private values.
- Security: Verify packaged runtime-manifest coverage and hashes during release
validation and installation smoke testing.

## Repository and supply-chain assurance

- Security: Upgrade CodeQL to the immutable v4 action and add a high-severity
dependency-review merge gate with an explicit license policy.
- Security: Add a scheduled OpenSSF Scorecard workflow that publishes SARIF
findings through GitHub code scanning with least-privilege permissions.
- Security: Require Dependency Review in managed branch-protection policy and
expand the CycloneDX SBOM to cover the complete shipped runtime and workflow
surface.
- Docs: Document mutation authorization, replay protection, rate limiting,
runtime integrity, audit privacy, package verification, and security-response
expectations.
- Test: Add functional regression coverage for nonce consumption, target
binding, replay rejection, rate limits, path confinement, audit-chain tamper
detection, runtime-manifest verification, workflow policy, and package
integrity.
28 changes: 27 additions & 1 deletion docs/sbom.cdx.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"component": {
"type": "application",
"name": "FolderView Plus",
"version": "2026.07.28.04",
"version": "2026.07.28.05",
"properties": [
{
"name": "folderview-plus:runtime-dependencies",
Expand Down Expand Up @@ -63,6 +63,19 @@
}
]
},
{
"type": "application",
"name": "actions/dependency-review-action",
"version": "a1d282b36b6f3519aa1f3fc636f609c47dddb294",
"scope": "optional",
"purl": "pkg:github/actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294",
"properties": [
{
"name": "folderview-plus:usage",
"value": "build-only-github-action"
}
]
},
{
"type": "application",
"name": "actions/setup-node",
Expand All @@ -89,6 +102,19 @@
}
]
},
{
"type": "application",
"name": "ossf/scorecard-action",
"version": "2d1146689b8cda280b9bc96326124645441f03bc",
"scope": "optional",
"purl": "pkg:github/ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc",
"properties": [
{
"name": "folderview-plus:usage",
"value": "build-only-github-action"
}
]
},
{
"type": "library",
"name": "@bcoe/v8-coverage",
Expand Down
7 changes: 7 additions & 0 deletions docs/security/PACKAGE_TRUST.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ compatible while stronger supply-chain evidence is available to administrators.
sidecar, archive filename, package version, and archive bytes to agree exactly.
- The package contains `build-metadata.json`, which records the channel, version,
source-content digest, archive URL, and icon-pack identity.
- The package contains `runtime-integrity.json`, which records SHA-256 and
expected modes for installed PHP, JavaScript, page, CSS, helper, and critical
metadata files. Diagnostics compares the installed tree with this manifest
without automatically modifying the system.
- Icon-pack installation verifies SHA-256 before a bounded archive preflight,
extracts into private staging, rejects links/special files/traversal, and
atomically activates the verified tree.
Expand Down Expand Up @@ -39,3 +43,6 @@ gh attestation verify folderview.plus-YYYY.MM.DD.UU.txz \
Unraid installation does not require the GitHub CLI and continues to use manifest
SHA-256 verification. Attestations are an additional origin/build claim for
administrators and release auditing, not a replacement for the on-system checksum.

Installed-runtime verification and recovery guidance is documented in
[`RUNTIME_INTEGRITY.md`](RUNTIME_INTEGRITY.md).
61 changes: 61 additions & 0 deletions docs/security/REQUEST_SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Request security and abuse controls

FolderView Plus layers its own request controls over the authenticated Unraid
webGUI session. These controls do not replace Unraid authentication.

## Mutation authorization

Every plugin-owned mutation must:

1. use `POST`;
2. carry the FolderView Plus request marker;
3. present the per-install request token;
4. pass same-origin `Origin` and `Referer` checks when those headers exist;
5. obtain a short-lived nonce from `security.php`;
6. bind that nonce to the target PHP endpoint and action;
7. consume the nonce exactly once;
8. present a unique transaction ID; and
9. remain within the API manifest's rate limit.

The browser request client performs nonce acquisition automatically. Mutation
retries remain disabled, so an uncertain response is reconciled from current
server state instead of replaying an operation.

The unload telemetry action is the only normal replay-protection exception. It
uses `sendBeacon`, cannot synchronously request a nonce, remains protected by the
install token and same-origin checks, and has a bounded high-volume telemetry
rate limit. Every exception must include `replayExemptReason` in
`server/api-endpoints.json`; the API contract guard rejects undocumented
exceptions.

## Rate limiting

The API manifest provides a generous default mutation budget. Restore,
delete-all, recovery, repair, and similar expensive operations use tighter
action-specific budgets. A rejected request returns HTTP 429 and `Retry-After`.
Read-only hydration is not rate limited by these mutation controls.

Ephemeral nonce, transaction, and rate state lives under
`/var/run/folderview.plus/` with private permissions. It intentionally resets on
reboot and does not write high-frequency request state to the Unraid boot device.

## Security audit chain

Authorized mutations append a bounded security event containing only:

- declared endpoint, action, and audit category;
- authorization result;
- whether replay protection applied;
- random trace and transaction IDs; and
- timestamp and chain metadata.

Names, paths, addresses, URLs, payloads, request tokens, and nonces are never
stored in this ledger. Events are HMAC chained with the protected install token.
Diagnostics reports whether the retained chain verifies but does not
automatically repair or discard a failed chain.

## Compatibility

The former unauthenticated backup-download GET route has been removed. Maintained
UI downloads use the shared request client, guarded POST, a one-time nonce, and a
Blob response.
31 changes: 31 additions & 0 deletions docs/security/RUNTIME_INTEGRITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Installed runtime integrity

Every FolderView Plus package contains `runtime-integrity.json`. The manifest is
generated after channel-specific package transformations and before archive
creation.

The manifest records SHA-256, byte size, and expected installed mode for:

- plugin page entrypoints;
- PHP endpoints and shared server libraries;
- browser runtime JavaScript;
- packaged shell/PHP helper scripts;
- plugin CSS; and
- critical runtime JSON metadata.

The manifest excludes itself and large passive asset collections. Package SHA-256
and GitHub attestations establish archive origin; the runtime manifest detects
changes after extraction.

Diagnostics compares the installed files with this manifest and reports:

- missing files;
- modified content;
- unexpected executable/runtime files;
- unreadable files; and
- changed permission modes.

Sanitized diagnostics hash finding paths. Full diagnostics can show the packaged
relative path. Integrity checking is detection-only: FolderView Plus never
silently restores, deletes, or replaces a finding. Reinstalling the same verified
package is the supported recovery action after the cause has been reviewed.
2 changes: 1 addition & 1 deletion docs/security/csp-readiness.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"mode": "report-only-shared-unraid-document",
"scope": {
"scannedRoot": "src/folderview.plus/usr/local/emhttp/plugins/folderview.plus",
"scannedFiles": 149,
"scannedFiles": 151,
"exclusions": [
"third-party icon asset pack",
"localization catalogs",
Expand Down
Loading