Skip to content

fix(auth): harden parsing of server-provided reCAPTCHA config - #16757

Open
paulb777 wants to merge 4 commits into
mainfrom
pb-harden-auth-recaptcha-config
Open

paulb777 wants to merge 4 commits into
mainfrom
pb-harden-auth-recaptcha-config

Conversation

@paulb777

@paulb777 paulb777 commented Oct 1, 2026

Copy link
Copy Markdown
Member

Context: #16728 — an Analytics server payload that was malformed crashed apps in production even though nothing changed on the client. This PR checks how FirebaseAuth parses config from the server, mostly the reCAPTCHA config (getRecaptchaConfig), and makes a few of those paths more tolerant.

Audit result

The Auth decoding paths I reviewed already use as? casts, guard their array indexing, and have no force-unwraps on server data. I found no crash in these paths. What I did find: in some cases, one malformed field or entry from the server silently threw away all of the config. The changes are small fixes for that.

Hardened paths

  • GetRecaptchaConfigResponse.recaptchaEnforcementState: this was decoded with one as? [[String: String]] cast. If any entry was not a dictionary, or any field in any entry was not a string (for example a new boolean field, or null), the cast failed and the whole array came back nil. reCAPTCHA enforcement was then treated as OFF for every provider. Each entry is now decoded separately: non-dictionary entries are dropped and only string values are kept. Unknown providers/states are still skipped later on, as before.
  • AuthRecaptchaVerifier site key extraction: the recaptchaKey was already required to split into 4 / segments. But keys like projects/123/keys/ or /// passed that check and stored an empty site key. These are now rejected with the existing "Invalid siteKey" (recaptchaNotEnabled) error, and no config is cached. Behavior for valid keys and for the reCAPTCHA-off case is unchanged.
  • AuthBackend error errors[].reason mapping: this used the same all-or-nothing as? [[String: String]] cast. A non-string sibling field (for example a numeric code) or a malformed entry stopped keyInvalid / ipRefererBlocked from mapping to invalidAPIKey / appNotAuthorized. Each entry is now handled separately and only reason has to be a string.

Reviewed with no change needed: GetProjectConfigResponse (authorizedDomains), GetAccountInfoResponse (checks users.count == 1 before indexing, which makes the UserProfileUpdate force-unwrap safe), the other *Response.swift decoders, splitStringAtFirstColon, and JWT parsing in AuthTokenResult.

Tests

  • FakeBackendRPCIssuer.fakeRecaptchaConfigJSON lets tests send any getRecaptchaConfig payload.
  • GetRecaptchaConfigTests: malformed entries mixed with valid ones, wrong-typed fields, NSNull/empty/missing fields.
  • AuthTests (iOS): verifier keeps valid enforcement states when other entries are malformed or unknown; wrong types fall back to OFF; malformed site keys ("", 456, projects/123/keys/, .../456/extra, ///) throw.
  • AuthBackendTests: keyInvalid / ipRefererBlocked still map correctly when sibling fields and entries are malformed.

These fail without the source changes (checked by reverting the sources and rerunning): testGetRecaptchaConfigResponseKeepsValidEntriesWhenSomeAreMalformed, testRecaptchaConfigIgnoresMalformedEnforcementStateEntries, testRecaptchaConfigMalformedSiteKeyThrows, testUnderlyingErrorReasonWithMalformedSiblingFields. The others are regression coverage.

Testing

xcodebuild -scheme AuthUnit test on the iOS Simulator (iPhone 16 Pro): 361 tests, 0 failures.

Decode reCAPTCHA enforcement state entries individually so one malformed entry or non-string field no longer discards the whole array (which silently treated enforcement as OFF). Reject recaptchaKey values with an empty site key segment. Decode backend underlying error entries individually so keyInvalid/ipRefererBlocked are still mapped when sibling fields are not strings. (#16728)
@gemini-code-assist

Copy link
Copy Markdown
Contributor
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

@paulb777

paulb777 commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request improves the robustness of the Firebase Auth backend when parsing malformed reCAPTCHA configurations and backend error details. Specifically, it updates the error and configuration parsing logic to handle unexpected types and malformed entries gracefully without discarding valid data or crashing. It also adds comprehensive unit tests to verify these edge cases. The feedback suggests using the more idiomatic Swift method hasPrefix(_:) instead of starts(with:) when checking the error reason prefix.

Comment thread FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift Outdated
Address review feedback: String.hasPrefix(_:) is the idiomatic way to check a string prefix, rather than the generic Sequence.starts(with:).
@paulb777

paulb777 commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request improves the robustness of the Firebase Auth SDK when parsing malformed reCAPTCHA configurations and backend error details from the server. Key changes include safer parsing of the errors array and recaptchaEnforcementState to prevent discarding valid entries, stricter validation of the recaptchaKey structure, and comprehensive unit tests covering these edge cases. Feedback on the changes suggests using optional chaining with compactMap for a more concise parsing implementation in GetRecaptchaConfigResponse.swift, and simplifying let _ = to _ = in the unit tests to align with Swift style guidelines.

Comment thread FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigResponse.swift Outdated
Comment thread FirebaseAuth/Tests/Unit/AuthBackendTests.swift Outdated
Addresses review feedback: use optional chaining instead of a nested if-let when parsing recaptchaEnforcementState (no behavior change), and use `_ =` instead of `let _ =` in the new backend test.
@paulb777

paulb777 commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request improves robustness when parsing malformed reCAPTCHA configurations and backend error details from the server. It updates the error and config parsing logic to safely handle unexpected types and malformed entries, and adds comprehensive unit tests. The review feedback suggests further tightening the validation of the recaptchaKey path structure in AuthRecaptchaVerifier to strictly match the expected projects/{project-id}/keys/{site-key} format.

Comment thread FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift
…cha-config

# Conflicts:
#	FirebaseAuth/CHANGELOG.md
@paulb777 paulb777 added this to the 13.1.0 - M188 milestone Oct 1, 2026

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants