Is Voila – AI Assistant, Copilot and AI Writer safe?

High risk

Voila is high risk. Code analysis: in Outlook web mail, Voila reads the open message's body, subject, sender, recipients, cc, and bcc, turns them into reply context, and posts it to https://chat.getvoila.ai/api/v1/prompts/chat.…

Initial conditionv1.8.2Chrome Web Store
78Risk
Who publishes it

Initial condition s.r.o. - 2 other listings from the same operator, none carrying a finding

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
Initial condition
Declared legal entity
Initial condition s.r.o.
Registered address
Urxova 10, Prague 18600, CZ
Registered contact
Initial condition - ICO 10953035

Same store account

2 other listings published from this account, 310k+ users between them, none of them carrying a finding.

Shared hosts - 12 hostnames

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

assets.getvoila.ai
Also called by 1 other listing: voilà-ai-powered-assistant
chat.getvoila.ai
Also called by 1 other listing: voilà-ai-powered-assistant
d2u6w5ruxmbk4z.cloudfront.net
Also called by 1 other listing: voilà-ai-powered-assistant
getvoila.ai
Also called by 1 other listing: voilà-ai-powered-assistant
figjam.new
Also called by 2 other listings
miro.new
Also called by 2 other listings, including ViinyxAI
pen.new
Also called by 2 other listings
design.new
Also called by 3 other listings
gist.new
Also called by 3 other listings, including Create New
task.new
Also called by 3 other listings
story.new
Also called by 5 other listings
linear.new
Also called by 6 other listings, including ViinyxAI

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

Outlook email content sent to Voila chat API

Code analysis: in Outlook web mail, Voila reads the open message's body, subject, sender, recipients, cc, and bcc, turns them into reply context, and posts it to https://chat.getvoila.ai/api/v1/prompts/chat.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You use Voila while viewing or replying to an Outlook web mail message.

The Outlook integration inserts a Respond with Voila button next to the compose send button.

The extension did this

The extension reads Outlook message fields and sends them as chat context to Voila.

The context string includes who the message is from, who you are replying to, and the message text.

Outlook fields placed into the chat context
  • Message body
    Maya Patel wrote: Please send the revised partner terms before the finance review on Thursday.

    This can expose the text of the Outlook conversation you are asking Voila to answer.

  • Subject
    Partner renewal terms

    This reveals what the email conversation is about even without the full body.

  • Sender
    Maya Patel <maya.patel@example.com>

    This identifies the person or mailbox that sent the message.

  • Recipients
    Jordan Lee <jordan.lee@example.com>

    This identifies who is included in the conversation.

  • Cc and bcc
    Cc: legal@example.com; Bcc: finance@example.com

    This can expose additional participants, including recipients not visible in the main To line.

Captured request
POSThttps://chat.getvoila.ai/api/v1/prompts/chat

Earlier dynamic analysis did not exercise the Outlook-specific path, so no request body or response body was recorded for this mail flow.

Headers
Content-Type
application/json
The code that does this

Outlook reads message fields and sends them into the Voila sidebar flow

Readable version

Outlook DOM extraction and reply context

js/outlook-extension.js
function o() {  var t, e, n, r, o, i, c, a, u, f, s, d, l, v;  return {    message: (null === (t = document.querySelector('[aria-label="Message body"]')) || void 0 === t || null === (e = t.textContent) || void 0 === e ? void 0 : e.trim()) || (null === (n = document.getElementById("docking_InitVisiblePart_0")) || void 0 === n || null === (r = n.querySelector("#docking_DockingTriggerPart_0")) || void 0 === r || null === (o = r.textContent) || void 0 === o ? void 0 : o.trim()),    subject: null === (i = document.querySelector('[data-app-section="MailReadCompose"] [role="heading"]')) || void 0 === i ? void 0 : i.textContent,    from: null === (c = document.querySelector('[id^="fromContainer"]')) || void 0 === c || null === (a = c.parentElement) || void 0 === a || null === (u = a.querySelector("span")) || void 0 === u ? void 0 : u.textContent,    to: (null === (f = document.querySelector(".EditorClass")) || void 0 === f ? void 0 : f.textContent) || (null === (s = document.getElementById("docking_InitVisiblePart_0")) || void 0 === s || null === (d = s.querySelector("ul li span")) || void 0 === d ? void 0 : d.textContent),    cc: null === (l = document.querySelector('[aria-label="Cc"]')) || void 0 === l ? void 0 : l.textContent,    bcc: null === (v = document.querySelector('[aria-label="Bcc"]')) || void 0 === v ? void 0 : v.textContent  }}function i() {  var t = o(),    e = void 0 === t.message;  if (e) window.postMessage({    type: "voila-message",    context: "",    email: {      draft: !0    }  });  else {    var n = "I'm ".concat(t.from, ". I'm replying to " ).concat(t.to, ". " ).concat(t.to, " wrote: " ).concat(t.message);    window.postMessage({      type: "voila-message",      context: n,      email: {        to: t.to,        subject: t.subject,        draft: !1      }    })  }}

