Is Autofill Smartly - JobFill safe?

High risk

Autofill Smartly - JobFill sends full page text, form field metadata, and visited hostnames to jobfill.ai on user actions.

When a user clicks 'Save Job', the extension captures the full text content and URL of the current page and sends them to jobfill.ai/api/applications/extract. On each autofill event, it also transmits form field labels, names, types, and placeholder text to jobfill.ai/api/labels, and sends the visited hostname to both jobfill.ai/api/events and Google Analytics. Additionally, clicking 'Summarize' sends the full page text to jobfill.ai/api/summary.

nhatdxv1.7.39Chrome Web Store
75Risk

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

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Save Job sends page text and URL to JobFill

Clicking Save Job in JobFill clones the page, extracts title and text with Readability, adds the URL, and sends those to the service worker, which POSTs to jobfill.ai/api/applications/extract.

DA confirmed injection, not the POST body.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You click Save Job in the JobFill sidebar on a page.

The sidebar is rendered by the content script that runs on matching pages.

The extension did this

The extension reads the page's readable text, title, and current URL and sends them to JobFill.

The service worker posts those fields to the application-extraction endpoint.

02EvidenceFIELD TABLE
Fields prepared for the Save Job request
FieldValueWhy it matters
Readable page text
Senior Software Engineer, Platform Team. Build internal tools for application workflows and collaborate with product teams. (illustrative)This can include the main text from the page where you clicked Save Job, such as a job description or application instructions.
Page title
Senior Software Engineer - Acme Careers (illustrative)This identifies the browser page or document title attached to the saved job.
Current page URL
https://www.linkedin.com/jobs/view/3987654321/ (illustrative)This identifies the exact page you submitted through Save Job.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://jobfill.ai/api/applications/extract
No request body was captured during dynamic analysis because the JobFill sign-in flow could not be completed; the shipped service worker posts to this endpoint after receiving the Save Job message.
04EvidenceCODE COMPARE
The code that does this

The Save Job button collects readable page content

What it actually does
Readable content-script Save Job handlercontent.js
C = function() {
  var t = sa(ra().mark((function t() {
    var n, e, r, i, o, a, s;
    return ra().wrap((function(t) {
      for (;;) switch (t.prev = t.next) {
        case 0:
          return t.prev = 0, c(!0), l().Notify.info("Saving the job...", {
            timeout: 2e4
          }), n = document.cloneNode(!0), e = new vt.Readability(n), r = e.parse(), t.next = 8, w({
            message: "save-job",
            title: null == r ? void 0 : r.title,
            textContent: null == r ? void 0 : r.textContent,
            url: window.location.href
          }, !0, "", 1e4);
        case 8:
          if (!0 !== (null == (i = t.sent) ? void 0 : i.status) || "object" !== na(null == i ? void 0 : i.data)) {
            t.next = 13;
            break
          }
          return o = i.data, a = o.status, s = o.message, l().Notify["success" === a ? "success" : "failure"](s), t.abrupt("return");
        case 13:
          throw new Error("Invalid response format");
        case 16:
          t.prev = 16, t.t0 = t.catch(0), l().Notify.failure("Failed to save the job");
        case 20:
          return t.prev = 20, c(!1), t.finish(20);
        case 23:
        case "end":
          return t.stop()
      }
    }), t, null, [
      [0, 16, 20, 23]
    ])
  })));
  return function() {
    return t.apply(this, arguments)
  }
}();
Readable Save Job button clickcontent.js
pt.createElement("button", {
  type: "button",
  className: "w-full rounded-md bg-indigo-500 px-0 py-2 text-center text-xs font-semibold mb-2 text-white hover:bg-indigo-400 cursor-pointer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500",
  onClick: function() {
    C(), w({
      message: "ga-event",
      event_name: "sw-c-sj"
    }, !1)
  },
  disabled: u
}, u ? "Saving..." : "Save Job")
05EvidenceCODE COMPARE
The code that does this

The service worker posts those fields to JobFill

What it actually does
Readable authenticated JobFill clientservice-worker.js
var $n = null,
  Kn = null,
  Zn = ["jf_u", "jf_k", "jf_s"],
  ti = "https://jobfill.ai",
  ei = new URL(ti).hostname,
  ni = fn.create({
    baseURL: "https://jobfill.ai",
    withCredentials: !0,
    timeout: 18e4
  });
Readable save-job POST branchservice-worker.js
if ("save-job" === t.message) return ni.post("/api/applications/extract", {
  title: t.title,
  textContent: t.textContent,
  url: t.url
}).then((function(t) {
  n({
    status: !0,
    data: t.data
  })
})).catch((function(t) {
  n({
    status: !1
  })
})), !0;
06EvidenceTHIRD PARTY LIST
Destination named by the Save Job flow
  • jobfill.ai

    Receives the Save Job application-extraction request containing the page title, readable text content, and URL.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Autofill sends site hostnames to JobFill and Google Analytics

When you use JobFill's autofill, the extension reads the current website hostname and sends it to JobFill.

The hostname also feeds a Google Analytics page_view event, revealing which site you filled during a signed-in session.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You use Autofill on a website.

The extension did this

The extension sends the current site hostname to JobFill and records it as an analytics page view.

