Skip to content

[workers-utils] Stop container key validation from crashing on malformed input - #15088

Merged
NuroDev merged 4 commits into
cloudflare:mainfrom
Neal006:fix/container-key-validation-crash
Aug 13, 2026
Merged

NuroDev merged 4 commits into
cloudflare:mainfrom
Neal006:fix/container-key-validation-crash

Conversation

@Neal006

@Neal006 Neal006 commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #15087.

Validating a containers entry pushed a type error into diagnostics and then dereferenced the value it had just rejected. Five malformed configs therefore threw a raw TypeError out of normalizeAndValidateConfig. None of them is a UserError, so handle-errors.ts printed a stack trace and "If you think this is a bug, please open an issue" instead of naming the offending key.

Three root causes, all in validateContainerApp:

  • public_key dereferenced after being rejected. if (!isRequiredProperty(key, "public_key", "string")) recorded the error, then the next statement called key.public_key.toLowerCase() unconditionally. Missing public_key threw Cannot read properties of undefined (reading 'toLowerCase'); a non-string one threw key.public_key.toLowerCase is not a function.
  • Non-object entries. isRequiredProperty bottoms out in hasProperty, which is property in target, and in throws on a primitive. authorized_keys: ["ssh-ed25519 AAAA..."] threw before any check could report anything.
  • configuration: null. The guard was typeof configuration !== "object" || Array.isArray(configuration), and typeof null === "object", so null passed as a valid object and Object.keys(null) threw about 240 lines later.

The authorized_keys and trusted_user_ca_keys blocks were copies of each other differing only in whether name is required, so both carried both key faults. They are now one validateSshPublicKeys helper: it reports a non-array up front, skips entries that are not objects, and makes the ED25519 prefix check an else if so it only runs on a public_key that already passed the string check. The configuration type check gains the missing null case, and the later Object.keys call is guarded so it only runs for a real object, which also removes the bogus Unexpected fields found in containers.configuration field: "0","1","2" warning a string value produced from its character offsets.

All of these now produce ordinary diagnostics such as containers.authorized_keys[0].public_key must be a string. Net effect on the source is 28 fewer lines.

Addressed from review

  • configuration: null combined with instance_type still crashed. The type check reported the problem and then fell through to the limits-versus-instance_type check, which dereferences configuration.disk, .vcpu and .memory_mib, throwing TypeError: Cannot read properties of null (reading 'disk'). That is the same class of crash this PR exists to remove, and my first pass missed it. The limits check is now an else branch of the type check, so it only runs once configuration is known to be a real object.
  • Article agreement in the unsupported-key-type message. It read "is a unsupported key type. Please provide a ED25519 public key" and now reads "an" in both places. This is the one existing message the PR changes; nothing in the repo asserted on it, which is why a test now does.
  • Changeset rewritten to describe user-facing impact rather than internals, per REVIEW.md.

Eight tests are added in normalize-and-validate-config.test.ts. Six failure cases each fail on main with the exact TypeError reported in the issue or found in review, one covers the corrected unsupported-key-type message, and one asserts a valid authorized_keys and trusted_user_ca_keys pair still validates clean, passing both before and after. These fields previously had no negative test coverage anywhere in the repo.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: this only changes what wrangler does with a config that was already invalid. The documented shape of containers.authorized_keys, containers.trusted_user_ca_keys and containers.configuration is unchanged, and no valid config behaves differently.

Copilot AI lite review requested due to automatic review settings August 8, 2026 08:12
@changeset-bot

changeset-bot Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7b2da6b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@cloudflare/workers-utils Patch
@cloudflare/autoconfig Patch
@cloudflare/cli-shared-helpers Patch
@cloudflare/deploy-helpers Patch
@cloudflare/remote-bindings Patch
@cloudflare/workers-auth Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@workers-devprod
workers-devprod requested review from a team and NuroDev and removed request for a team August 8, 2026 08:12
@workers-devprod

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/container-key-validation-crash.md: [@cloudflare/wrangler]
  • packages/workers-utils/src/config/validation.ts: [@cloudflare/wrangler]
  • packages/workers-utils/tests/config/validation/normalize-and-validate-config.test.ts: [@cloudflare/wrangler]

devin-ai-integration[bot]

This comment was marked as resolved.

Copilot AI 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.

Pull request overview

This PR fixes @cloudflare/workers-utils config validation for containers so malformed authorized_keys, trusted_user_ca_keys, and configuration values produce diagnostics instead of throwing raw TypeErrors from normalizeAndValidateConfig() (improving Wrangler’s error handling for invalid configs).

Changes:

  • Adds a shared validateSshPublicKeys() helper to validate containers.authorized_keys and containers.trusted_user_ca_keys with proper gating (no dereference after a failed type check).
  • Treats containers.configuration: null as invalid and avoids running additional-properties validation unless it’s a real object.
  • Adds unit tests covering several previously-crashing malformed containers configurations.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
packages/workers-utils/src/config/validation.ts Refactors SSH key validation into a helper and tightens containers.configuration validation/guarding.
packages/workers-utils/tests/config/validation/normalize-and-validate-config.test.ts Adds regression tests ensuring malformed containers configs produce diagnostics instead of throwing.
.changeset/container-key-validation-crash.md Adds a patch changeset documenting the crash-to-diagnostics behavior fix.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/workers-utils/src/config/validation.ts
Comment thread packages/workers-utils/src/config/validation.ts

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@dario-piotrowicz dario-piotrowicz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The PR generally looks good to me but there seem to be a few things that need fixing

Could you have a look @Neal006? 🙏

Comment thread packages/workers-utils/src/config/validation.ts
Comment thread packages/workers-utils/src/config/validation.ts
@pkg-pr-new

pkg-pr-new Bot commented Aug 11, 2026 •

Copy link
Copy Markdown
@cloudflare/autoconfig

npm i https://pkg.pr.new/@cloudflare/autoconfig@15088

@cloudflare/build-output-utils

npm i https://pkg.pr.new/@cloudflare/build-output-utils@15088

@cloudflare/config

npm i https://pkg.pr.new/@cloudflare/config@15088

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@15088

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/@cloudflare/deploy-helpers@15088

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@15088

miniflare

npm i https://pkg.pr.new/miniflare@15088

@cloudflare/pages-functions

npm i https://pkg.pr.new/@cloudflare/pages-functions@15088

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@15088

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@15088

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@15088

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@15088

@cloudflare/workers-auth

npm i https://pkg.pr.new/@cloudflare/workers-auth@15088

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@15088

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@15088

wrangler

npm i https://pkg.pr.new/wrangler@15088

commit: 7b2da6b

@Neal006

Neal006 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

@dario-piotrowicz thanks for taking the time to go through this. All three points are now covered, and two of them were already handled in a follow-up commit that landed before your pass, so the older threads are pointing at code that has since changed. Summary in one place:

1. Test placement (your comment on normalize-and-validate-config.test.ts). Done in e622478. Both null configuration cases, should error if containers.configuration is null and should error if containers.configuration is null and instance_type is set, now sit directly after the containers shape checks at the top of the [containers] describe, so every type error for the block reads in one place. Pure move, no test body or assertion changed.

2. Grammar in the unsupported key type message. Already fixed in 041f4e7, pushed on 8 Aug. The diagnostic now reads is an unsupported key type. Please provide an ED25519 public key. and is covered by should error if an authorized_keys public_key is not an ED25519 key, which previously had no test at all.

3. configuration: null combined with instance_type. Also fixed in 041f4e7. The limits versus instance_type check is now an else if on the configuration type check, so .disk, .vcpu and .memory_mib are only read once configuration is known to be a real non-null object. The regression test named above pairs configuration: null with instance_type: "lite" and asserts the diagnostic instead of the crash.

Where the PR stands. Three root causes in validateContainerApp, all in the same class of bug: a type error is recorded into diagnostics and then the rejected value is dereferenced anyway. The two duplicated key validation blocks are one shared helper, so authorized_keys and trusted_user_ca_keys cannot drift apart again. Net removal of source lines, with tests for each previously crashing config.

Verification on the current head: workers-utils suite passes at 475 tests, tsc -p clean, oxfmt clean. The remaining red checks are in areas this change does not touch, the Windows fixtures one being @fixture/additional-modules > watches additional modules, a file watcher flake. Happy to rebase for a clean run if that helps.

Could you have another look when you get a moment, and let me know if anything else needs changing? Glad to make any further adjustments you would like.

…med input