Sidebar POST to Voila chat API

js/standalone.js
ne = {  chat: n.chat,  email: null === Z || void 0 === Z ? void 0 : Z.email,  model: null === (c = n.selectedAiModel) || void 0 === c ? void 0 : c.id,  auth_token: null === Z || void 0 === Z ? void 0 : Z.auth_token,  client_date: (new Date).toString(),  language: null === (u = n.selectedLanguage) || void 0 === u ? void 0 : u.code,  intent: null === (h = n.intent) || void 0 === h ? void 0 : h.intent,  temperature: null === (p = n.metadata) || void 0 === p || null === (f = p.action) || void 0 === f ? void 0 : f.temperature,  tone: null === (g = n.tone) || void 0 === g ? void 0 : g.value,  context: (n.context || "").trim(),  attachments: Y,  persona: N,  conversation: n.conversation,  user_uuid: ee,  version: null === te || void 0 === te ? void 0 : te.version}, n.metadata = {}, oe = "", Object(l["a"])(x["b"] + "/api/v1/prompts/chat", {  method: "POST",  body: JSON.stringify(ne),  signal: n.abortController.signal,  openWhenHidden: !0,  priority: "high",  headers: {    "Content-Type": "application/json"  }})
Destination receiving the Outlook context
    • chat.getvoila.ai

    Receives the Voila chat request containing Outlook message context.

Gmail email content sent to Voila chat API

When Voila runs inside Gmail, it reads the email's body, subject, sender, and recipient.

The sidebar builds a chat request with that data, the account email, an auth token, and a user UUID, posted to chat.getvoila.ai/api/v1/prompts/chat.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You use Voila while viewing or replying to a Gmail message.

The Gmail integration adds a reply control and wires the current message into that action.

The extension did this

The extension reads the email and sends it as chat context to Voila.

The request also includes Voila account identifiers from extension storage.

Fields placed into the Gmail chat request
  • Email body
    Previous email chain: From: Alice Morgan <alice@example.com> Date: Mon, 13 Jul 2026 09:12:00 -0700 To: Jordan Lee <jordan@example.com> Subject: Renewal terms Please review the renewal language before Friday.

    This can expose the text of the Gmail conversation you are asking Voila to answer.

  • Email metadata
    To: Alice Morgan; Subject: Renewal terms; draft: false

    This identifies who is involved in the conversation and what the message is about.

  • Voila account email
    jordan@example.com

    This links the Gmail context to the Voila account using the extension.

  • Auth token
    auth_token=<redacted>

    This is account authorization data sent in the same JSON request as the email context.

  • User UUID
    4d1d8e62-26d4-4b73-9cf1-55f5b2a76c37

    This gives the service a stable identifier for the browser profile using the extension.

Captured request
POSThttps://chat.getvoila.ai/api/v1/prompts/chat

Earlier dynamic analysis did not exercise the Gmail-specific path, so no request body or response body was recorded for this mail flow.

Headers
Content-Type
application/json
The code that does this

Gmail reads the open message and posts it into the Voila sidebar flow

Readable version

Gmail message extraction and sidebar handoff