02EvidenceFIELD TABLE
Fields sent by this path
FieldValueWhy it matters
Website hostname
careers.example.orgShows which site you were using when Autofill ran.
Analytics event name
hnTies the website hostname to a page-view event for this extension.
Analytics client ID
7f0b47a4-83d0-44b3-8f75-1dd6aef8b6c1Lets the analytics service group repeated events from the same browser profile.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://jobfill.ai/api/events
No body or response was recorded in unauthenticated dynamic testing; the shipped handler posts this URL when Autofill reaches the ga-hn path.
04EvidenceNETWORK CAPTURE
Captured request
POSThttps://www.google-analytics.com/mp/collect?measurement_id=G-V79VSW9NZG&api_secret=<redacted>
No live Google Analytics response was recorded in unauthenticated dynamic testing; the shipped handler invokes this endpoint through firePageViewEvent.
05EvidenceCODE COMPARE
The code that does this

The content script sends the hostname and the service worker forwards it

What it actually does
Readable content-script hostname messagecontent.js
case 16:
  return Zd.value = !0, rp.value = ru(Zd, rp, _d), ip(), window.self === window.top && w({
    message: "ga-hn",
    hn: window.self.location.hostname
  }, !1), t.abrupt("return", !1);
Readable service-worker hostname handlerservice-worker.js
if ("ga-hn" === t.message) {
  try {
    u.firePageViewEvent("hn", t.hn), ni.post("/api/events", {
      hn: t.hn
    }).catch((function(t) {}))
  } catch (t) {}
  return !1
}
Readable analytics page-view wrapperservice-worker.js
key: "firePageViewEvent",
value: (o = c(a().mark((function t(e, n) {
  var i, o = arguments;
  return a().wrap((function(t) {
    for (;;) switch (t.prev = t.next) {
      case 0:
        return i = o.length > 2 && void 0 !== o[2] ? o[2] : {}, t.abrupt("return", this.fireEvent("page_view", r({
          page_title: e,
          page_location: n
        }, i)));
      case 2:
      case "end":
        return t.stop()
    }
  }), t, this)
}))), function(t, e) {
  return o.apply(this, arguments)
})
06EvidenceTHIRD PARTY LIST
Destinations reached by the hostname path
  • jobfill.ai

    Receives the hostname in a POST to /api/events when the ga-hn handler runs.

  • www.google-analytics.com

    Receives a Measurement Protocol page_view event with the hostname as page_location.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Summarize sends current page text to JobFill

Clicking Summarize in the JobFill sidebar converts the page to visible text and posts that text to JobFill for summarization.

Since the content script runs on all sites, submitted text can come from any page with the sidebar available.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You click Summarize in the JobFill sidebar.

The extension did this

The extension reads visible text from the current page and posts it to JobFill.

02EvidenceFIELD TABLE
Fields sent for summarization
FieldValueWhy it matters
Page text
Senior Product Manager role, responsibilities, requirements, and application questionsCan include the visible content you are reading, editing, or preparing to submit on the active site.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://jobfill.ai/api/summary
The static proof path shows the service worker posts raw_text to this endpoint; no recorded request body is included here.
04EvidenceCODE COMPARE
The code that does this

The sidebar extracts page text and the service worker posts it

What it actually does
Readable Summarize button handlercontent.js
pt.createElement("button", {
  type: "button",
  className: "w-full rounded-md bg-indigo-500 px-0 py-2 text-center text-xs font-semibold mb-2 text-white hover:bg-indigo-400 cursor-pointer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500",
  onClick: function() {
    n(), w({
      message: "ga-event",
      event_name: "sw-c-sm"
    }, !1)
  },
  disabled: e
}, e ? "Summarising..." : "Summarize")
Readable text extraction helpercontent.js
function Lo(t) {
  return function(t, n = {}, e) {
    return To(n)(t, e)
  }(t.documentElement.innerHTML, {
    wordwrap: !1,
    selectors: [{
      selector: '[style*="display: none"]',
      format: "skip"
    }, {
      selector: '[style*="visibility: hidden"]',
      format: "skip"
    }, {
      selector: "[hidden]",
      format: "skip"
    }, {
      selector: ".hidden",
      format: "skip"
    }, {
      selector: ".d-none",
      format: "skip"
    }, {
      selector: ".invisible",
      format: "skip"
    }, {
      selector: '[aria-hidden="true"]',
      format: "skip"
    }, {
      selector: ".visually-hidden",
      format: "skip"
    }]
  }).trim()
}
Readable summary message sendercontent.js
case 7:
  return t.next = 9, w({
    message: "generate-summary",
    raw_text: n
  }, !0, "", 12e4);
case 9:
  if ((r = t.sent).status) {
    t.next = 13;
    break
  }
  return t.abrupt("return");
Readable service-worker summary handlerservice-worker.js
if ("generate-summary" === t.message) return Dn(Bn().mark((function e() {
  var i;
  return Bn().wrap((function(e) {
    for (;;) switch (e.prev = e.next) {
      case 0:
        return e.prev = 0, e.next = 3, ni.post("/api/summary", {
          raw_text: t.raw_text
        });
      case 3:
        i = e.sent, n({
          status: !0,
          data: i.data
        }), e.next = 11;
        break;
      case 7:
        e.prev = 7, e.t0 = e.catch(0), n({
          status: !1,
          message: "Failed to generate summary"
        });
      case 11:
      case "end":
        return e.stop()
    }
  }), e, null, [
    [0, 7]
  ])
})))(), !0;
05EvidenceTHIRD PARTY LIST
Destination reached by the summarize path
  • jobfill.ai

    Receives raw page text in POST requests to /api/summary.

Data recipients

jobfill.aiwww.google-analytics.com
Updated 17 September 2026kbgfilncepjeoodogmebahnloidgaibg