Is Simplify Copilot - Autofill job applications, job tracker & AI resumes safe?

Medium risk

Simplify Copilot is medium risk. Dynamic analysis captured 38 POSTs to api.axiom.co in one Simplify Copilot session. Each tracked_input event records the field touched: label, ATS, employer, input type, posting ID, not typed value. On by default via flag `analyticsEvents`.…

Simplify Jobs Inc.v3.1.6Chrome Web Store
49Risk
Who publishes it

Simplify Jobs - no other listings under this identity, 15 shared hostnames

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

Publisher
Simplify Jobs Inc.
Declared legal entity
Simplify Jobs
Registered address
2261 Market St #4189, San Francisco, CA 94114-1612, US
Registered contact
Rushil Srivastava

Shared hosts - 15 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.

api.exp.welcometothejungle.com
Also called by 1 other listing: Simplify Copilot – Autofill job applications
app.welcometothejungle.com
Also called by 1 other listing
feedback.simplify.jobs
Also called by 1 other listing: Simplify Copilot – Autofill job applications
job-boards.cdn.greenhouse.io
Also called by 1 other listing: Simplify Copilot – Autofill job applications
sabre.simplify.jobs
Also called by 1 other listing
simplifyjobs.notion.site
Also called by 1 other listing: Simplify Copilot – Autofill job applications
theoffice.fandom.com
Also called by 1 other listing
api.simplify.jobs
Also called by 2 other listings
api.village.ai
Also called by 2 other listings, including Village
k.village.ai
Also called by 2 other listings
village.ai
Also called by 2 other listings, including Village
village.sfo3.cdn.digitaloceanspaces.com
Also called by 2 other listings, including Village
villagehq.notion.site
Also called by 2 other listings, including Village
dol.gov
Also called by 4 other listings, including H1B Sponsor Checker by H1BGrader
simplify.jobs
Also called by 5 other listings

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

Publishers can request a review.

Findings

Autofill field metadata sent to Axiom analytics on every job form interaction

Dynamic analysis captured 38 POSTs to api.axiom.co in one Simplify Copilot session.

Each tracked_input event records the field touched: label, ATS, employer, input type, posting ID, not typed value.

On by default via flag `analyticsEvents`.

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

You interact with a field in a job application form.

Any click or keystroke in a tracked input triggers the event.

The extension did this

The extension sends the field label, ATS system, company name, and input metadata to api.axiom.co.

The field value is removed before transmission; the remaining metadata is posted as a tracked_input event to Axiom's ingest API.

Captured request
POSThttps://api.axiom.co/v1/datasets/sabre/ingest

HTTP 200. Our dynamic analysis captured 38 requests of this shape in a single session.

Headers
Content-Type
application/json
Authorization
Bearer xaat-e0a585d9-2911-489d-8c83-babd0dc44f28
X-Axiom-Org-Id
simplify-qiqd
Body
[  {    "labelText": "Why are you a good fit for Simplify",    "ATSKey": "Greenhouse",    "trackedObj": "simplify:tutorial",    "inputTagName": "TEXTAREA",    "status": "tracking",    "name": "tracked_input"  }]
Fields transmitted in each tracked_input event
  • Field label
    Why are you a good fit for Simplify

    The text label of the job application form field you interacted with, such as 'Why are you a good fit for this role?'.

  • ATS system
    Greenhouse

    The name of the applicant tracking system used by the employer, identifying which job platform you are applying through.

  • Job posting identifier
    simplify:tutorial

    An internal reference to the specific job posting you are applying for.

  • Input element type
    TEXTAREA

    The HTML element type of the form field (e.g. TEXTAREA, INPUT).

The code that does this

Service worker strips inputValue then forwards the remaining fields to Axiom

Readable version
// background.bundle.js:50514-50521 const handleTrackInput = async ({ trackedInput: input }) => { const payload = Object.assign({}, input); delete payload.inputValue; // field value removed before sending sendToAxiom({ name: 'tracked_input', event: payload }); return true; };
Destination for form interaction metadata
    • api.axiom.co

    Axiom analytics. Receives tracked_input events for the 'sabre' dataset under org simplify-qiqd (Simplify Jobs Inc.), posted with a hardcoded bearer token in the bundle.

Cover letter HTML is uploaded when saved or used

Saving a cover letter template or using the editor in Simplify Copilot packages the name and HTML content, sent to Simplify's account API.

In testing, the endpoint returned HTTP 401 and Use cover letter stayed disabled with no account.

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

You use Simplify Copilot's cover letter editor.

The same path is used when you create a template, update a saved cover letter, or choose Use Cover Letter.

The extension did this

The extension sends the cover letter name and HTML content to Simplify's API.

For a newly used cover letter, the request object can also include job tracking context and whether the letter was generated.

Fields the code places in cover-letter API objects
  • Cover letter name
    Cover Letter for Product Manager at Acme Labs (illustrative)

    This names the letter or template you save, which can identify the job or company you are applying to.

  • Cover letter HTML
    <p>Dear Hiring Manager,</p><p>I am writing to express my interest in the {{JOB_TITLE}} position at {{COMPANY_NAME}}.</p><p>{{COPILOT_GENERATE_BODY}}</p><p>Sincerely,<br/>{{USER_FULL_NAME}}</p>

    This is the formatted text of the cover letter you typed, generated, or saved as a template.

  • Job tracking context
    trackedObj for an Acme Labs application (illustrative)

    This can connect a saved cover letter to the job record active in the extension.

  • Generated marker
    true

    This marks whether the cover letter came from the generator rather than being typed entirely by you.

Captured request
GEThttps://api.simplify.jobs/v2/candidate/me/template/cover-letter

HTTP 401 Unauthorized; no request body because this was a GET request.

The code that does this

The editor puts cover letter HTML into extension messages

Readable version

Create template sends html_content

deobfuscated/js/contentScriptMain.bundle.js:68653-68691
ee = (0, Ho.useCallback)(async () => {  if (Z && !window.confirm("You have unsaved changes to this template. Discard them?")) return;  const e = window.prompt("Name for the new template:", "My Template");  if (e && e.trim()) {    z(!0);    try {      vo({        name: "misc",        event: {          action: "create_cover_letter_template",          source: "CoverLetterEditor"        }      });      const t = (null == m ? void 0 : m.html) && m.html.trim() ? m.html : "<p>Dear Hiring Manager,</p><p>I am writing to express my interest in the {{JOB_TITLE}} position at {{COMPANY_NAME}}.</p><p>{{COPILOT_GENERATE_BODY}}</p><p>Sincerely,<br/>{{USER_FULL_NAME}}</p>",        n = {          name: e.trim(),          html_content: t        },        r = await o.runtime.sendMessage({          method: "createCoverLetterTemplate",          template: n        });      if (!r.ok) return void window.alert(r.error);      A(r.template.id), L(r.template), D(r.template.name), B(!1), K([]);      const i = r.template.html_content || "";      null == J || J.commands.setContent(i, {        emitUpdate: !1      }), g(e => {        var t;        return hZ(pZ({}, null != e ? e : {}), {          html: i,          text: null !== (t = null == J ? void 0 : J.getText()) && void 0 !== t ? t : ""        })      }), await Y()    } finally {      z(!1)    }  }}, [J, null == m ? void 0 : m.html, Y, Z])

Use cover letter sends html_content