js/gmail-extension.js
function S(t, e) {  var n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : null,    r = {      type: "voila-message",      context: t,      email: e    };  n && (r.prompt = n), window.postMessage(r)}function P(t, e, n) {  r = t;  var o = "",    i = {};  if ("compose" === e) i = {    draft: !0  };  else {    var c, a, u, f = n.new.get.email_id(),      s = n.new.get.email_data(f);    i = {      to: (null === s || void 0 === s || null === (c = s.from) || void 0 === c ? void 0 : c.name) || (null === s || void 0 === s || null === (a = s.from) || void 0 === a ? void 0 : a.address),      subject: null === s || void 0 === s ? void 0 : s.subject,      draft: 0 === ((null === (u = t.recipients()) || void 0 === u ? void 0 : u.to) || []).length    }, o = I(t, s)  }  S(o, i)}function w(t) {  try {    if (!o) return;    var e = document.querySelectorAll(".gA.gt"),      n = e[e.length - 1];    if (!n) return;    var i = n.querySelector(".ams.bkI, .ams.bkH");    i || (i = document.querySelectorAll('[aria-label="Reply"]')[0]), i || (i = n.querySelectorAll("button[aria-label]")[0]), i || (i = n.querySelectorAll(".amn button")[0]), i && i.click(), S(o.context, o.email, t), setTimeout((function() {      r = window.gmail.dom.composes()[0], m()    }), 100)  } catch (c) {}}

Sidebar POST to Voila chat API

js/standalone.js
Q = o.sent, Z = Q.user, ee = Q.uuid, te = e.runtime.getManifest(), ne = {  chat: n.chat,  email: null === Z || void 0 === Z ? void 0 : Z.email,  model: null === (c = n.selectedAiModel) || void 0 === c ? void 0 : c.id,  auth_token: null === Z || void 0 === Z ? void 0 : Z.auth_token,  client_date: (new Date).toString(),  language: null === (u = n.selectedLanguage) || void 0 === u ? void 0 : u.code,  intent: null === (h = n.intent) || void 0 === h ? void 0 : h.intent,  temperature: null === (p = n.metadata) || void 0 === p || null === (f = p.action) || void 0 === f ? void 0 : f.temperature,  tone: null === (g = n.tone) || void 0 === g ? void 0 : g.value,  context: (n.context || "").trim(),  attachments: Y,  persona: N,  conversation: n.conversation,  user_uuid: ee,  version: null === te || void 0 === te ? void 0 : te.version}, n.metadata = {}, oe = "", Object(l["a"])(x["b"] + "/api/v1/prompts/chat", {  method: "POST",  body: JSON.stringify(ne),  signal: n.abortController.signal,  openWhenHidden: !0,  priority: "high",  headers: {    "Content-Type": "application/json"  }})
Destination receiving the Gmail context
    • chat.getvoila.ai

    Receives the Voila chat request containing the Gmail context and account identifiers.

Page text sent to Voila when context is enabled

With "Use current page as context" on, the extension extracts the page's text and adds it to the chat request sent to chat.getvoila.ai.

Code review confirmed this; traffic replay didn't trigger the feature, so no body was captured.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You enable Use current page as context for a prompt.

The button appears in the Voila prompt footer when page context is available.

The extension did this

The extension reads the active page and adds the extracted text to the chat request.

The implementation calls the page-text extractor and later serializes the context field into the POST body.

Fields prepared for the chat request
  • Readable page text
    Example Article Title This article explains the quarterly rollout plan and internal milestones.

    The main text from the page you are viewing can be included with your prompt.

  • Page context
    https://intranet.example.com/quarterly-rollout-plan

    The context ties your prompt to the page where you used the feature.

  • Voila account
    employee@example.com

    The chat request can include account data that links the prompt to your Voila session.

Captured request
POSThttps://chat.getvoila.ai/api/v1/prompts/chat
Headers
Content-Type
application/json
The code that does this

The page-context toggle reads the document, and the chat POST includes context

Readable version

Page-context toggle calls the extractor

deobfuscated/js/standalone.js
togglePageAsContext: function() {  var e = this;  return Object(s["a"])(regeneratorRuntime.mark((function t() {    return regeneratorRuntime.wrap((function(t) {      while (1) switch (t.prev = t.next) {        case 0:          if (e.currentPageAsContext = !e.currentPageAsContext, !e.currentPageAsContext) {            t.next = 9;            break          }          return t.t0 = e, t.next = 5, Object(T["a"])(document, e.prompt);        case 5:          t.t1 = t.sent, t.t0.$emit.call(t.t0, "onContextChange", t.t1), t.next = 10;          break;        case 9:          e.$emit("onContextChange", "");        case 10:          e.focusElement("prompt");        case 11:        case "end":          return t.stop()      }    }), t)  })))()}

Chat request body includes the context property

deobfuscated/js/standalone.js
ne = {  chat: n.chat,  email: null === Z || void 0 === Z ? void 0 : Z.email,  model: null === (c = n.selectedAiModel) || void 0 === c ? void 0 : c.id,  auth_token: null === Z || void 0 === Z ? void 0 : Z.auth_token,  client_date: (new Date).toString(),  language: null === (u = n.selectedLanguage) || void 0 === u ? void 0 : u.code,  intent: null === (h = n.intent) || void 0 === h ? void 0 : h.intent,  temperature: null === (p = n.metadata) || void 0 === p || null === (f = p.action) || void 0 === f ? void 0 : f.temperature,  tone: null === (g = n.tone) || void 0 === g ? void 0 : g.value,  context: (n.context || "").trim(),  attachments: Y,  persona: N,  conversation: n.conversation,  user_uuid: ee,  version: null === te || void 0 === te ? void 0 : te.version}, n.metadata = {}, oe = "", Object(l["a"])(x["b"] + "/api/v1/prompts/chat", {  method: "POST",  body: JSON.stringify(ne),  signal: n.abortController.signal,  openWhenHidden: !0,  priority: "high",  headers: {    "Content-Type": "application/json"  }})

Extractor removes scripts/styles and chooses readable text

deobfuscated/js/chunk-common.js
function a(t, e) {  if (null !== e && void 0 !== e && e.cssSelector && "" !== (null === e || void 0 === e ? void 0 : e.cssSelector)) return null === t || void 0 === t ? void 0 : t.querySelectorAll(null === e || void 0 === e ? void 0 : e.cssSelector);  window.location.hostname;  var n = window.location.href;  return n.startsWith("https://app.frontapp.com/inboxes") ? null === t || void 0 === t ? void 0 : t.querySelector('[data-testid="conversation-timeline"]') : void 0}function u(t) {  return t instanceof NodeList ? Array.from(t).map(u).join("------") : (null === t || void 0 === t ? void 0 : t.innerText) || (null === t || void 0 === t ? void 0 : t.textContent)}function c(t) {  try {    if (Object(o["isProbablyReaderable"])(t, {        minScore: 70      })) {      var e = new o["Readability"](t).parse();      return e.textContent    }  } catch (n) {}}function s(t, e, n) {  return l.apply(this, arguments)}function l() {  return l = Object(r["a"])(regeneratorRuntime.mark((function t(e, n, r) {    var o, s, l, p, d;    return regeneratorRuntime.wrap((function(t) {      while (1) switch (t.prev = t.next) {        case 0:          return o = e.cloneNode(!0), o.querySelectorAll("style, script").forEach((function(t) {            return t.remove()          })), s = u(a(o, r)), l = c(o), p = u(null === o || void 0 === o ? void 0 : o.querySelector("main")), d = u(null === o || void 0 === o ? void 0 : o.querySelector("body")), t.abrupt("return", Object(i["a"])(s || l || p || d));        case 7:        case "end":          return t.stop()      }    }), t)  }))), l.apply(this, arguments)}
Remote hosts used by this flow
    • chat.getvoila.ai

    Receives the chat request containing the context field.

    • www.getvoila.ai

    Configured as the main Voila API host in the bundled API constants.

+1 more finding not shown

Updated 30 September 2026cakobppopkpmmglabcdcklncbckjpkcl