Skip to content

fix: validate TLS certificates on the native browser network path - #34791

Open
cacieprins wants to merge 5 commits into
developfrom
claude/cypress-34760-remediation-0e5e75
Open

fix: validate TLS certificates on the native browser network path#34791
cacieprins wants to merge 5 commits into
developfrom
claude/cypress-34760-remediation-0e5e75

Conversation

@cacieprins

@cacieprins cacieprins commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Additional details

Root cause. Cypress launches every Chromium browser with --ignore-certificate-errors. When the certificate an origin presents actually errors — a self-signed development certificate, an internal CA, or Cypress's own MITM CA on the legacy path — Chrome treats the connection like a clicked-through certificate warning and, by design, never writes anything from it to the HTTP disk cache. On the Cypress 16 default (native browser network) path this made the cache inert for any HTTPS app with an untrusted certificate: every navigation re-downloaded every static asset. This is independent of CDP interception, which the issue originally blamed; that was refuted empirically across Chrome 148–152 and the issue has been rewritten with the corrected root cause.

The fix, scoped to the native browser network path (Chrome, Chromium, Edge — not forceHttp1, Electron, Firefox, or WebKit, which are unchanged):

  • A new trustedCertificates configuration option lets users declare a certificate their app presents, as { filePath }, { pem }, or a precomputed { spki } fingerprint. Each entry's SubjectPublicKeyInfo fingerprint is passed to Chrome via --ignore-certificate-errors-spki-list. Chrome honors that list over the blanket flag, so the connection becomes genuinely trusted — and therefore cacheable — rather than merely tolerated. Chrome matches the fingerprint against any certificate in the chain the server presents, so one leaf or CA fingerprint suffices.
  • The blanket --ignore-certificate-errors is kept. The change is purely additive: origins you don't declare load exactly as they do today (just uncached, as before); origins you do declare gain a working browser cache.
  • Verified on real Chrome by inspecting the browser's disk cache directly after a run: the origin's assets are present when the certificate is declared and absent when it is not.

Why the blanket flag stays (for now). A stricter variant that dropped --ignore-certificate-errors on this path was evaluated in CI. It broke real self-signed HTTPS setups on the netstack beyond caching: Chrome refuses service-worker registration on a page with a genuine certificate error, and cross-origin navigation to a hosts-mapped self-signed origin timed out (service_worker_spec, web_security_spec). Those are user-visible breaks for a common local-dev configuration and don't belong in a patch release. With the allow-mechanism now in place, tightening the blanket flag can be a deliberate, documented change in a major version.

Why there is no disk-cache system test. The cache benefit is unobservable from a Cypress system test: Cypress's other launch flags load invalid certificates regardless of trust, so navigation success is not a signal; a repeat visit within a spec is served by the renderer's in-memory cache even when the disk cache is broken; and the browser cache is reset between specs. The included system test therefore guards the config → SPKI → launch plumbing end to end on real Chrome and says so explicitly. The cache behavior itself is covered by direct disk inspection and by the lower-level verification recorded on the issue.

Also in this PR: the system-test fixtures are TypeScript (a .cy.ts fixture spec requires a tsconfig.json, added), and AGENTS.md records the "TypeScript for all new code" convention.


Note

Medium Risk
Touches browser launch flags and TLS trust on the default Chromium network path; misconfiguration could affect which origins are trusted, though behavior is additive and scoped to declared certificates.

Overview
Adds trustedCertificates so Chromium browsers on the native (CDP) network path can treat selected dev/self-signed certs as genuinely trusted, restoring HTTP disk caching for those HTTPS origins instead of only tolerating cert errors via --ignore-certificate-errors.

Each entry is exactly one of { filePath }, { pem }, or { spki }; config validation, TypeScript types, and defaults are wired through @packages/config. At launch, entries are resolved to deduped SPKI fingerprints (packages/server/lib/util/spki.ts) and passed on the browser path as --ignore-certificate-errors-spki-list=… alongside the existing blanket ignore flag; the MITM/forceHttp1 path is unchanged.