deobfuscated/js/contentScriptMain.bundle.js:69016-69067
"aria-label": "Use cover letter",disabled: !d || !(null == m ? void 0 : m.html),onClick: () => {  vo({    name: "misc",    event: {      action: "fill_cover_letter",      source: "CoverLetterEditor"    }  });  const e = null == m ? void 0 : m.html;  if (e)    if (U) {      const t = (null == l ? void 0 : l.title) ? `Cover Letter for ${l.title}${l.companyName?` at ${l.companyName}`:""}` : "Cover Letter";      o.runtime.sendMessage({        method: "updateCandidateCoverLetter",        coverLetterId: U,        update: {          name: (null != H ? H : t).slice(0, 200),          html_content: e        }      })    } else {      const t = (null == l ? void 0 : l.title) ? `Cover Letter for ${l.title}${l.companyName?` at ${l.companyName}`:""}` : "Cover Letter";      o.runtime.sendMessage({        method: "createCandidateCoverLetter",        coverLetter: {          name: t.slice(0, 200),          html_content: e,          tracked_obj: (null == l ? void 0 : l.trackedObj) || void 0,          generated: $        }      }).then(e => {        (null == e ? void 0 : e.ok) && p(t => t ? hZ(pZ({}, t), {          savedId: e.coverLetter.id,          savedName: e.coverLetter.name        }) : t)      })    } p(m ? hZ(pZ({}, m), {    savedId: null != U ? U : m.savedId,    savedName: null != H ? H : m.savedName  }) : m), C ? null == d || d({    keyPaths: ["coverLetter"],    showProgress: !0  }) : null == u || u("coverLetter", {    inputFillStatus: "",    inputFillMessage: "",    inputFillTime: void 0,    actionIndex: void 0  }), s("modal/cover-letter-editor")},children: C ? "Fill cover letter" : "Use Cover Letter"
The code that does this

The background worker forwards the messages to account API routes

Readable version

Base API host

deobfuscated/js/background.bundle.js:47345-47352
const Y = {  BASE: "https://api.simplify.jobs",  WITH_CREDENTIALS: !1,  TOKEN: void 0,  USERNAME: void 0,  PASSWORD: void 0,  HEADERS: void 0};

Cover letter API methods

deobfuscated/js/background.bundle.js:50936-50974
static async createCandidateCoverLetter(e) {  return await So({    method: "POST",    path: "/v2/candidate/me/cover-letter",    body: e  })}static async updateCandidateCoverLetter(e, t) {  return await So({    method: "PUT",    path: `/v2/candidate/me/cover-letter/${e}`,    body: t  })}static async copilotWriteAndSaveCoverLetter(e) {  return await So({    method: "POST",    path: "/v2/candidate/me/copilot/cover-letter-doc",    body: e  })}static async getCoverLetterTemplates() {  return await So({    method: "GET",    path: "/v2/candidate/me/template/cover-letter"  })}static async getCoverLetterTemplate(e) {  return await So({    method: "GET",    path: `/v2/candidate/me/template/cover-letter/${e}`  })}static async createCoverLetterTemplate(e) {  return await So({    method: "POST",    path: "/v2/candidate/me/template/cover-letter",    body: e  })}

Message handlers call API methods

deobfuscated/js/background.bundle.js:100233-100306
case "createCoverLetterTemplate":  return (async ({    template: e  }) => {    try {      return {        ok: !0,        template: (await Qo.createCoverLetterTemplate(e)).body      }    } catch (e) {      var t;      const n = null == e || null === (t = e.body) || void 0 === t ? void 0 : t.detail;      return {        ok: !1,        error: "string" == typeof n ? n : "Failed to create template"      }    }  })(e);case "updateCandidateCoverLetter":  return (async ({    coverLetterId: e,    update: t  }) => {    try {      return {        ok: !0,        coverLetter: (await Qo.updateCandidateCoverLetter(e, t)).body      }    } catch (e) {      var n;      const t = null == e || null === (n = e.body) || void 0 === n ? void 0 : n.detail;      return {        ok: !1,        error: "string" == typeof t ? t : "Failed to update cover letter"      }    }  })(e);case "createCandidateCoverLetter":  return (async ({    coverLetter: e  }) => {    try {      return {        ok: !0,        coverLetter: (await Qo.createCandidateCoverLetter(e)).body      }    } catch (e) {      var t;      const n = null == e || null === (t = e.body) || void 0 === t ? void 0 : t.detail;      return {        ok: !1,        error: "string" == typeof n ? n : "Failed to create cover letter"      }    }  })(e);
External destination for the cover-letter data
    • api.simplify.jobs

    Simplify Jobs account API that receives candidate cover letter and cover letter template requests.

Updated 30 September 2026pbanhockgagggenencehbnadejlgchfc