Files
Public Source Publisher 72c93e51fb
Public source validation / verify (push) Successful in 1m20s
CertScope: update dependencies and deployment and CI (+2 areas)
Public changes compared with the previous published export:
4 files changed.

Affected areas:
- dependencies: 1 file
- deployment and CI: 1 file
- documentation: 1 file
- scripts: 1 file

Changed files:
- Added: ".gitea/workflows/ci.yml"
- Updated: "SECURITY.md"
- Updated: "package-lock.json"
- Added: "scripts/audit-dependencies.mjs"

Export provenance/manifests refreshed; excluded from the change summary.

Publish curated CertScope source from 9cd536d4e2dd485794e5f5accd70220de4a081de
2026-10-09 01:10:53 +00:00

37 lines
6.4 KiB
Markdown

# Security policy
CertScope is intentionally a bounded single-host inspector, not a network scanner or a general-purpose fetch proxy.
## Security boundaries
- Input is one normalized DNS hostname. URLs, credentials, IP literals and malformed hostnames are rejected; Unicode names are converted to their ASCII IDN form before policy checks.
- A and AAAA resolution is performed before connection. Every answer is validated as public unicast before any candidate is attempted. If one family fails, the other safe family can continue as partial evidence; if no safe address exists, inspection stops.
- HTTP and HTTPS use only ports 80 and 443. Redirects are restricted to HTTP(S), revalidated and re-resolved for every hop, limited to three hops, and policy-rejected targets are surfaced as evidence without a request. HTTPS-to-HTTP downgrade is explicitly blocked.
- Redirect evidence redacts URL userinfo before it is returned or exported; the raw redirect is only used transiently to enforce the credential policy.
- HTTP and TLS connect directly to the validated IP address while preserving the normalized hostname for the Host header and TLS SNI. This avoids a later unchecked hostname resolution in the connect path and keeps DNS-rebinding/TOCTOU exposure bounded to the individual validated attempt.
- DNS, TLS and HTTP use aggregate deadlines, not only per-hop timers. Address fallback is bounded and records failed candidates without unbounded retries. HTTP response bodies are discarded after headers are captured.
- The unauthenticated inspect endpoint has four in-process inspection slots and a 30-request/60-second process-local fair-use window. Forwarded identity is only honored with `CERTSCOPE_TRUST_PROXY=true`; otherwise the conservative direct-client bucket is used. This is not a replacement for access control at a public edge.
- Partial collector failures are typed evidence and return a report where possible; they are not fabricated missing findings and do not receive a score deduction for unavailable evidence.
- API input/policy failures are `400`, no-resolution failures are `422`, capacity/fair-use failures are `429`, and unexpected application failures are generic `500` responses. Unexpected logs contain only an error class and optional code, never the hostname, response body or stack trace.
- The app sets baseline browser security headers: CSP, frame denial, `nosniff`, strict referrer policy, permissions policy and CORP. COOP is deliberately not emitted: this documented HTTP-only self-hosted endpoint cannot enforce it and Chromium records it as an ignored-header console error. The CSP retains `unsafe-inline` for Next.js static/RSC bootstrap compatibility. Next.js documents nonce-based CSP as a dynamic-rendering/middleware integration; this compact static/standalone app does not add that architectural cost without a tested end-to-end nonce pipeline. HSTS is not forced on the app because the documented self-hosted endpoint may be served over plain HTTP behind an external TLS terminator.
- The production container uses a pinned Node Alpine base, Next standalone runtime artifacts, a non-root user, no-new-privileges, dropped capabilities, a read-only filesystem, bounded `/tmp` and resource limits.
- The application has no accounts, database, background workers, shell execution, arbitrary fetch endpoint or AI dependency.
## Header semantics
The HTTP diagnostics evaluate values, not just presence. HSTS requires one valid non-negative `max-age`; zero is disabled, under one day is weak, and less than one year is short-lived. CSP follows first-directive-wins semantics for duplicates and evaluates broad sources by directive: a script `data:` source is materially different from an image `data:` source. The parser intentionally reports only reliable posture observations; it is not a full CSP validator. `X-Content-Type-Options` must equal `nosniff` case-insensitively. Referrer-Policy comma fallback lists use the last browser-recognized policy; unknown fallback tokens do not invalidate an otherwise supported policy. A restrictive CSP `frame-ancestors` policy is accepted as clickjacking protection equivalent to `X-Frame-Options`, while scheme-wide and wildcard sources are weak. The typed aggregate reports healthy controls, attention required or incomplete evidence without turning a partial collector into a missing control. SPF analysis only evaluates the visible terminal `all` qualifier and never follows `include` chains. Malformed certificate validity windows and malformed MX answers are surfaced as evidence-backed warnings; they are not silently treated as healthy.
## Dependencies and release hygiene
`package-lock.json` is authoritative. CI and Docker use `npm ci`, CI runs production-only and full npm audits, the production image is built and scanned for high/critical OS and library vulnerabilities, and a production CycloneDX SBOM is uploaded as a build artifact. Workflow actions are pinned to immutable commit SHAs and the Docker base is pinned to a registry manifest digest. Dependency and base-image updates are deliberate changes followed by the full validation suite.
### Temporary dev-tooling advisory exception — 2026-10-05
The production dependency audit remains strict and must contain no high or critical findings. The full development graph currently contains exactly one upstream advisory, `GHSA-vfj7-8cjw-p6xm`, through `eslint-config-next -> @next/eslint-plugin-next -> fast-glob -> micromatch -> braces@3.0.3`. As of 2026-10-05 upstream has not published a patched `braces` release; npm's proposed remediation is a semver-major downgrade of `eslint-config-next` to 14.2.35, which is not compatible with CertScope's reviewed Next.js 16.3.8 toolchain.
CI therefore uses `scripts/audit-dependencies.mjs` as a fail-closed exception: it accepts only the exact five-node high-severity finding set, the exact advisory identifier/range, the reviewed package versions and dependency chain above. Any additional finding, changed severity/range/advisory, dependency-version drift, changed remediation, malformed audit output, or production audit finding fails CI. The exception must be removed or revised as soon as upstream publishes a compatible patched release.
## Reporting issues
Do not include live credentials, private keys or confidential internal hostnames in a report. Provide a minimal reproduction using public or synthetic targets. Security fixes must preserve the public-address and redirect policy and include an offline regression test.