Skip to content

fix(security): base64-encode survey WebView payload to prevent script injection (ENG-1813)#55

Merged
mattinannt merged 1 commit into
mainfrom
fix/ENG-1813-js-payload-backtick-fix
Jul 21, 2026
Merged

fix(security): base64-encode survey WebView payload to prevent script injection (ENG-1813)#55
mattinannt merged 1 commit into
mainfrom
fix/ENG-1813-js-payload-backtick-fix

Conversation

@pandeymangg

@pandeymangg pandeymangg commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What & why

ENG-1813 — script injection via the survey WebView payload.

The survey payload was spliced into a JavaScript template literal in the WebView HTML:

const json = `{{WEBVIEW_DATA}}`;   // {{WEBVIEW_DATA}} = raw survey JSON

Survey content is server/admin-authored (headlines, subheaders, choice labels, styling, an HTML question type…). A value containing a backtick — or ${…}, which a template literal evaluates eagerly — breaks out of the string and runs as arbitrary JS in the WebView, which also holds the FormbricksJavascript bridge. This is the Android counterpart of the iOS issue (formbricks/ios#51).

The existing #%23 and \"' replacements were partial workarounds for the same class of problem: they did not stop backtick/${} breakout, and they corrupted legitimate survey content (every " became ', and hex colors like #FF0000 were percent-mangled).

Fix

Mirror the iOS remediation — never let survey content be parsed as JS source:

  • Base64-encode the payload in Kotlin (Base64.NO_WRAP) and decode it in the WebView via atob + TextDecoder, then JSON.parse. Base64 output is [A-Za-z0-9+/=] only, so backticks, ${…}, quotes and </script> can no longer appear in the string and break out.
  • Removed the #%23 and \"' workarounds — unnecessary once base64'd, and they were corrupting valid survey text (bonus data-integrity fix).
  • Switched the single loadData call to loadDataWithBaseURL(null, …) so the base64 (which may contain +, /, =) isn't mangled by loadData's data:-URL percent-decoding. This is the analogue of iOS's loadHTMLString(_, baseURL: nil).

Verification

  • ./gradlew :android:compileReleaseKotlin — passes.
  • Existing FormbricksViewModelInstrumentedTest (getJson) is unaffected — its assertions don't depend on the removed workarounds.
  • Published via publishToMavenLocal and smoke-tested in a host app — surveys render correctly.

Notes / scope

@pandeymangg pandeymangg changed the title fix: fixes the js payload backtick bug fix(security): base64-encode survey WebView payload to prevent script injection (ENG-1813) Jul 21, 2026
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 69b03a2f-3b03-4c15-a63d-fbfb4e8dac5d

📥 Commits

Reviewing files that changed from the base of the PR and between 367db37 and c2266bc.

📒 Files selected for processing (1)
  • android/src/main/java/com/formbricks/android/webview/FormbricksViewModel.kt

Walkthrough

FormbricksViewModel now Base64-encodes UTF-8 survey JSON before embedding it in the WebView HTML. The HTML template decodes the payload with atob and TextDecoder before rendering. JSON escaping workarounds were removed, and the WebView binding adapter now uses loadDataWithBaseURL.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No pull request description was provided, so there's not enough text to judge its relevance. Add a brief description of the WebView payload fix and the issue it addresses.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: fixing the JS payload bug in the WebView flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@pandeymangg
pandeymangg requested review from Dhruwang and mattinannt and removed request for Dhruwang July 21, 2026 07:37
@mattinannt
mattinannt added this pull request to the merge queue Jul 21, 2026
Merged via the queue into main with commit 19e34b9 Jul 21, 2026
7 checks passed
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.

2 participants