Validating a `containers` entry pushed a type error into diagnostics and
then dereferenced the value it had just rejected. An `authorized_keys` or
`trusted_user_ca_keys` entry whose `public_key` was missing or was not a
string reached `key.public_key.toLowerCase()` and threw, and an entry that
was not an object threw earlier still, from the `in` operator inside
`hasProperty`. A `configuration` of `null` passed the `typeof !== "object"`
check and threw later from `Object.keys()`.

None of these are a `UserError`, so wrangler printed a stack trace and
asked the user to report a bug instead of naming the offending key.

Each check now gates the checks that depend on it. The two duplicated key
blocks become one shared `validateSshPublicKeys` helper, which also
rejects a non-object entry up front, and the `configuration` type check
gains the missing `null` case so `Object.keys` only sees a real object.
No existing error message changed.
…uration

Review caught that the `configuration` type check reported a non-object
and then fell through to the limits-versus-instance_type check, which
dereferences `configuration.disk`, `.vcpu` and `.memory_mib`. A config
pairing `configuration: null` with `instance_type` therefore still threw
`TypeError: Cannot read properties of null (reading 'disk')`, which is
the exact class of crash this branch removes.

The limits check is now an `else` branch of the type check, so it only
runs once `configuration` is known to be a real object.

Also correct the article agreement in the unsupported key type message,
which read "a unsupported" and "a ED25519". No test or snapshot covered
that string, so a case for it is added alongside the regression test
pairing a null configuration with an instance type.
…r containers type checks

The two tests covering a null `containers.configuration`, one on its own
and one paired with an `instance_type`, sat further down among the SSH
key cases, which is where they happened to be written rather than where
they belong. Move both up next to the checks that assert on the shape of
the `containers` field, so every type error for the block reads in one
place.

No test bodies or assertions change.
@petebacondarwin
petebacondarwin force-pushed the fix/container-key-validation-crash branch from e622478 to adb618b Compare August 12, 2026 06:33
@petebacondarwin

Copy link
Copy Markdown
Contributor

We recently landed #14994, a large change to Miniflare's configuration internals that touched ~177 files across the repo. Leaving this PR on its old base was likely to cause conflicts, so we've rebased it onto the latest main and force-pushed the result.

Your local copy of this branch is now out of date. Before you push again, please reset to the new version:

git fetch origin
git checkout fix/container-key-validation-crash
git reset --hard origin/fix/container-key-validation-crash

Because the base moved a long way, it's also worth reinstalling before you carry on — the lockfile changed:

pnpm install

Sorry for the interruption. If the rebase looks wrong, or CI now fails in a way that seems related to the Miniflare config change rather than your own work, comment here and we'll help get it sorted.

@Neal006

Neal006 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Hi @petebacondarwin, @dario-piotrowicz, thanks for the rebase onto the new base.

I have reset my local branch to the force-pushed version and re-verified the change against it:

  • The diff against current main is still only three files: validation.ts, the validation test file, and the changeset. Nothing from new config miniflare attempt 3 #14994 came across in the rebase.
  • All 466 workers-utils config validation tests pass on the new base.
  • The defect is still present on main. Reverting validation.ts to main and re-running the suite fails 7 tests, and they pass again with the fix restored, so this is still needed rather than something new config miniflare attempt 3 #14994 already covers.
  • All three review points are in the current head adb618bc7: the "an unsupported" / "an ED25519" grammar, the else if so the instance_type limits check cannot read a configuration that was already rejected, and the two null configuration tests moved next to the other containers type checks.

Nothing outstanding on my side. CI shows 13 workflow suites at action_required waiting on an approval to run. Happy to make any further changes, just let me know.

@dario-piotrowicz dario-piotrowicz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM 🙂

@workers-devprod

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

@workers-devprod workers-devprod 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.

Codeowners reviews satisfied

@github-project-automation github-project-automation Bot moved this from Untriaged to Approved in workers-sdk Aug 13, 2026
@NuroDev
NuroDev enabled auto-merge (squash) August 13, 2026 12:19
@NuroDev
NuroDev merged commit fb6b51b into cloudflare:main Aug 13, 2026
63 of 64 checks passed
@github-project-automation github-project-automation Bot moved this from Approved to Done in workers-sdk Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[workers-utils] Malformed containers authorized_keys, trusted_user_ca_keys or configuration crashes config validation with a TypeError

6 participants