16.0.1 changelog documents the fix (#34760). A Chrome-only system-test fixture exercises config → SPKI → launch plumbing. AGENTS.md notes TypeScript for new fixtures and a system-test snapshot pruning gotcha.

Reviewed by Cursor Bugbot for commit 6e5a8f1. Bugbot is set up for automated code reviews on this repo. Configure here.

Steps to test

Unit coverage (validation, SPKI derivation, launch-flag gating):

cd packages/server && yarn test-unit util/spki_spec.ts
cd packages/server && yarn test-unit browsers/chrome_spec.ts
yarn workspace @packages/config test

End-to-end on real Chrome (a self-signed HTTPS origin whose leaf certificate is declared in trustedCertificates):

cd system-tests && env -u ELECTRON_RUN_AS_NODE yarn test trusted_certificates --browser chrome

Manual, to see the cache effect: run an e2e project on Chrome against an HTTPS origin with a self-signed certificate. Without trustedCertificates the page loads, but nothing from that origin appears in the browser's disk cache. Add trustedCertificates: [{ filePath: 'certs/server.pem' }] (relative to the project root) and the origin's assets are cached and served from disk on later navigations. Confirm the launch args: --ignore-certificate-errors is still present, and --ignore-certificate-errors-spki-list=<fingerprint> is added alongside it.

How has the user experience changed?

No visual change. Behavioral: purely additive. On Chrome, Chromium, and Edge without forceHttp1, static assets from an origin whose certificate is declared in the new trustedCertificates option are now cached across navigations, so asset-heavy specs against such origins stop re-downloading everything on each cy.visit. Origins that are not declared behave exactly as before.

PR Tasks

  • Is there an associated issue with maintainer approval for PR submission?
  • Have tests been added/updated?
  • Has a PR for user-facing changes been opened in cypress-documentation? To follow — the new trustedCertificates option needs documenting.
  • Have API changes been updated in the type definitions?

🤖 Generated with Claude Code

cacieprins and others added 3 commits September 4, 2026 10:13
On the CDP netstack (Chrome, Chromium, Edge), Cypress no longer passes
the blanket --ignore-certificate-errors flag, which silently accepted
invalid certificates and, as a side effect, prevented the browser from
caching static assets across navigations. The browser now validates
certificates as it does in production.

Adds a `trustedCertificates` config option so users can declare a
self-signed or private-CA certificate their app under test presents;
each entry's SubjectPublicKeyInfo fingerprint is passed to Chrome via
--ignore-certificate-errors-spki-list. Firefox, WebKit, Electron, and
forceHttp1 runs are unaffected and keep the legacy behavior.

Addresses #34760.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…wser network path

Exercises the end-to-end plumbing on Chrome: a self-signed HTTPS origin
whose leaf certificate is declared in `trustedCertificates` loads because
its SPKI fingerprint reaches Chrome via --ignore-certificate-errors-spki-list,
with the blanket --ignore-certificate-errors no longer passed.

Deliberately does not assert the disk-cache behavior the feature restores,
which is unobservable from a system test: Cypress's security-reducing
launch flags load invalid certs regardless of trust, the same-renderer
memory cache masks the disk cache within a spec, and the browser cache is
reset between specs. That behavior is covered by lower-level verification.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the .js fixture config and spec with cypress.config.ts (a plain
export default, since lightweight fixtures have no node_modules to resolve
`cypress` from) and a .cy.ts spec, and adds the tsconfig.json a .cy.ts
fixture requires — the batteries-included preprocessor throws
TsConfigNotFoundError without one (house precedent: projects/ts-proj).

Records the "TypeScript for all new code" convention in AGENTS.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…stedCertificates is additive

Dropping the blanket flag on the native browser network path broke real
self-signed HTTPS setups beyond caching: Chrome refuses service-worker
registration on a page with a genuine certificate error, and cross-origin
navigation to a hosts-mapped self-signed origin timed out
(system-tests-chrome: service_worker_spec, web_security_spec). Those are
user-visible breaks for a common local-dev configuration.

The blanket flag now stays. `trustedCertificates` layers an
--ignore-certificate-errors-spki-list on top; Chrome honors that list over
the blanket flag, so a declared cert's origin is genuinely trusted and its
assets cache, while undeclared origins behave exactly as before. Tightening
the blanket flag can be a deliberate change in a major version.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 552a243. Configure here.

Comment thread system-tests/__snapshots__/web_security_spec.js
Running `yarn test web_security --browser chrome` locally let snap-shot-it
prune the Firefox-gated snapshot key from __snapshots__/web_security_spec.js,
and it was swept into the previous commit. CI then failed the Firefox test
with "Cannot store new snapshot value". Restores the file from develop and
records the gotcha in system-tests/AGENTS.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cypress

cypress Bot commented Sep 4, 2026

Copy link
Copy Markdown

cypress    Run #74310

Run Properties:  status check passed Passed #74310  •  git commit 6e5a8f13d5: chore: restore web_security snapshots pruned by a local system-test run
Project cypress
Branch Review claude/cypress-34760-remediation-0e5e75
Run status status check passed Passed #74310
Run duration 15m 42s
Commit git commit 6e5a8f13d5: chore: restore web_security snapshots pruned by a local system-test run
Committer Cacie Prins
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 13
Tests that did not run due to a developer annotating a test with .skip  Pending 1118
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 29197
View all changes introduced in this branch ↗︎
UI Coverage  68.06%
  Untested elements 23  
  Tested elements 49  
Accessibility  98.96%
  Failed rules  0 critical   3 serious   2 moderate   0 minor
  Failed elements 18  

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: an ignored certificate error disables the browser HTTP cache — every navigation re-downloads all static assets

1 participant