Files
CertScope-Public/SECURITY.md
T
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

6.4 KiB

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.